Skip to content

Commit

Permalink
Add absolute load address support for the DynamicLoader plugins
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Tamas Berghammer committed Aug 24, 2015
1 parent 71ad47f commit 42ecef3
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 74 deletions.
13 changes: 9 additions & 4 deletions lldb/include/lldb/Target/DynamicLoader.h
Expand Up @@ -263,12 +263,14 @@ class DynamicLoader :
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.
///
Expand All @@ -282,8 +284,11 @@ class DynamicLoader :

/// 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;
Expand Down
46 changes: 27 additions & 19 deletions lldb/source/Core/DynamicLoader.cpp
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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();
Expand All @@ -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);
}
}
Expand Down
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand All @@ -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;
Expand Down
Expand Up @@ -124,7 +124,8 @@ class DynamicLoaderHexagonDYLD : public lldb_private::DynamicLoader
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.
///
Expand All @@ -135,7 +136,10 @@ class DynamicLoaderHexagonDYLD : public lldb_private::DynamicLoader
/// 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.
///
Expand Down
Expand Up @@ -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
Expand Down Expand Up @@ -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__);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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())
{
Expand Down Expand Up @@ -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);
Expand Down
Expand Up @@ -103,7 +103,7 @@ class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader

/// 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
Expand All @@ -126,16 +126,17 @@ class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader
/// @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.
Expand All @@ -155,7 +156,7 @@ class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader

/// 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
Expand Down
64 changes: 38 additions & 26 deletions lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
Expand Up @@ -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;

if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, load_addr))
++num_loaded_sections;
}
const elf::ELFProgramHeader* header = GetProgramHeaderByIndex(i);
if (header == nullptr)
continue;

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
Expand Down

0 comments on commit 42ecef3

Please sign in to comment.