Skip to content

[lldb] Add SBValue::GetValueAsAddress API #90144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions lldb/bindings/interface/SBValueDocstrings.i
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,26 @@ linked list."
%feature("docstring", "Expands nested expressions like .a->b[0].c[1]->d."
) lldb::SBValue::GetValueForExpressionPath;

%feature("docstring", "
Return the value as an address. On failure, LLDB_INVALID_ADDRESS
will be returned. On architectures like AArch64, where the
top (unaddressable) bits can be used for authentication,
memory tagging, or top byte ignore, this method will return
the value with those top bits cleared.

GetValueAsUnsigned returns the actual value, with the
authentication/Top Byte Ignore/Memory Tagging Extension bits.

Calling this on a random value which is not a pointer is
incorrect. Call GetType().IsPointerType() if in doubt.

An SB API program may want to show both the literal byte value
and the address it refers to in memory. These two SBValue
methods allow SB API writers to behave appropriately for their
interface."
) lldb::SBValue::GetValueAsAddress;


%feature("doctstring", "
Returns the number for children.

Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/API/SBValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class LLDB_API SBValue {

uint64_t GetValueAsUnsigned(uint64_t fail_value = 0);

lldb::addr_t GetValueAsAddress();

ValueType GetValueType();

// If you call this on a newly created ValueObject, it will always return
Expand Down
19 changes: 19 additions & 0 deletions lldb/source/API/SBValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,25 @@ uint64_t SBValue::GetValueAsUnsigned(uint64_t fail_value) {
return fail_value;
}

lldb::addr_t SBValue::GetValueAsAddress() {
addr_t fail_value = LLDB_INVALID_ADDRESS;
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp) {
bool success = true;
uint64_t ret_val = fail_value;
ret_val = value_sp->GetValueAsUnsigned(fail_value, &success);
if (!success)
return fail_value;
ProcessSP process_sp = m_opaque_sp->GetProcessSP();
if (!process_sp)
return ret_val;
return process_sp->FixDataAddress(ret_val);
}

return fail_value;
}

bool SBValue::MightHaveChildren() {
LLDB_INSTRUMENT_VA(this);

Expand Down
3 changes: 3 additions & 0 deletions lldb/test/API/clear-sbvalue-nonaddressable-bits/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
C_SOURCES := main.c

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""Test that SBValue clears non-addressable bits"""

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestClearSBValueNonAddressableBits(TestBase):
NO_DEBUG_INFO_TESTCASE = True

# On AArch64 systems, the top bits that are not used for
# addressing may be used for TBI, MTE, and/or pointer
# authentication.
@skipIf(archs=no_match(["aarch64", "arm64", "arm64e"]))

# Only run this test on systems where TBI is known to be
# enabled, so the address mask will clear the TBI bits.
@skipUnlessPlatform(["linux"] + lldbplatformutil.getDarwinOSTriples())
def test(self):
self.source = "main.c"
self.build()
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec(self.source, False)
)

if self.TraceOn():
self.runCmd("frame variable")
self.runCmd("frame variable &count &global")

frame = thread.GetFrameAtIndex(0)

count_p = frame.FindVariable("count_p")
count_invalid_p = frame.FindVariable("count_invalid_p")
self.assertEqual(
count_p.GetValueAsUnsigned(), count_invalid_p.GetValueAsAddress()
)
self.assertNotEqual(
count_invalid_p.GetValueAsUnsigned(), count_invalid_p.GetValueAsAddress()
)
self.assertEqual(5, count_p.Dereference().GetValueAsUnsigned())
self.assertEqual(5, count_invalid_p.Dereference().GetValueAsUnsigned())

global_p = frame.FindVariable("global_p")
global_invalid_p = frame.FindVariable("global_invalid_p")
self.assertEqual(
global_p.GetValueAsUnsigned(), global_invalid_p.GetValueAsAddress()
)
self.assertNotEqual(
global_invalid_p.GetValueAsUnsigned(), global_invalid_p.GetValueAsAddress()
)
self.assertEqual(10, global_p.Dereference().GetValueAsUnsigned())
self.assertEqual(10, global_invalid_p.Dereference().GetValueAsUnsigned())

main_p = frame.FindVariable("main_p")
main_invalid_p = frame.FindVariable("main_invalid_p")
self.assertEqual(
main_p.GetValueAsUnsigned(), main_invalid_p.GetValueAsAddress()
)
27 changes: 27 additions & 0 deletions lldb/test/API/clear-sbvalue-nonaddressable-bits/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <stdint.h>

int global = 10;

int main() {
int count = 5;
int *count_p = &count;

// Add some metadata in the top byte (this will crash unless the
// test is running with TBI enabled, but we won't dereference it)

intptr_t scratch = (intptr_t)count_p;
scratch |= (3ULL << 60);
int *count_invalid_p = (int *)scratch;

int (*main_p)() = main;
scratch = (intptr_t)main_p;
scratch |= (3ULL << 60);
int (*main_invalid_p)() = (int (*)())scratch;

int *global_p = &global;
scratch = (intptr_t)global_p;
scratch |= (3ULL << 60);
int *global_invalid_p = (int *)scratch;

return count; // break here
}