Add absolute load address support for the DynamicLoader plugins
The POSIX linker generally reports the load bias for the loaded libraries but in some case it is useful to handle a library based on absolute load address. Example usecases: * Windows linker uses absolute addresses * Library list came from different source (e.g. /proc/<pid>/maps) Differential revision: http://reviews.llvm.org/D12233 llvm-svn: 245834
This commit is contained in:
parent
71ad47f81f
commit
42ecef3b15
|
@ -263,12 +263,14 @@ protected:
|
|||
virtual void
|
||||
UpdateLoadedSections(lldb::ModuleSP module,
|
||||
lldb::addr_t link_map_addr,
|
||||
lldb::addr_t base_addr);
|
||||
lldb::addr_t base_addr,
|
||||
bool base_addr_is_offset);
|
||||
|
||||
// Utility method so base classes can share implementation of UpdateLoadedSections
|
||||
void
|
||||
UpdateLoadedSectionsCommon(lldb::ModuleSP module,
|
||||
lldb::addr_t base_addr);
|
||||
lldb::addr_t base_addr,
|
||||
bool base_addr_is_offset);
|
||||
|
||||
/// Removes the loaded sections from the target in @p module.
|
||||
///
|
||||
|
@ -282,8 +284,11 @@ protected:
|
|||
|
||||
/// Locates or creates a module given by @p file and updates/loads the
|
||||
/// resulting module at the virtual base address @p base_addr.
|
||||
lldb::ModuleSP
|
||||
LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t link_map_addr, lldb::addr_t base_addr);
|
||||
virtual lldb::ModuleSP
|
||||
LoadModuleAtAddress(const lldb_private::FileSpec &file,
|
||||
lldb::addr_t link_map_addr,
|
||||
lldb::addr_t base_addr,
|
||||
bool base_addr_is_offset);
|
||||
|
||||
const lldb_private::SectionList *
|
||||
GetSectionListFromModule(const lldb::ModuleSP module) const;
|
||||
|
|
|
@ -119,16 +119,20 @@ DynamicLoader::GetTargetExecutable()
|
|||
}
|
||||
|
||||
void
|
||||
DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr)
|
||||
DynamicLoader::UpdateLoadedSections(ModuleSP module,
|
||||
addr_t link_map_addr,
|
||||
addr_t base_addr,
|
||||
bool base_addr_is_offset)
|
||||
{
|
||||
UpdateLoadedSectionsCommon(module, base_addr);
|
||||
UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset);
|
||||
}
|
||||
|
||||
void
|
||||
DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module, addr_t base_addr)
|
||||
DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module,
|
||||
addr_t base_addr,
|
||||
bool base_addr_is_offset)
|
||||
{
|
||||
bool changed;
|
||||
const bool base_addr_is_offset = true;
|
||||
module->SetLoadAddress(m_process->GetTarget(), base_addr, base_addr_is_offset, changed);
|
||||
}
|
||||
|
||||
|
@ -171,7 +175,10 @@ DynamicLoader::GetSectionListFromModule(const ModuleSP module) const
|
|||
}
|
||||
|
||||
ModuleSP
|
||||
DynamicLoader::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr)
|
||||
DynamicLoader::LoadModuleAtAddress(const FileSpec &file,
|
||||
addr_t link_map_addr,
|
||||
addr_t base_addr,
|
||||
bool base_addr_is_offset)
|
||||
{
|
||||
Target &target = m_process->GetTarget();
|
||||
ModuleList &modules = target.GetImages();
|
||||
|
@ -180,27 +187,28 @@ DynamicLoader::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, a
|
|||
ModuleSpec module_spec (file, target.GetArchitecture());
|
||||
if ((module_sp = modules.FindFirstModule (module_spec)))
|
||||
{
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr);
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr, base_addr_is_offset);
|
||||
}
|
||||
else if ((module_sp = target.GetSharedModule(module_spec)))
|
||||
{
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr);
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr, base_addr_is_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to fetch the load address of the file from the process. It can be different from the
|
||||
// address reported by the linker in case of a file with fixed load address because the
|
||||
// linker reports the bias between the load address specified in the file and the actual
|
||||
// load address it loaded the file.
|
||||
bool is_loaded;
|
||||
lldb::addr_t load_addr;
|
||||
Error error = m_process->GetFileLoadAddress(file, is_loaded, load_addr);
|
||||
if (error.Fail() || !is_loaded)
|
||||
load_addr = base_addr;
|
||||
|
||||
if ((module_sp = m_process->ReadModuleFromMemory(file, load_addr)))
|
||||
if (base_addr_is_offset)
|
||||
{
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr);
|
||||
// Try to fetch the load address of the file from the process as we need absolute load
|
||||
// address to read the file out of the memory instead of a load bias.
|
||||
bool is_loaded;
|
||||
lldb::addr_t load_addr;
|
||||
Error error = m_process->GetFileLoadAddress(file, is_loaded, load_addr);
|
||||
if (error.Success() && is_loaded)
|
||||
base_addr = load_addr;
|
||||
}
|
||||
|
||||
if ((module_sp = m_process->ReadModuleFromMemory(file, base_addr)))
|
||||
{
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr, false);
|
||||
target.GetImages().AppendIfNeeded(module_sp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ DynamicLoaderHexagonDYLD::DidAttach()
|
|||
|
||||
// Map the loaded sections of this executable
|
||||
if ( load_offset != LLDB_INVALID_ADDRESS )
|
||||
UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset);
|
||||
UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset, true);
|
||||
|
||||
// AD: confirm this?
|
||||
// Load into LLDB all of the currently loaded executables in the stub
|
||||
|
@ -268,7 +268,10 @@ DynamicLoaderHexagonDYLD::CanLoadImage()
|
|||
}
|
||||
|
||||
void
|
||||
DynamicLoaderHexagonDYLD::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr)
|
||||
DynamicLoaderHexagonDYLD::UpdateLoadedSections(ModuleSP module,
|
||||
addr_t link_map_addr,
|
||||
addr_t base_addr,
|
||||
bool base_addr_is_offset)
|
||||
{
|
||||
Target &target = m_process->GetTarget();
|
||||
const SectionList *sections = GetSectionListFromModule(module);
|
||||
|
@ -442,7 +445,7 @@ DynamicLoaderHexagonDYLD::RefreshModules()
|
|||
for (I = m_rendezvous.loaded_begin(); I != E; ++I)
|
||||
{
|
||||
FileSpec file(I->path.c_str(), true);
|
||||
ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr);
|
||||
ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr, true);
|
||||
if (module_sp.get())
|
||||
{
|
||||
loaded_modules.AppendIfNeeded( module_sp );
|
||||
|
@ -571,7 +574,7 @@ DynamicLoaderHexagonDYLD::LoadAllCurrentModules()
|
|||
{
|
||||
const char *module_path = I->path.c_str();
|
||||
FileSpec file(module_path, false);
|
||||
ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr);
|
||||
ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr, true);
|
||||
if (module_sp.get())
|
||||
{
|
||||
module_list.Append(module_sp);
|
||||
|
@ -591,7 +594,10 @@ DynamicLoaderHexagonDYLD::LoadAllCurrentModules()
|
|||
/// Helper for the entry breakpoint callback. Resolves the load addresses
|
||||
/// of all dependent modules.
|
||||
ModuleSP
|
||||
DynamicLoaderHexagonDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr)
|
||||
DynamicLoaderHexagonDYLD::LoadModuleAtAddress(const FileSpec &file,
|
||||
addr_t link_map_addr,
|
||||
addr_t base_addr,
|
||||
bool base_addr_is_offset)
|
||||
{
|
||||
Target &target = m_process->GetTarget();
|
||||
ModuleList &modules = target.GetImages();
|
||||
|
@ -602,12 +608,12 @@ DynamicLoaderHexagonDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t link_
|
|||
// check if module is currently loaded
|
||||
if ((module_sp = modules.FindFirstModule (module_spec)))
|
||||
{
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr);
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr, true);
|
||||
}
|
||||
// try to load this module from disk
|
||||
else if ((module_sp = target.GetSharedModule(module_spec)))
|
||||
{
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr);
|
||||
UpdateLoadedSections(module_sp, link_map_addr, base_addr, true);
|
||||
}
|
||||
|
||||
return module_sp;
|
||||
|
|
|
@ -124,7 +124,8 @@ protected:
|
|||
void
|
||||
UpdateLoadedSections(lldb::ModuleSP module,
|
||||
lldb::addr_t link_map_addr,
|
||||
lldb::addr_t base_addr);
|
||||
lldb::addr_t base_addr,
|
||||
bool base_addr_is_offset) override;
|
||||
|
||||
/// Removes the loaded sections from the target in @p module.
|
||||
///
|
||||
|
@ -135,7 +136,10 @@ protected:
|
|||
/// Locates or creates a module given by @p file and updates/loads the
|
||||
/// resulting module at the virtual base address @p base_addr.
|
||||
lldb::ModuleSP
|
||||
LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t link_map_addr, lldb::addr_t base_addr);
|
||||
LoadModuleAtAddress(const lldb_private::FileSpec &file,
|
||||
lldb::addr_t link_map_addr,
|
||||
lldb::addr_t base_addr,
|
||||
bool base_addr_is_offset) override;
|
||||
|
||||
/// Callback routine invoked when we hit the breakpoint on process entry.
|
||||
///
|
||||
|
|
|
@ -165,7 +165,7 @@ DynamicLoaderPOSIXDYLD::DidAttach()
|
|||
m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID,
|
||||
executable_sp->GetFileSpec().GetPath().c_str ());
|
||||
|
||||
UpdateLoadedSections(executable_sp, LLDB_INVALID_ADDRESS, load_offset);
|
||||
UpdateLoadedSections(executable_sp, LLDB_INVALID_ADDRESS, load_offset, true);
|
||||
|
||||
// When attaching to a target, there are two possible states:
|
||||
// (1) We already crossed the entry point and therefore the rendezvous
|
||||
|
@ -223,7 +223,7 @@ DynamicLoaderPOSIXDYLD::DidLaunch()
|
|||
{
|
||||
ModuleList module_list;
|
||||
module_list.Append(executable);
|
||||
UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset);
|
||||
UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset, true);
|
||||
|
||||
if (log)
|
||||
log->Printf ("DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()", __FUNCTION__);
|
||||
|
@ -252,11 +252,13 @@ DynamicLoaderPOSIXDYLD::CanLoadImage()
|
|||
}
|
||||
|
||||
void
|
||||
DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr)
|
||||
DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module,
|
||||
addr_t link_map_addr,
|
||||
addr_t base_addr,
|
||||
bool base_addr_is_offset)
|
||||
{
|
||||
m_loaded_modules[module] = link_map_addr;
|
||||
|
||||
UpdateLoadedSectionsCommon(module, base_addr);
|
||||
UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -414,7 +416,7 @@ DynamicLoaderPOSIXDYLD::RefreshModules()
|
|||
E = m_rendezvous.loaded_end();
|
||||
for (I = m_rendezvous.loaded_begin(); I != E; ++I)
|
||||
{
|
||||
ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr);
|
||||
ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true);
|
||||
if (module_sp.get())
|
||||
{
|
||||
loaded_modules.AppendIfNeeded(module_sp);
|
||||
|
@ -432,8 +434,7 @@ DynamicLoaderPOSIXDYLD::RefreshModules()
|
|||
for (I = m_rendezvous.unloaded_begin(); I != E; ++I)
|
||||
{
|
||||
ModuleSpec module_spec{I->file_spec};
|
||||
ModuleSP module_sp =
|
||||
loaded_modules.FindFirstModule (module_spec);
|
||||
ModuleSP module_sp = loaded_modules.FindFirstModule (module_spec);
|
||||
|
||||
if (module_sp.get())
|
||||
{
|
||||
|
@ -520,10 +521,9 @@ DynamicLoaderPOSIXDYLD::LoadAllCurrentModules()
|
|||
ModuleSP executable = GetTargetExecutable();
|
||||
m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
|
||||
|
||||
|
||||
for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
|
||||
{
|
||||
ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr);
|
||||
ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true);
|
||||
if (module_sp.get())
|
||||
{
|
||||
module_list.Append(module_sp);
|
||||
|
|
|
@ -103,7 +103,7 @@ protected:
|
|||
|
||||
/// Enables a breakpoint on a function called by the runtime
|
||||
/// linker each time a module is loaded or unloaded.
|
||||
void
|
||||
virtual void
|
||||
SetRendezvousBreakpoint();
|
||||
|
||||
/// Callback routine which updates the current list of loaded modules based
|
||||
|
@ -126,16 +126,17 @@ protected:
|
|||
/// @param link_map_addr The virtual address of the link map for the @p module.
|
||||
///
|
||||
/// @param base_addr The virtual base address @p module is loaded at.
|
||||
virtual void
|
||||
void
|
||||
UpdateLoadedSections(lldb::ModuleSP module,
|
||||
lldb::addr_t link_map_addr,
|
||||
lldb::addr_t base_addr);
|
||||
lldb::addr_t base_addr,
|
||||
bool base_addr_is_offset) override;
|
||||
|
||||
/// Removes the loaded sections from the target in @p module.
|
||||
///
|
||||
/// @param module The module to traverse.
|
||||
virtual void
|
||||
UnloadSections(const lldb::ModuleSP module);
|
||||
void
|
||||
UnloadSections(const lldb::ModuleSP module) override;
|
||||
|
||||
/// Resolves the entry point for the current inferior process and sets a
|
||||
/// breakpoint at that address.
|
||||
|
@ -155,7 +156,7 @@ protected:
|
|||
|
||||
/// Helper for the entry breakpoint callback. Resolves the load addresses
|
||||
/// of all dependent modules.
|
||||
void
|
||||
virtual void
|
||||
LoadAllCurrentModules();
|
||||
|
||||
/// Computes a value for m_load_offset returning the computed address on
|
||||
|
|
|
@ -847,40 +847,52 @@ ObjectFileELF::SetLoadAddress (Target &target,
|
|||
SectionList *section_list = GetSectionList ();
|
||||
if (section_list)
|
||||
{
|
||||
if (value_is_offset)
|
||||
if (!value_is_offset)
|
||||
{
|
||||
const size_t num_sections = section_list->GetSize();
|
||||
size_t sect_idx = 0;
|
||||
|
||||
for (sect_idx = 0; sect_idx < num_sections; ++sect_idx)
|
||||
bool found_offset = false;
|
||||
for (size_t i = 0, count = GetProgramHeaderCount(); i < count; ++i)
|
||||
{
|
||||
// Iterate through the object file sections to find all
|
||||
// of the sections that have SHF_ALLOC in their flag bits.
|
||||
SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
|
||||
// if (section_sp && !section_sp->IsThreadSpecific())
|
||||
if (section_sp && section_sp->Test(SHF_ALLOC))
|
||||
{
|
||||
lldb::addr_t load_addr = section_sp->GetFileAddress() + value;
|
||||
|
||||
// On 32-bit systems the load address have to fit into 4 bytes. The rest of
|
||||
// the bytes are the overflow from the addition.
|
||||
if (GetAddressByteSize() == 4)
|
||||
load_addr &= 0xFFFFFFFF;
|
||||
const elf::ELFProgramHeader* header = GetProgramHeaderByIndex(i);
|
||||
if (header == nullptr)
|
||||
continue;
|
||||
|
||||
if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, load_addr))
|
||||
++num_loaded_sections;
|
||||
}
|
||||
if (header->p_type != PT_LOAD || header->p_offset != 0)
|
||||
continue;
|
||||
|
||||
value = value - header->p_vaddr;
|
||||
found_offset = true;
|
||||
break;
|
||||
}
|
||||
return num_loaded_sections > 0;
|
||||
if (!found_offset)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
const size_t num_sections = section_list->GetSize();
|
||||
size_t sect_idx = 0;
|
||||
|
||||
for (sect_idx = 0; sect_idx < num_sections; ++sect_idx)
|
||||
{
|
||||
// Not sure how to slide an ELF file given the base address
|
||||
// of the ELF file in memory
|
||||
// Iterate through the object file sections to find all
|
||||
// of the sections that have SHF_ALLOC in their flag bits.
|
||||
SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
|
||||
// if (section_sp && !section_sp->IsThreadSpecific())
|
||||
if (section_sp && section_sp->Test(SHF_ALLOC))
|
||||
{
|
||||
lldb::addr_t load_addr = section_sp->GetFileAddress() + value;
|
||||
|
||||
// On 32-bit systems the load address have to fit into 4 bytes. The rest of
|
||||
// the bytes are the overflow from the addition.
|
||||
if (GetAddressByteSize() == 4)
|
||||
load_addr &= 0xFFFFFFFF;
|
||||
|
||||
if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, load_addr))
|
||||
++num_loaded_sections;
|
||||
}
|
||||
}
|
||||
return num_loaded_sections > 0;
|
||||
}
|
||||
}
|
||||
return false; // If it changed
|
||||
return false;
|
||||
}
|
||||
|
||||
ByteOrder
|
||||
|
|
Loading…
Reference in New Issue