Skip to content

Commit 2c76e88

Browse files
authored
Add register lookup as another fallback computation for address-expressions (#85492)
The idea behind the address-expression is that it handles all the common expressions that produce addresses. It handles actual valid expressions that return a scalar, and it handles useful cases that the various source languages don't support. At present, the fallback handles: <symbol_name>{+-}<offset> which isn't valid C but is very handy. This patch adds handling of: $<reg_name> and $<reg_name>{+-}<offset> That's kind of pointless in C because the C expression parser handles that expression already. But some languages don't have a straightforward way to represent register values like this (swift) so having this fallback is quite a quality of life improvement. I added a test which tests that I didn't mess up either of these fallbacks, though it doesn't test the actually handling of registers that I added, since the expression parser for C succeeds in that case and returns before this code gets run. I will add a test on the swift fork for that checks that this works the same way for a swift frame after this check.
1 parent 8e625db commit 2c76e88

File tree

4 files changed

+99
-7
lines changed

4 files changed

+99
-7
lines changed

lldb/source/Interpreter/OptionArgParser.cpp

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
#include "lldb/Interpreter/OptionArgParser.h"
1010
#include "lldb/DataFormatters/FormatManager.h"
1111
#include "lldb/Target/ABI.h"
12+
#include "lldb/Target/RegisterContext.h"
1213
#include "lldb/Target/Target.h"
14+
#include "lldb/Utility/RegisterValue.h"
1315
#include "lldb/Utility/Status.h"
1416
#include "lldb/Utility/StreamString.h"
1517

@@ -233,24 +235,68 @@ OptionArgParser::DoToAddress(const ExecutionContext *exe_ctx, llvm::StringRef s,
233235
// Since the compiler can't handle things like "main + 12" we should try to
234236
// do this for now. The compiler doesn't like adding offsets to function
235237
// pointer types.
238+
// Some languages also don't have a natural representation for register
239+
// values (e.g. swift) so handle simple uses of them here as well.
240+
// We use a regex to parse these forms, the regex handles:
241+
// $reg_name
242+
// $reg_name+offset
243+
// symbol_name+offset
244+
//
245+
// The important matching elements in the regex below are:
246+
// 1: The reg name if there's no +offset
247+
// 3: The symbol/reg name if there is an offset
248+
// 4: +/-
249+
// 5: The offset value.
236250
static RegularExpression g_symbol_plus_offset_regex(
237-
"^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$");
251+
"^(\\$[^ +-]+)|(([^ +-]+)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*)$");
238252

239253
llvm::SmallVector<llvm::StringRef, 4> matches;
240254
if (g_symbol_plus_offset_regex.Execute(sref, &matches)) {
241255
uint64_t offset = 0;
242-
llvm::StringRef name = matches[1];
243-
llvm::StringRef sign = matches[2];
244-
llvm::StringRef str_offset = matches[3];
245-
if (!str_offset.getAsInteger(0, offset)) {
256+
llvm::StringRef name;
257+
if (!matches[1].empty())
258+
name = matches[1];
259+
else
260+
name = matches[3];
261+
262+
llvm::StringRef sign = matches[4];
263+
llvm::StringRef str_offset = matches[5];
264+
265+
// Some languages don't have a natural type for register values, but it
266+
// is still useful to look them up here:
267+
std::optional<lldb::addr_t> register_value;
268+
StackFrame *frame = exe_ctx->GetFramePtr();
269+
llvm::StringRef reg_name = name;
270+
if (frame && reg_name.consume_front("$")) {
271+
RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
272+
if (reg_ctx_sp) {
273+
const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfoByName(reg_name);
274+
if (reg_info) {
275+
RegisterValue reg_val;
276+
bool success = reg_ctx_sp->ReadRegister(reg_info, reg_val);
277+
if (success && reg_val.GetType() != RegisterValue::eTypeInvalid) {
278+
register_value = reg_val.GetAsUInt64(0, &success);
279+
if (!success)
280+
register_value.reset();
281+
}
282+
}
283+
}
284+
}
285+
if (!str_offset.empty() && !str_offset.getAsInteger(0, offset)) {
246286
Status error;
247-
addr = ToAddress(exe_ctx, name, LLDB_INVALID_ADDRESS, &error);
287+
if (register_value)
288+
addr = register_value.value();
289+
else
290+
addr = ToAddress(exe_ctx, name, LLDB_INVALID_ADDRESS, &error);
248291
if (addr != LLDB_INVALID_ADDRESS) {
249292
if (sign[0] == '+')
250293
return addr + offset;
251294
return addr - offset;
252295
}
253-
}
296+
} else if (register_value)
297+
// In the case of register values, someone might just want to get the
298+
// value in a language whose expression parser doesn't support registers.
299+
return register_value.value();
254300
}
255301

256302
if (error_ptr)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
C_SOURCES := main.c
2+
CFLAGS_EXTRAS := -std=c99
3+
4+
include Makefile.rules
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""
2+
Make sure that "target modules lookup -va $pc" works
3+
"""
4+
5+
6+
import lldb
7+
import lldbsuite.test.lldbutil as lldbutil
8+
from lldbsuite.test.lldbtest import *
9+
10+
11+
class TestImageLookupPCInC(TestBase):
12+
def test_sample_rename_this(self):
13+
"""There can be many tests in a test case - describe this test here."""
14+
self.build()
15+
self.main_source_file = lldb.SBFileSpec("main.c")
16+
self.sample_test()
17+
18+
def sample_test(self):
19+
"""Make sure the address expression resolves to the right function"""
20+
21+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
22+
self, "Set a breakpoint here", self.main_source_file
23+
)
24+
25+
self.expect("target modules lookup -va $pc", substrs=["doSomething"])
26+
self.expect("target modules lookup -va $pc+4", substrs=["doSomething"])
27+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <stdio.h>
2+
3+
void
4+
doSomething()
5+
{
6+
printf ("Set a breakpoint here.\n");
7+
printf ("Need a bit more code.\n");
8+
}
9+
10+
int
11+
main()
12+
{
13+
doSomething();
14+
return 0;
15+
}

0 commit comments

Comments
 (0)