forked from OSchip/llvm-project
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