Skip to content

Commit 4d635be

Browse files
committed
Add SBValue::GetValueAsAddress API for removing non-addressing metadata
On target where metadata is stored in bits that aren't used for virtual addressing -- AArch64 Top Byte Ignore and pointer authentication are two examples -- an SBValue object representing a pointer will return the address with metadata for SBValue::GetValueAsUnsigned. Users may want to get the virtual address without the metadata; this new method gives them a way to do this. Differential Revision: https://reviews.llvm.org/D142792
1 parent 2010269 commit 4d635be

File tree

9 files changed

+157
-2
lines changed

9 files changed

+157
-2
lines changed

lldb/bindings/interface/SBValueDocstrings.i

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,24 @@ linked list."
135135
%feature("docstring", "Expands nested expressions like .a->b[0].c[1]->d."
136136
) lldb::SBValue::GetValueForExpressionPath;
137137

138+
%feature("docstring", "
139+
Return the value as an address. On failure, LLDB_INVALID_ADDRESS
140+
will be returned. On architectures like AArch64, where the
141+
top (unaddressable) bits can be used for authentication,
142+
memory tagging, or top byte ignore, this method will return
143+
the value with those top bits cleared.
144+
145+
GetValueAsUnsigned returns the actual value, with the
146+
authentication/Top Byte Ignore/Memory Tagging Extension bits.
147+
148+
Calling this on a random value which is not a pointer is
149+
incorrect. Call GetType().IsPointerType() if in doubt.
150+
151+
An SB API program may want to show both the literal byte value
152+
and the address it refers to in memory. These two SBValue
153+
methods allow SB API writers to behave appropriately for their
154+
interface.") lldb::SBValue::GetValueAsAddress;
155+
138156
%feature("doctstring", "
139157
Returns the number for children.
140158

lldb/include/lldb/API/SBValue.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ class LLDB_API SBValue {
6262

6363
uint64_t GetValueAsUnsigned(uint64_t fail_value = 0);
6464

65+
lldb::addr_t GetValueAsAddress();
66+
6567
ValueType GetValueType();
6668

6769
// If you call this on a newly created ValueObject, it will always return

lldb/include/lldb/Core/ValueObject.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,10 @@ class ValueObject {
564564

565565
lldb::addr_t GetPointerValue(AddressType *address_type = nullptr);
566566

567+
/// Remove TBI/MTE/ptrauth bits from address, if those are defined on this
568+
/// target/ABI.
569+
lldb::addr_t GetStrippedPointerValue(lldb::addr_t address);
570+
567571
lldb::ValueObjectSP GetSyntheticChild(ConstString key) const;
568572

569573
lldb::ValueObjectSP GetSyntheticArrayMember(size_t index, bool can_create);

lldb/source/API/SBValue.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "lldb/Symbol/Type.h"
3131
#include "lldb/Symbol/Variable.h"
3232
#include "lldb/Symbol/VariableList.h"
33+
#include "lldb/Target/ABI.h"
3334
#include "lldb/Target/ExecutionContext.h"
3435
#include "lldb/Target/Process.h"
3536
#include "lldb/Target/StackFrame.h"
@@ -924,6 +925,25 @@ uint64_t SBValue::GetValueAsUnsigned(uint64_t fail_value) {
924925
return fail_value;
925926
}
926927

928+
lldb::addr_t SBValue::GetValueAsAddress() {
929+
addr_t fail_value = LLDB_INVALID_ADDRESS;
930+
ValueLocker locker;
931+
lldb::ValueObjectSP value_sp(GetSP(locker));
932+
if (value_sp) {
933+
bool success = true;
934+
uint64_t ret_val = fail_value;
935+
ret_val = value_sp->GetValueAsUnsigned(fail_value, &success);
936+
if (!success)
937+
return fail_value;
938+
if (ProcessSP process_sp = m_opaque_sp->GetProcessSP())
939+
if (ABISP abi_sp = process_sp->GetABI())
940+
return abi_sp->FixCodeAddress(ret_val);
941+
return ret_val;
942+
}
943+
944+
return fail_value;
945+
}
946+
927947
bool SBValue::MightHaveChildren() {
928948
LLDB_INSTRUMENT_VA(this);
929949

lldb/source/Core/ValueObject.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "lldb/Symbol/SymbolContext.h"
3232
#include "lldb/Symbol/Type.h"
3333
#include "lldb/Symbol/Variable.h"
34+
#include "lldb/Target/ABI.h"
3435
#include "lldb/Target/ExecutionContext.h"
3536
#include "lldb/Target/Language.h"
3637
#include "lldb/Target/LanguageRuntime.h"
@@ -1453,6 +1454,14 @@ addr_t ValueObject::GetAddressOf(bool scalar_is_load_address,
14531454
return LLDB_INVALID_ADDRESS;
14541455
}
14551456

1457+
addr_t ValueObject::GetStrippedPointerValue(addr_t address) {
1458+
ExecutionContext exe_ctx(GetExecutionContextRef());
1459+
if (Process *process = exe_ctx.GetProcessPtr())
1460+
if (ABISP abi_sp = process->GetABI())
1461+
return abi_sp->FixCodeAddress(address);
1462+
return address;
1463+
}
1464+
14561465
addr_t ValueObject::GetPointerValue(AddressType *address_type) {
14571466
addr_t address = LLDB_INVALID_ADDRESS;
14581467
if (address_type)
@@ -1468,11 +1477,15 @@ addr_t ValueObject::GetPointerValue(AddressType *address_type) {
14681477
address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
14691478
break;
14701479

1471-
case Value::ValueType::HostAddress:
1480+
case Value::ValueType::HostAddress: {
1481+
lldb::offset_t data_offset = 0;
1482+
address = m_data.GetAddress(&data_offset);
1483+
} break;
1484+
14721485
case Value::ValueType::LoadAddress:
14731486
case Value::ValueType::FileAddress: {
14741487
lldb::offset_t data_offset = 0;
1475-
address = m_data.GetAddress(&data_offset);
1488+
address = GetStrippedPointerValue(m_data.GetAddress(&data_offset));
14761489
} break;
14771490
}
14781491

@@ -3011,6 +3024,11 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
30113024
if (type) {
30123025
CompilerType pointer_type(type.GetPointerType());
30133026
if (pointer_type) {
3027+
if (Process *process = exe_ctx.GetProcessPtr()) {
3028+
if (ABISP abi_sp = process->GetABI()) {
3029+
address = abi_sp->FixCodeAddress(address);
3030+
}
3031+
}
30143032
lldb::DataBufferSP buffer(
30153033
new lldb_private::DataBufferHeap(&address, sizeof(lldb::addr_t)));
30163034
lldb::ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create(

lldb/source/DataFormatters/ValueObjectPrinter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,13 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed,
440440
if (!m_options.m_hide_name)
441441
m_stream->PutChar(' ');
442442
m_stream->PutCString(m_value);
443+
if (IsPointerValue(m_valobj->GetCompilerType())) {
444+
uint64_t orig_value = m_valobj->GetValueAsUnsigned(0);
445+
addr_t stripped = m_valobj->GetPointerValue();
446+
if (stripped != orig_value) {
447+
m_stream->Printf(" (actual=0x%" PRIx64 ")", stripped);
448+
}
449+
}
443450
value_printed = true;
444451
}
445452
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
C_SOURCES := main.c
2+
3+
include Makefile.rules
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""Test that SBValue clears non-addressable bits"""
2+
3+
import lldb
4+
from lldbsuite.test.decorators import *
5+
from lldbsuite.test.lldbtest import *
6+
from lldbsuite.test import lldbutil
7+
8+
class TestClearSBValueNonAddressableBits(TestBase):
9+
10+
NO_DEBUG_INFO_TESTCASE = True
11+
12+
# On AArch64 systems, the top bits that are not used for
13+
# addressing may be used for TBI, MTE, and/or pointer
14+
# authentication.
15+
@skipIf(archs=no_match(['aarch64', 'arm64', 'arm64e']))
16+
17+
# Only run this test on systems where TBI is known to be
18+
# enabled, so the address mask will clear the TBI bits.
19+
@skipUnlessPlatform(["linux"]+lldbplatformutil.getDarwinOSTriples())
20+
def test(self):
21+
self.source = 'main.c'
22+
self.build()
23+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
24+
"break here", lldb.SBFileSpec(self.source, False))
25+
26+
if self.TraceOn():
27+
self.runCmd ("frame variable")
28+
self.runCmd ("frame variable &count &global")
29+
30+
frame = thread.GetFrameAtIndex(0)
31+
32+
count_p = frame.FindVariable("count_p")
33+
count_invalid_p = frame.FindVariable("count_invalid_p")
34+
self.assertEqual(count_p.GetValueAsUnsigned(), count_invalid_p.GetValueAsAddress())
35+
self.assertNotEqual(count_invalid_p.GetValueAsUnsigned(), count_invalid_p.GetValueAsAddress())
36+
self.assertEqual(5, count_p.Dereference().GetValueAsUnsigned())
37+
self.assertEqual(5, count_invalid_p.Dereference().GetValueAsUnsigned())
38+
strm = lldb.SBStream()
39+
count_invalid_p.GetDescription(strm)
40+
self.assertIn("actual=0x", strm.GetData())
41+
42+
global_p = frame.FindVariable("global_p")
43+
global_invalid_p = frame.FindVariable("global_invalid_p")
44+
self.assertEqual(global_p.GetValueAsUnsigned(), global_invalid_p.GetValueAsAddress())
45+
self.assertNotEqual(global_invalid_p.GetValueAsUnsigned(), global_invalid_p.GetValueAsAddress())
46+
self.assertEqual(10, global_p.Dereference().GetValueAsUnsigned())
47+
self.assertEqual(10, global_invalid_p.Dereference().GetValueAsUnsigned())
48+
strm = lldb.SBStream()
49+
global_invalid_p.GetDescription(strm)
50+
self.assertIn("actual=0x", strm.GetData())
51+
52+
main_p = frame.FindVariable("main_p")
53+
main_invalid_p = frame.FindVariable("main_invalid_p")
54+
self.assertEqual(main_p.GetValueAsUnsigned(), main_invalid_p.GetValueAsAddress())
55+
strm = lldb.SBStream()
56+
main_invalid_p.GetDescription(strm)
57+
self.assertIn("main at main.c:", strm.GetData())
58+
self.assertIn("actual=0x", strm.GetData())
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
int global = 10;
2+
3+
int main() {
4+
int count = 5;
5+
int *count_p = &count;
6+
7+
// Add some metadata in the top byte (this will crash unless the
8+
// test is running with TBI enabled, but we won't dereference it)
9+
10+
intptr_t scratch = (intptr_t)count_p;
11+
scratch |= (3ULL << 60);
12+
int *count_invalid_p = (int *)scratch;
13+
14+
int (*main_p)() = main;
15+
scratch = (intptr_t)main_p;
16+
scratch |= (3ULL << 60);
17+
int (*main_invalid_p)() = (int (*)())scratch;
18+
19+
int *global_p = &global;
20+
scratch = (intptr_t)global_p;
21+
scratch |= (3ULL << 60);
22+
int *global_invalid_p = (int *)scratch;
23+
24+
return count; // break here
25+
}

0 commit comments

Comments
 (0)