Skip to content

Commit d83ae32

Browse files
authored
Merge pull request #7153 from jimingham/nsindexset
Fix the NSIndexSet data formatter for changes in macOS Sonoma.
2 parents 4ea1eb0 + 350ee3f commit d83ae32

File tree

1 file changed

+47
-10
lines changed

1 file changed

+47
-10
lines changed

lldb/source/Plugins/Language/ObjC/Cocoa.cpp

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider(
252252
if (!process_sp)
253253
return false;
254254

255-
ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
255+
AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
256+
ObjCLanguageRuntime::Get(*process_sp));
256257

257258
if (!runtime)
258259
return false;
@@ -279,20 +280,56 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider(
279280

280281
do {
281282
if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") {
283+
// Foundation version 2000 added a bitmask if the index set fit in 64 bits
284+
// and a Tagged Pointer version if the bitmask is small enough to fit in
285+
// the tagged pointer payload.
286+
// It also changed the layout (but not the size) of the set descriptor.
287+
288+
// First check whether this is a tagged pointer. The bitmask will be in
289+
// the payload of the tagged pointer.
290+
uint64_t payload;
291+
if (runtime->GetFoundationVersion() >= 2000
292+
&& descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) {
293+
count = llvm::popcount(payload);
294+
break;
295+
}
296+
// The first 32 bits describe the index set in all cases:
282297
Status error;
283298
uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(
284-
valobj_addr + ptr_size, 4, 0, error);
299+
valobj_addr + ptr_size, 4, 0, error);
285300
if (error.Fail())
286301
return false;
287-
// this means the set is empty - count = 0
288-
if ((mode & 1) == 1) {
289-
count = 0;
290-
break;
302+
// Now check if the index is held in a bitmask in the object:
303+
if (runtime->GetFoundationVersion() >= 2000) {
304+
// The first two bits are "isSingleRange" and "isBitfield". If this is
305+
// a bitfield we handle it here, otherwise set mode appropriately and
306+
// the rest of the treatment is in common.
307+
if ((mode & 2) == 2) {
308+
// The bitfield is a 64 bit uint at the beginning of the data var.
309+
uint64_t bitfield = process_sp->ReadUnsignedIntegerFromMemory(
310+
valobj_addr + 2 * ptr_size, 8, 0, error);
311+
if (error.Fail())
312+
return false;
313+
count = llvm::popcount(bitfield);
314+
break;
315+
}
316+
// It wasn't a bitfield, so read the isSingleRange from its new loc:
317+
if ((mode & 1) == 1)
318+
mode = 1; // this means the set only has one range
319+
else
320+
mode = 2; // this means the set has multiple ranges
321+
} else {
322+
// this means the set is empty - count = 0
323+
if ((mode & 1) == 1) {
324+
count = 0;
325+
break;
326+
}
327+
328+
if ((mode & 2) == 2)
329+
mode = 1; // this means the set only has one range
330+
else
331+
mode = 2; // this means the set has multiple ranges
291332
}
292-
if ((mode & 2) == 2)
293-
mode = 1; // this means the set only has one range
294-
else
295-
mode = 2; // this means the set has multiple ranges
296333
if (mode == 1) {
297334
count = process_sp->ReadUnsignedIntegerFromMemory(
298335
valobj_addr + 3 * ptr_size, ptr_size, 0, error);

0 commit comments

Comments
 (0)