Skip to content

Commit 42570b6

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 (cherry picked from commit 4d9039c)
1 parent d3e945a commit 42570b6

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
@@ -2472,7 +2472,6 @@ ObjCLanguageRuntime::ClassDescriptorSP
24722472
AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(
24732473
lldb::addr_t ptr) {
24742474
ClassDescriptorSP actual_class_descriptor_sp;
2475-
uint64_t data_payload;
24762475
uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();
24772476

24782477
if (!IsPossibleTaggedPointer(unobfuscated))
@@ -2500,12 +2499,15 @@ AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(
25002499
m_cache[slot] = actual_class_descriptor_sp;
25012500
}
25022501

2503-
data_payload =
2502+
uint64_t data_payload =
25042503
(((uint64_t)unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >>
25052504
m_objc_debug_taggedpointer_payload_rshift);
2506-
2507-
return ClassDescriptorSP(
2508-
new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload));
2505+
int64_t data_payload_signed =
2506+
((int64_t)((int64_t)unobfuscated
2507+
<< m_objc_debug_taggedpointer_payload_lshift) >>
2508+
m_objc_debug_taggedpointer_payload_rshift);
2509+
return ClassDescriptorSP(new ClassDescriptorV2Tagged(
2510+
actual_class_descriptor_sp, data_payload, data_payload_signed));
25092511
}
25102512

25112513
AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended(
@@ -2557,7 +2559,6 @@ ObjCLanguageRuntime::ClassDescriptorSP
25572559
AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(
25582560
lldb::addr_t ptr) {
25592561
ClassDescriptorSP actual_class_descriptor_sp;
2560-
uint64_t data_payload;
25612562
uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();
25622563

25632564
if (!IsPossibleTaggedPointer(unobfuscated))
@@ -2588,12 +2589,16 @@ AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(
25882589
m_ext_cache[slot] = actual_class_descriptor_sp;
25892590
}
25902591

2591-
data_payload = (((uint64_t)unobfuscated
2592-
<< m_objc_debug_taggedpointer_ext_payload_lshift) >>
2593-
m_objc_debug_taggedpointer_ext_payload_rshift);
2592+
uint64_t data_payload = (((uint64_t)unobfuscated
2593+
<< m_objc_debug_taggedpointer_ext_payload_lshift) >>
2594+
m_objc_debug_taggedpointer_ext_payload_rshift);
2595+
int64_t data_payload_signed =
2596+
((int64_t)((int64_t)unobfuscated
2597+
<< m_objc_debug_taggedpointer_ext_payload_lshift) >>
2598+
m_objc_debug_taggedpointer_ext_payload_rshift);
25942599

2595-
return ClassDescriptorSP(
2596-
new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload));
2600+
return ClassDescriptorSP(new ClassDescriptorV2Tagged(
2601+
actual_class_descriptor_sp, data_payload, data_payload_signed));
25972602
}
25982603

25992604
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)