Skip to content

Commit 4d9039c

Browse files
committed
Add support for fetching signed values from tagged pointers.
The ObjC runtime offers both signed & unsigned tagged pointer value accessors to tagged pointer providers, but lldb's tagged pointer code only implemented the unsigned one. This patch adds an emulation of the signed one. The motivation for doing this is that NSNumbers use the signed accessor (they are always signed) and we need to follow that in our summary provider or we will get incorrect values for negative NSNumbers. The data-formatter-objc test file had NSNumber examples (along with lots of other goodies) but the NSNumber values weren't tested. So I also added checks for those values to the test. I also did a quick audit of the other types in that main.m file, and it looks like pretty much all the other values are either intermediates or are tested. Differential Revision: https://reviews.llvm.org/D99694
1 parent 432b2ab commit 4d9039c

File tree

6 files changed

+92
-17
lines changed

6 files changed

+92
-17
lines changed

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ static void NSNumber_FormatInt(ValueObject &valobj, Stream &stream, int value,
351351
}
352352

353353
static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream,
354-
uint64_t value, lldb::LanguageType lang) {
354+
int64_t value, lldb::LanguageType lang) {
355355
static ConstString g_TypeHint("NSNumber:long");
356356

357357
std::string prefix, suffix;
@@ -456,9 +456,15 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
456456
return NSDecimalNumberSummaryProvider(valobj, stream, options);
457457

458458
if (class_name == "NSNumber" || class_name == "__NSCFNumber") {
459-
uint64_t value = 0;
459+
int64_t value = 0;
460460
uint64_t i_bits = 0;
461-
if (descriptor->GetTaggedPointerInfo(&i_bits, &value)) {
461+
if (descriptor->GetTaggedPointerInfoSigned(&i_bits, &value)) {
462+
// Check for "preserved" numbers. We still don't support them yet.
463+
if (i_bits & 0x8) {
464+
lldbassert(!static_cast<bool>("We should handle preserved numbers!"));
465+
return false;
466+
}
467+
462468
switch (i_bits) {
463469
case 0:
464470
NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
4141
return false;
4242
}
4343

44+
bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
45+
int64_t *value_bits = nullptr,
46+
uint64_t *payload = nullptr) override {
47+
return false;
48+
}
49+
4450
uint64_t GetInstanceSize() override;
4551

4652
ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; }
@@ -253,7 +259,7 @@ class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {
253259

254260
ClassDescriptorV2Tagged(
255261
ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,
256-
uint64_t payload) {
262+
uint64_t u_payload, int64_t s_payload) {
257263
if (!actual_class_sp) {
258264
m_valid = false;
259265
return;
@@ -264,9 +270,10 @@ class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {
264270
return;
265271
}
266272
m_valid = true;
267-
m_payload = payload;
273+
m_payload = u_payload;
268274
m_info_bits = (m_payload & 0x0FULL);
269275
m_value_bits = (m_payload & ~0x0FULL) >> 4;
276+
m_value_bits_signed = (s_payload & ~0x0FLL) >> 4;
270277
}
271278

272279
~ClassDescriptorV2Tagged() override = default;
@@ -308,6 +315,18 @@ class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {
308315
return true;
309316
}
310317

318+
bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
319+
int64_t *value_bits = nullptr,
320+
uint64_t *payload = nullptr) override {
321+
if (info_bits)
322+
*info_bits = GetInfoBits();
323+
if (value_bits)
324+
*value_bits = GetValueBitsSigned();
325+
if (payload)
326+
*payload = GetPayload();
327+
return true;
328+
}
329+
311330
uint64_t GetInstanceSize() override {
312331
return (IsValid() ? m_pointer_size : 0);
313332
}
@@ -319,6 +338,10 @@ class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {
319338
// these calls are not part of any formal tagged pointers specification
320339
virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); }
321340

341+
virtual int64_t GetValueBitsSigned() {
342+
return (IsValid() ? m_value_bits_signed : 0);
343+
}
344+
322345
virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); }
323346

324347
virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); }
@@ -329,6 +352,7 @@ class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {
329352
bool m_valid;
330353
uint64_t m_info_bits;
331354
uint64_t m_value_bits;
355+
int64_t m_value_bits_signed;
332356
uint64_t m_payload;
333357
};
334358

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ class AppleObjCRuntimeV1 : public AppleObjCRuntime {
6464
return false;
6565
}
6666

67+
bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
68+
int64_t *value_bits = nullptr,
69+
uint64_t *payload = nullptr) override {
70+
return false;
71+
}
72+
6773
uint64_t GetInstanceSize() override { return m_instance_size; }
6874

