Skip to content

Commit 6e56c49

Browse files
committed
Decr pc when looking for DWARF loc list entry mid-stack
When looking for a variable location in a DWARF location list, we search the list of ranges to find one that includes the pc. With a function mid-stack, the "pc" is the return pc instead of the call instruction, and in optimized code this can be another function or a different basic block (with different variable locations). Back up the "pc" value mid-stack to find the correct location list entry. Differential Revision: https://reviews.llvm.org/D124597 rdar://63903416
1 parent 02aa795 commit 6e56c49

File tree

4 files changed

+74
-9
lines changed

4 files changed

+74
-9
lines changed

lldb/source/Expression/DWARFExpression.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -858,29 +858,28 @@ bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx,
858858
ModuleSP module_sp = m_module_wp.lock();
859859

860860
if (IsLocationList()) {
861-
addr_t pc;
861+
Address pc;
862862
StackFrame *frame = nullptr;
863-
if (reg_ctx)
864-
pc = reg_ctx->GetPC();
865-
else {
863+
if (!reg_ctx || !reg_ctx->GetPCForSymbolication(pc)) {
866864
frame = exe_ctx->GetFramePtr();
867865
if (!frame)
868866
return false;
869867
RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
870868
if (!reg_ctx_sp)
871869
return false;
872-
pc = reg_ctx_sp->GetPC();
870+
reg_ctx_sp->GetPCForSymbolication(pc);
873871
}
874872

875873
if (func_load_addr != LLDB_INVALID_ADDRESS) {
876-
if (pc == LLDB_INVALID_ADDRESS) {
874+
if (!pc.IsValid()) {
877875
if (error_ptr)
878876
error_ptr->SetErrorString("Invalid PC in frame.");
879877
return false;
880878
}
881879

882-
if (llvm::Optional<DataExtractor> expr =
883-
GetLocationExpression(func_load_addr, pc)) {
880+
Target *target = exe_ctx->GetTargetPtr();
881+
if (llvm::Optional<DataExtractor> expr = GetLocationExpression(
882+
func_load_addr, pc.GetLoadAddress(target))) {
884883
return DWARFExpression::Evaluate(
885884
exe_ctx, reg_ctx, module_sp, *expr, m_dwarf_cu, m_reg_kind,
886885
initial_value_ptr, object_address_ptr, result, error_ptr);
@@ -2862,7 +2861,7 @@ bool DWARFExpression::MatchesOperand(StackFrame &frame,
28622861
if (load_function_start == LLDB_INVALID_ADDRESS)
28632862
return false;
28642863

2865-
addr_t pc = frame.GetFrameCodeAddress().GetLoadAddress(
2864+
addr_t pc = frame.GetFrameCodeAddressForSymbolication().GetLoadAddress(
28662865
frame.CalculateTarget().get());
28672866

28682867
if (llvm::Optional<DataExtractor> expr =
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
C_SOURCES := main.c
2+
CFLAGS_EXTRAS := -O1
3+
include Makefile.rules
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Test that lldb picks the correct DWARF location list entry with a return-pc out of bounds."""
2+
3+
import lldb
4+
from lldbsuite.test.decorators import *
5+
from lldbsuite.test.lldbtest import *
6+
from lldbsuite.test import lldbutil
7+
8+
9+
class LocationListLookupTestCase(TestBase):
10+
11+
mydir = TestBase.compute_mydir(__file__)
12+
13+
def setUp(self):
14+
# Call super's setUp().
15+
TestBase.setUp(self)
16+
17+
def test_loclist(self):
18+
self.build()
19+
exe = self.getBuildArtifact("a.out")
20+
21+
# Create a target by the debugger.
22+
target = self.dbg.CreateTarget(exe)
23+
self.assertTrue(target, VALID_TARGET)
24+
self.dbg.SetAsync(False)
25+
26+
li = lldb.SBLaunchInfo(["a.out"])
27+
error = lldb.SBError()
28+
process = target.Launch(li, error)
29+
self.assertTrue(process.IsValid())
30+
self.assertTrue(process.is_stopped)
31+
32+
# Find `main` on the stack, then
33+
# find `argv` local variable, then
34+
# check that we can read the c-string in argv[0]
35+
for f in process.GetSelectedThread().frames:
36+
if f.GetDisplayFunctionName() == "main":
37+
argv = f.GetValueForVariablePath("argv").GetChildAtIndex(0)
38+
strm = lldb.SBStream()
39+
argv.GetDescription(strm)
40+
self.assertNotEqual(strm.GetData().find('a.out'), -1)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
4+
// The goal with this test is:
5+
// 1. Have main() followed by foo()
6+
// 2. Have the no-return call to abort() in main be the last instruction
7+
// 3. Have the next instruction be the start of foo()
8+
// 4. The debug info for argv uses a location list.
9+
// clang at -O1 on x86_64 or arm64 has debuginfo like
10+
// DW_AT_location (0x00000049:
11+
// [0x0000000100003f15, 0x0000000100003f25): DW_OP_reg4 RSI
12+
// [0x0000000100003f25, 0x0000000100003f5b): DW_OP_reg15 R15)
13+
14+
void foo(int);
15+
int main(int argc, char **argv) {
16+
char *file = argv[0];
17+
char f0 = file[0];
18+
printf("%c\n", f0);
19+
foo(f0);
20+
printf("%s %d\n", argv[0], argc);
21+
abort(); /// argv is still be accessible here
22+
}
23+
void foo(int in) { printf("%d\n", in); }

0 commit comments

Comments
 (0)