forked from OSchip/llvm-project
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
This commit is contained in:
parent
02aa795785
commit
6e56c4961a
|
@ -858,29 +858,28 @@ bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx,
|
||||||
ModuleSP module_sp = m_module_wp.lock();
|
ModuleSP module_sp = m_module_wp.lock();
|
||||||
|
|
||||||
if (IsLocationList()) {
|
if (IsLocationList()) {
|
||||||
addr_t pc;
|
Address pc;
|
||||||
StackFrame *frame = nullptr;
|
StackFrame *frame = nullptr;
|
||||||
if (reg_ctx)
|
if (!reg_ctx || !reg_ctx->GetPCForSymbolication(pc)) {
|
||||||
pc = reg_ctx->GetPC();
|
|
||||||
else {
|
|
||||||
frame = exe_ctx->GetFramePtr();
|
frame = exe_ctx->GetFramePtr();
|
||||||
if (!frame)
|
if (!frame)
|
||||||
return false;
|
return false;
|
||||||
RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
|
RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
|
||||||
if (!reg_ctx_sp)
|
if (!reg_ctx_sp)
|
||||||
return false;
|
return false;
|
||||||
pc = reg_ctx_sp->GetPC();
|
reg_ctx_sp->GetPCForSymbolication(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func_load_addr != LLDB_INVALID_ADDRESS) {
|
if (func_load_addr != LLDB_INVALID_ADDRESS) {
|
||||||
if (pc == LLDB_INVALID_ADDRESS) {
|
if (!pc.IsValid()) {
|
||||||
if (error_ptr)
|
if (error_ptr)
|
||||||
error_ptr->SetErrorString("Invalid PC in frame.");
|
error_ptr->SetErrorString("Invalid PC in frame.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (llvm::Optional<DataExtractor> expr =
|
Target *target = exe_ctx->GetTargetPtr();
|
||||||
GetLocationExpression(func_load_addr, pc)) {
|
if (llvm::Optional<DataExtractor> expr = GetLocationExpression(
|
||||||
|
func_load_addr, pc.GetLoadAddress(target))) {
|
||||||
return DWARFExpression::Evaluate(
|
return DWARFExpression::Evaluate(
|
||||||
exe_ctx, reg_ctx, module_sp, *expr, m_dwarf_cu, m_reg_kind,
|
exe_ctx, reg_ctx, module_sp, *expr, m_dwarf_cu, m_reg_kind,
|
||||||
initial_value_ptr, object_address_ptr, result, error_ptr);
|
initial_value_ptr, object_address_ptr, result, error_ptr);
|
||||||
|
@ -2862,7 +2861,7 @@ bool DWARFExpression::MatchesOperand(StackFrame &frame,
|
||||||
if (load_function_start == LLDB_INVALID_ADDRESS)
|
if (load_function_start == LLDB_INVALID_ADDRESS)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
addr_t pc = frame.GetFrameCodeAddress().GetLoadAddress(
|
addr_t pc = frame.GetFrameCodeAddressForSymbolication().GetLoadAddress(
|
||||||
frame.CalculateTarget().get());
|
frame.CalculateTarget().get());
|
||||||
|
|
||||||
if (llvm::Optional<DataExtractor> expr =
|
if (llvm::Optional<DataExtractor> expr =
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
C_SOURCES := main.c
|
||||||
|
CFLAGS_EXTRAS := -O1
|
||||||
|
include Makefile.rules
|
|
@ -0,0 +1,40 @@
|
||||||
|
"""Test that lldb picks the correct DWARF location list entry with a return-pc out of bounds."""
|
||||||
|
|
||||||
|
import lldb
|
||||||
|
from lldbsuite.test.decorators import *
|
||||||
|
from lldbsuite.test.lldbtest import *
|
||||||
|
from lldbsuite.test import lldbutil
|
||||||
|
|
||||||
|
|
||||||
|
class LocationListLookupTestCase(TestBase):
|
||||||
|
|
||||||
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# Call super's setUp().
|
||||||
|
TestBase.setUp(self)
|
||||||
|
|
||||||
|
def test_loclist(self):
|
||||||
|
self.build()
|
||||||
|
exe = self.getBuildArtifact("a.out")
|
||||||
|
|
||||||
|
# Create a target by the debugger.
|
||||||
|
target = self.dbg.CreateTarget(exe)
|
||||||
|
self.assertTrue(target, VALID_TARGET)
|
||||||
|
self.dbg.SetAsync(False)
|
||||||
|
|
||||||
|
li = lldb.SBLaunchInfo(["a.out"])
|
||||||
|
error = lldb.SBError()
|
||||||
|
process = target.Launch(li, error)
|
||||||
|
self.assertTrue(process.IsValid())
|
||||||
|
self.assertTrue(process.is_stopped)
|
||||||
|
|
||||||
|
# Find `main` on the stack, then
|
||||||
|
# find `argv` local variable, then
|
||||||
|
# check that we can read the c-string in argv[0]
|
||||||
|
for f in process.GetSelectedThread().frames:
|
||||||
|
if f.GetDisplayFunctionName() == "main":
|
||||||
|
argv = f.GetValueForVariablePath("argv").GetChildAtIndex(0)
|
||||||
|
strm = lldb.SBStream()
|
||||||
|
argv.GetDescription(strm)
|
||||||
|
self.assertNotEqual(strm.GetData().find('a.out'), -1)
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// The goal with this test is:
|
||||||
|
// 1. Have main() followed by foo()
|
||||||
|
// 2. Have the no-return call to abort() in main be the last instruction
|
||||||
|
// 3. Have the next instruction be the start of foo()
|
||||||
|
// 4. The debug info for argv uses a location list.
|
||||||
|
// clang at -O1 on x86_64 or arm64 has debuginfo like
|
||||||
|
// DW_AT_location (0x00000049:
|
||||||
|
// [0x0000000100003f15, 0x0000000100003f25): DW_OP_reg4 RSI
|
||||||
|
// [0x0000000100003f25, 0x0000000100003f5b): DW_OP_reg15 R15)
|
||||||
|
|
||||||
|
void foo(int);
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
char *file = argv[0];
|
||||||
|
char f0 = file[0];
|
||||||
|
printf("%c\n", f0);
|
||||||
|
foo(f0);
|
||||||
|
printf("%s %d\n", argv[0], argc);
|
||||||
|
abort(); /// argv is still be accessible here
|
||||||
|
}
|
||||||
|
void foo(int in) { printf("%d\n", in); }
|
Loading…
Reference in New Issue