Skip to content

Commit 4185656

Browse files
committed
Fix the NSIndexSet data formatter for changes in macOS Sonoma.
1 parent e229086 commit 4185656

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
@@ -237,7 +237,8 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider(
237237
if (!process_sp)
238238
return false;
239239

240-
ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
240+
AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
241+
ObjCLanguageRuntime::Get(*process_sp));
241242

242243
if (!runtime)
243244
return false;
@@ -264,20 +265,56 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider(
264265

265266
do {
266267
if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") {
268+
// Foundation version 2000 added a bitmask if the index set fit in 64 bits
269+
// and a Tagged Pointer version if the bitmask is small enough to fit in
270+
// the tagged pointer payload.
271+
// It also changed the layout (but not the size) of the set descriptor.
272+
273+
// First check whether this is a tagged pointer. The bitmask will be in
274+
// the payload of the tagged pointer.
275+
uint64_t payload;
276+
if (runtime->GetFoundationVersion() >= 2000
277+
&& descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) {
278+
count = llvm::popcount(payload);
279+
break;
280+
}
281+
// The first 32 bits describe the index set in all cases:
267282
Status error;
268283
uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(
269-
valobj_addr + ptr_size, 4, 0, error);
284+
valobj_addr + ptr_size, 4, 0, error);
270285
if (error.Fail())
271286
return false;
272-
// this means the set is empty - count = 0
273-
if ((mode & 1) == 1) {
274-
count = 0;
275-
break;
287+
// Now check if the index is held in a bitmask in the object:
288+
if (runtime->GetFoundationVersion() >= 2000) {
289+
// The first two bits are "isSingleRange" and "isBitfield". If this is
290+
// a bitfield we handle it here, otherwise set mode appropriately and
291+
// the rest of the treatment is in common.
292+
if ((mode & 2) == 2) {
293+
// The bitfield is a 64 bit uint at the beginning of the data var.
294+
uint64_t bitfield = process_sp->ReadUnsignedIntegerFromMemory(
295+
valobj_addr + 2 * ptr_size, 8, 0, error);
296+
if (error.Fail())
297+
return false;
298+
count = llvm::popcount(bitfield);
299+
break;
300+
}
301+
// It wasn't a bitfield, so read the isSingleRange from its new loc:
302+
if ((mode & 1) == 1)
303+
mode = 1; // this means the set only has one range
304+
else
305+
mode = 2; // this means the set has multiple ranges
306+
} else {
307+
// this means the set is empty - count = 0
308+
if ((mode & 1) == 1) {
309+
count = 0;
310+
break;
311+
}
312+
313+
if ((mode & 2) == 2)
314+
mode = 1; // this means the set only has one range
315+
else
316+
mode = 2; // this means the set has multiple ranges
276317
}
277-
if ((mode & 2) == 2)
278-
mode = 1; // this means the set only has one range
279-
else
280-
mode = 2; // this means the set has multiple ranges
281318
if (mode == 1) {
282319
count = process_sp->ReadUnsignedIntegerFromMemory(
283320
valobj_addr + 3 * ptr_size, ptr_size, 0, error);

0 commit comments

Comments
 (0)