forked from OSchip/llvm-project
Advanced guessing of rendezvous breakpoint
When rendezvous structure is not initialized we need to set up rendezvous breakpoint anyway. In this case the code will locate dynamic loader (interpreter) and look for known function names. Bug: https://bugs.llvm.org/show_bug.cgi?id=25806 Differential Revision: https://reviews.llvm.org/D41533 llvm-svn: 322209
This commit is contained in:
parent
90d96aa107
commit
4c3ea8029e
|
@ -17,23 +17,23 @@ class TestBreakpointInGlobalConstructors(TestBase):
|
|||
mydir = TestBase.compute_mydir(__file__)
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
def setUp(self):
|
||||
TestBase.setUp(self)
|
||||
def test(self):
|
||||
self.build()
|
||||
self.line_foo = line_number('foo.cpp', '// !BR_foo')
|
||||
self.line_main = line_number('main.cpp', '// !BR_main')
|
||||
|
||||
@expectedFailureAll(bugnumber="llvm.org/pr35480", oslist=["linux"])
|
||||
def test(self):
|
||||
self.build()
|
||||
exe = os.path.join(os.getcwd(), "a.out")
|
||||
self.runCmd("file %s" % exe)
|
||||
target = self.dbg.CreateTarget("a.out")
|
||||
self.assertTrue(target, VALID_TARGET)
|
||||
|
||||
env= self.registerSharedLibrariesWithTarget(target, ["foo"])
|
||||
|
||||
bp_main = lldbutil.run_break_set_by_file_and_line(
|
||||
self, 'main.cpp', self.line_main)
|
||||
bp_foo = lldbutil.run_break_set_by_file_and_line(
|
||||
self, 'foo.cpp', self.line_foo)
|
||||
|
||||
self.runCmd("run")
|
||||
process = target.LaunchSimple(
|
||||
None, env, self.get_process_working_directory())
|
||||
|
||||
self.assertIsNotNone(
|
||||
lldbutil.get_one_thread_stopped_at_breakpoint_id(
|
||||
|
|
|
@ -368,7 +368,6 @@ class LoadUnloadTestCase(TestBase):
|
|||
|
||||
@skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
|
||||
@skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
|
||||
@unittest2.expectedFailure("llvm.org/pr25806")
|
||||
def test_static_init_during_load(self):
|
||||
"""Test that we can set breakpoints correctly in static initializers"""
|
||||
|
||||
|
@ -392,16 +391,6 @@ class LoadUnloadTestCase(TestBase):
|
|||
'd_init',
|
||||
'stop reason = breakpoint %d' % d_init_bp_num])
|
||||
|
||||
self.runCmd("continue")
|
||||
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
|
||||
substrs=['stopped',
|
||||
'a_init',
|
||||
'stop reason = breakpoint %d' % a_init_bp_num])
|
||||
self.expect("thread backtrace",
|
||||
substrs=['a_init',
|
||||
'dlopen',
|
||||
'main'])
|
||||
|
||||
self.runCmd("continue")
|
||||
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
|
||||
substrs=['stopped',
|
||||
|
@ -411,3 +400,13 @@ class LoadUnloadTestCase(TestBase):
|
|||
substrs=['b_init',
|
||||
'dlopen',
|
||||
'main'])
|
||||
|
||||
self.runCmd("continue")
|
||||
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
|
||||
substrs=['stopped',
|
||||
'a_init',
|
||||
'stop reason = breakpoint %d' % a_init_bp_num])
|
||||
self.expect("thread backtrace",
|
||||
substrs=['a_init',
|
||||
'dlopen',
|
||||
'main'])
|
||||
|
|
|
@ -79,7 +79,8 @@ DynamicLoaderPOSIXDYLD::DynamicLoaderPOSIXDYLD(Process *process)
|
|||
: DynamicLoader(process), m_rendezvous(process),
|
||||
m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS),
|
||||
m_auxv(), m_dyld_bid(LLDB_INVALID_BREAK_ID),
|
||||
m_vdso_base(LLDB_INVALID_ADDRESS) {}
|
||||
m_vdso_base(LLDB_INVALID_ADDRESS),
|
||||
m_interpreter_base(LLDB_INVALID_ADDRESS) {}
|
||||
|
||||
DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() {
|
||||
if (m_dyld_bid != LLDB_INVALID_BREAK_ID) {
|
||||
|
@ -117,7 +118,7 @@ void DynamicLoaderPOSIXDYLD::DidAttach() {
|
|||
: "<null executable>",
|
||||
load_offset);
|
||||
|
||||
EvalVdsoStatus();
|
||||
EvalSpecialModulesStatus();
|
||||
|
||||
// if we dont have a load address we cant re-base
|
||||
bool rebase_exec = (load_offset == LLDB_INVALID_ADDRESS) ? false : true;
|
||||
|
@ -207,7 +208,7 @@ void DynamicLoaderPOSIXDYLD::DidLaunch() {
|
|||
|
||||
executable = GetTargetExecutable();
|
||||
load_offset = ComputeLoadOffset();
|
||||
EvalVdsoStatus();
|
||||
EvalSpecialModulesStatus();
|
||||
|
||||
if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) {
|
||||
ModuleList module_list;
|
||||
|
@ -217,7 +218,12 @@ void DynamicLoaderPOSIXDYLD::DidLaunch() {
|
|||
if (log)
|
||||
log->Printf("DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()",
|
||||
__FUNCTION__);
|
||||
|
||||
if (!SetRendezvousBreakpoint()) {
|
||||
// If we cannot establish rendezvous breakpoint right now
|
||||
// we'll try again at entry point.
|
||||
ProbeEntry();
|
||||
}
|
||||
|
||||
m_process->GetTarget().ModulesDidLoad(module_list);
|
||||
}
|
||||
|
@ -329,38 +335,77 @@ bool DynamicLoaderPOSIXDYLD::EntryBreakpointHit(
|
|||
return false; // Continue running.
|
||||
}
|
||||
|
||||
void DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() {
|
||||
bool DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() {
|
||||
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
|
||||
if (m_dyld_bid != LLDB_INVALID_BREAK_ID) {
|
||||
LLDB_LOG(log,
|
||||
"Rendezvous breakpoint breakpoint id {0} for pid {1}"
|
||||
"is already set.",
|
||||
m_dyld_bid,
|
||||
m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
|
||||
return true;
|
||||
}
|
||||
|
||||
addr_t break_addr = m_rendezvous.GetBreakAddress();
|
||||
addr_t break_addr;
|
||||
Target &target = m_process->GetTarget();
|
||||
|
||||
if (m_dyld_bid == LLDB_INVALID_BREAK_ID) {
|
||||
if (log)
|
||||
log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64
|
||||
" setting rendezvous break address at 0x%" PRIx64,
|
||||
__FUNCTION__,
|
||||
BreakpointSP dyld_break;
|
||||
if (m_rendezvous.IsValid()) {
|
||||
break_addr = m_rendezvous.GetBreakAddress();
|
||||
LLDB_LOG(log, "Setting rendezvous break address for pid {0} at {1:x}",
|
||||
m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID,
|
||||
break_addr);
|
||||
Breakpoint *dyld_break =
|
||||
target.CreateBreakpoint(break_addr, true, false).get();
|
||||
dyld_break = target.CreateBreakpoint(break_addr, true, false);
|
||||
} else {
|
||||
LLDB_LOG(log, "Rendezvous structure is not set up yet. "
|
||||
"Trying to locate rendezvous breakpoint in the interpreter "
|
||||
"by symbol name.");
|
||||
ModuleSP interpreter = LoadInterpreterModule();
|
||||
if (!interpreter) {
|
||||
LLDB_LOG(log, "Can't find interpreter, rendezvous breakpoint isn't set.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function names from different dynamic loaders that are known
|
||||
// to be used as rendezvous between the loader and debuggers.
|
||||
static std::vector<std::string> DebugStateCandidates{
|
||||
"_dl_debug_state", "rtld_db_dlactivity", "__dl_rtld_db_dlactivity",
|
||||
"r_debug_state", "_r_debug_state", "_rtld_debug_state",
|
||||
};
|
||||
|
||||
FileSpecList containingModules;
|
||||
containingModules.Append(interpreter->GetFileSpec());
|
||||
dyld_break = target.CreateBreakpoint(
|
||||
&containingModules, nullptr /* containingSourceFiles */,
|
||||
DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC,
|
||||
0, /* offset */
|
||||
eLazyBoolNo, /* skip_prologue */
|
||||
true, /* internal */
|
||||
false /* request_hardware */);
|
||||
}
|
||||
|
||||
if (dyld_break->GetNumResolvedLocations() != 1) {
|
||||
LLDB_LOG(
|
||||
log,
|
||||
"Rendezvous breakpoint has abnormal number of"
|
||||
" resolved locations ({0}) in pid {1}. It's supposed to be exactly 1.",
|
||||
dyld_break->GetNumResolvedLocations(),
|
||||
m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
|
||||
|
||||
target.RemoveBreakpointByID(dyld_break->GetID());
|
||||
return false;
|
||||
}
|
||||
|
||||
BreakpointLocationSP location = dyld_break->GetLocationAtIndex(0);
|
||||
LLDB_LOG(log,
|
||||
"Successfully set rendezvous breakpoint at address {0:x} "
|
||||
"for pid {1}",
|
||||
location->GetLoadAddress(),
|
||||
m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
|
||||
|
||||
dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
|
||||
dyld_break->SetBreakpointKind("shared-library-event");
|
||||
m_dyld_bid = dyld_break->GetID();
|
||||
} else {
|
||||
if (log)
|
||||
log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64
|
||||
" reusing break id %" PRIu32 ", address at 0x%" PRIx64,
|
||||
__FUNCTION__,
|
||||
m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID,
|
||||
m_dyld_bid, break_addr);
|
||||
}
|
||||
|
||||
// Make sure our breakpoint is at the right address.
|
||||
assert(target.GetBreakpointByID(m_dyld_bid)
|
||||
->FindLocationByAddress(break_addr)
|
||||
->GetBreakpoint()
|
||||
.GetID() == m_dyld_bid);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(
|
||||
|
@ -485,7 +530,7 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread,
|
|||
return thread_plan_sp;
|
||||
}
|
||||
|
||||
void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) {
|
||||
void DynamicLoaderPOSIXDYLD::LoadVDSO() {
|
||||
if (m_vdso_base == LLDB_INVALID_ADDRESS)
|
||||
return;
|
||||
|
||||
|
@ -506,13 +551,38 @@ void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) {
|
|||
}
|
||||
}
|
||||
|
||||
ModuleSP DynamicLoaderPOSIXDYLD::LoadInterpreterModule() {
|
||||
if (m_interpreter_base == LLDB_INVALID_ADDRESS)
|
||||
return nullptr;
|
||||
|
||||
MemoryRegionInfo info;
|
||||
Target &target = m_process->GetTarget();
|
||||
Status status = m_process->GetMemoryRegionInfo(m_interpreter_base, info);
|
||||
if (status.Fail() || info.GetMapped() != MemoryRegionInfo::eYes ||
|
||||
info.GetName().IsEmpty()) {
|
||||
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
|
||||
LLDB_LOG(log, "Failed to get interpreter region info: {0}", status);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSpec file(info.GetName().GetCString(), false);
|
||||
ModuleSpec module_spec(file, target.GetArchitecture());
|
||||
|
||||
if (ModuleSP module_sp = target.GetSharedModule(module_spec)) {
|
||||
UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_interpreter_base,
|
||||
false);
|
||||
return module_sp;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
|
||||
DYLDRendezvous::iterator I;
|
||||
DYLDRendezvous::iterator E;
|
||||
ModuleList module_list;
|
||||
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
|
||||
|
||||
if (!m_rendezvous.Resolve()) {
|
||||
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
|
||||
if (log)
|
||||
log->Printf("DynamicLoaderPOSIXDYLD::%s unable to resolve POSIX DYLD "
|
||||
"rendezvous address",
|
||||
|
@ -524,7 +594,7 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
|
|||
// that ourselves here.
|
||||
ModuleSP executable = GetTargetExecutable();
|
||||
m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
|
||||
LoadVDSO(module_list);
|
||||
LoadVDSO();
|
||||
|
||||
std::vector<FileSpec> module_names;
|
||||
for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
|
||||
|
@ -536,6 +606,8 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
|
|||
ModuleSP module_sp =
|
||||
LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true);
|
||||
if (module_sp.get()) {
|
||||
LLDB_LOG(log, "LoadAllCurrentModules loading module: {0}",
|
||||
I->file_spec.GetFilename());
|
||||
module_list.Append(module_sp);
|
||||
} else {
|
||||
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
|
||||
|
@ -575,11 +647,14 @@ addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() {
|
|||
return m_load_offset;
|
||||
}
|
||||
|
||||
void DynamicLoaderPOSIXDYLD::EvalVdsoStatus() {
|
||||
AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AUXV_AT_SYSINFO_EHDR);
|
||||
|
||||
if (I != m_auxv->end())
|
||||
void DynamicLoaderPOSIXDYLD::EvalSpecialModulesStatus() {
|
||||
auto I = m_auxv->FindEntry(AuxVector::AUXV_AT_SYSINFO_EHDR);
|
||||
if (I != m_auxv->end() && I->value != 0)
|
||||
m_vdso_base = I->value;
|
||||
|
||||
I = m_auxv->FindEntry(AuxVector::AUXV_AT_BASE);
|
||||
if (I != m_auxv->end() && I->value != 0)
|
||||
m_interpreter_base = I->value;
|
||||
}
|
||||
|
||||
addr_t DynamicLoaderPOSIXDYLD::GetEntryPoint() {
|
||||
|
|
|
@ -85,13 +85,17 @@ protected:
|
|||
/// mapped to the address space
|
||||
lldb::addr_t m_vdso_base;
|
||||
|
||||
/// Contains AT_BASE, which means a dynamic loader has been
|
||||
/// mapped to the address space
|
||||
lldb::addr_t m_interpreter_base;
|
||||
|
||||
/// Loaded module list. (link map for each module)
|
||||
std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>>
|
||||
m_loaded_modules;
|
||||
|
||||
/// Enables a breakpoint on a function called by the runtime
|
||||
/// If possible sets a breakpoint on a function called by the runtime
|
||||
/// linker each time a module is loaded or unloaded.
|
||||
virtual void SetRendezvousBreakpoint();
|
||||
bool SetRendezvousBreakpoint();
|
||||
|
||||
/// Callback routine which updates the current list of loaded modules based
|
||||
/// on the information supplied by the runtime linker.
|
||||
|
@ -138,7 +142,11 @@ protected:
|
|||
/// of all dependent modules.
|
||||
virtual void LoadAllCurrentModules();
|
||||
|
||||
void LoadVDSO(lldb_private::ModuleList &modules);
|
||||
void LoadVDSO();
|
||||
|
||||
// Loading an interpreter module (if present) assumming m_interpreter_base
|
||||
// already points to its base address.
|
||||
lldb::ModuleSP LoadInterpreterModule();
|
||||
|
||||
/// Computes a value for m_load_offset returning the computed address on
|
||||
/// success and LLDB_INVALID_ADDRESS on failure.
|
||||
|
@ -148,9 +156,10 @@ protected:
|
|||
/// success and LLDB_INVALID_ADDRESS on failure.
|
||||
lldb::addr_t GetEntryPoint();
|
||||
|
||||
/// Evaluate if Aux vectors contain vDSO information
|
||||
/// Evaluate if Aux vectors contain vDSO and LD information
|
||||
/// in case they do, read and assign the address to m_vdso_base
|
||||
void EvalVdsoStatus();
|
||||
/// and m_interpreter_base.
|
||||
void EvalSpecialModulesStatus();
|
||||
|
||||
/// Loads Module from inferior process.
|
||||
void ResolveExecutableModule(lldb::ModuleSP &module_sp);
|
||||
|
|
Loading…
Reference in New Issue