6975
ObjCISA GetISA() override { return m_isa; }

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2457,7 +2457,6 @@ ObjCLanguageRuntime::ClassDescriptorSP
24572457
AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(
24582458
lldb::addr_t ptr) {
24592459
ClassDescriptorSP actual_class_descriptor_sp;
2460-
uint64_t data_payload;
24612460
uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();
24622461

24632462
if (!IsPossibleTaggedPointer(unobfuscated))
@@ -2485,12 +2484,15 @@ AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(
24852484
m_cache[slot] = actual_class_descriptor_sp;
24862485
}
24872486

2488-
data_payload =
2487+
uint64_t data_payload =
24892488
(((uint64_t)unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >>
24902489
m_objc_debug_taggedpointer_payload_rshift);
2491-
2492-
return ClassDescriptorSP(
2493-
new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload));
2490+
int64_t data_payload_signed =
2491+
((int64_t)((int64_t)unobfuscated
2492+
<< m_objc_debug_taggedpointer_payload_lshift) >>
2493+
m_objc_debug_taggedpointer_payload_rshift);
2494+
return ClassDescriptorSP(new ClassDescriptorV2Tagged(
2495+
actual_class_descriptor_sp, data_payload, data_payload_signed));
24942496
}
24952497

24962498
AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended(
@@ -2542,7 +2544,6 @@ ObjCLanguageRuntime::ClassDescriptorSP
25422544
AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(
25432545
lldb::addr_t ptr) {
25442546
ClassDescriptorSP actual_class_descriptor_sp;
2545-
uint64_t data_payload;
25462547
uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();
25472548

25482549
if (!IsPossibleTaggedPointer(unobfuscated))
@@ -2573,12 +2574,16 @@ AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(
25732574
m_ext_cache[slot] = actual_class_descriptor_sp;
25742575
}
25752576

2576-
data_payload = (((uint64_t)unobfuscated
2577-
<< m_objc_debug_taggedpointer_ext_payload_lshift) >>
2578-
m_objc_debug_taggedpointer_ext_payload_rshift);
2577+
uint64_t data_payload = (((uint64_t)unobfuscated
2578+
<< m_objc_debug_taggedpointer_ext_payload_lshift) >>
2579+
m_objc_debug_taggedpointer_ext_payload_rshift);
2580+
int64_t data_payload_signed =
2581+
((int64_t)((int64_t)unobfuscated
2582+
<< m_objc_debug_taggedpointer_ext_payload_lshift) >>
2583+
m_objc_debug_taggedpointer_ext_payload_rshift);
25792584

2580-
return ClassDescriptorSP(
2581-
new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload));
2585+
return ClassDescriptorSP(new ClassDescriptorV2Tagged(
2586+
actual_class_descriptor_sp, data_payload, data_payload_signed));
25822587
}
25832588

25842589
AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache(

lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,20 @@ class ObjCLanguageRuntime : public LanguageRuntime {
8787

8888
virtual bool IsValid() = 0;
8989

90+
/// There are two routines in the ObjC runtime that tagged pointer clients
91+
/// can call to get the value from their tagged pointer, one that retrieves
92+
/// it as an unsigned value and one a signed value. These two
93+
/// GetTaggedPointerInfo methods mirror those two ObjC runtime calls.
94+
/// @{
9095
virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
9196
uint64_t *value_bits = nullptr,
9297
uint64_t *payload = nullptr) = 0;
9398

99+
virtual bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
100+
int64_t *value_bits = nullptr,
101+
uint64_t *payload = nullptr) = 0;
102+
/// @}
103+
94104
virtual uint64_t GetInstanceSize() = 0;
95105

96106
// use to implement version-specific additional constraints on pointers

lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCCF.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ def test_coreframeworks_and_run_command(self):
4545
'(Point) point = (v=7, h=12)', '(Point *) point_ptr = (v=7, h=12)',
4646
'(SEL) foo_selector = "foo_selector_impl"'
4747
]
48-
4948
self.expect("frame variable", substrs=expect_strings)
5049

5150
if self.getArchitecture() in ['i386', 'x86_64']:
@@ -56,3 +55,28 @@ def test_coreframeworks_and_run_command(self):
5655
'(HIRect) hi_rect = origin=(x = 3, y = 5) size=(width = 4, height = 6)',
5756
]
5857
self.expect("frame variable", substrs=extra_string)
58+
59+
# The original tests left out testing the NSNumber values, so do that here.
60+
# This set is all pointers, with summaries, so we only check the summary.
61+
var_list_pointer = [
62+
['NSNumber *', 'num1', '(int)5'],
63+
['NSNumber *', 'num2', '(float)3.140000'],
64+
['NSNumber *', 'num3', '(double)3.14'],
65+
['NSNumber *', 'num4', '(int128_t)18446744073709551614'],
66+
['NSNumber *', 'num5', '(char)65'],
67+
['NSNumber *', 'num6', '(long)255'],
68+
['NSNumber *', 'num7', '(long)2000000'],
69+
['NSNumber *', 'num8_Y', 'YES'],
70+
['NSNumber *', 'num8_N', 'NO'],
71+
['NSNumber *', 'num9', '(short)-31616'],
72+
['NSNumber *', 'num_at1', '(int)12'],
73+
['NSNumber *', 'num_at2', '(int)-12'],
74+
['NSNumber *', 'num_at3', '(double)12.5'],
75+
['NSNumber *', 'num_at4', '(double)-12.5'],
76+
['NSDecimalNumber *', 'decimal_number', '123456 x 10^-10'],
77+
['NSDecimalNumber *', 'decimal_number_neg', '-123456 x 10^10']
78+
]
79+
for type, var_path, summary in var_list_pointer:
80+
self.expect_var_path(var_path, summary, None, type)
81+
82+

0 commit comments

Comments
 (0)