Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,10 @@
add_lldb_library(lldbPluginDynamicLoaderHexagonDYLD PLUGIN
HexagonDYLDRendezvous.cpp
DynamicLoaderHexagonDYLD.cpp
LINK_LIBS
lldbBreakpoint
lldbCore
lldbSymbol
lldbTarget
)

View File

@@ -0,0 +1,147 @@
//===-- DynamicLoaderHexagonDYLD.h ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_DynamicLoaderHexagonDYLD_h_
#define liblldb_DynamicLoaderHexagonDYLD_h_
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Target/DynamicLoader.h"
#include "HexagonDYLDRendezvous.h"
class DynamicLoaderHexagonDYLD : public lldb_private::DynamicLoader {
public:
DynamicLoaderHexagonDYLD(lldb_private::Process *process);
~DynamicLoaderHexagonDYLD() override;
static void Initialize();
static void Terminate();
static lldb_private::ConstString GetPluginNameStatic();
static const char *GetPluginDescriptionStatic();
static lldb_private::DynamicLoader *
CreateInstance(lldb_private::Process *process, bool force);
//------------------------------------------------------------------
// DynamicLoader protocol
//------------------------------------------------------------------
void DidAttach() override;
void DidLaunch() override;
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
bool stop_others) override;
lldb_private::Status CanLoadImage() override;
lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module,
const lldb::ThreadSP thread,
lldb::addr_t tls_file_addr) override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private::ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
protected:
/// Runtime linker rendezvous structure.
HexagonDYLDRendezvous m_rendezvous;
/// Virtual load address of the inferior process.
lldb::addr_t m_load_offset;
/// Virtual entry address of the inferior process.
lldb::addr_t m_entry_point;
/// Rendezvous breakpoint.
lldb::break_id_t m_dyld_bid;
/// 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
/// linker each time a module is loaded or unloaded.
bool SetRendezvousBreakpoint();
/// Callback routine which updates the current list of loaded modules based
/// on the information supplied by the runtime linker.
static bool RendezvousBreakpointHit(
void *baton, lldb_private::StoppointCallbackContext *context,
lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
/// Helper method for RendezvousBreakpointHit. Updates LLDB's current set
/// of loaded modules.
void RefreshModules();
/// Updates the load address of every allocatable section in @p module.
///
/// @param module The module to traverse.
///
/// @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.
void UpdateLoadedSections(lldb::ModuleSP module, lldb::addr_t link_map_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.
void UnloadSections(const lldb::ModuleSP module) override;
/// Callback routine invoked when we hit the breakpoint on process entry.
///
/// This routine is responsible for resolving the load addresses of all
/// dependent modules required by the inferior and setting up the rendezvous
/// breakpoint.
static bool
EntryBreakpointHit(void *baton,
lldb_private::StoppointCallbackContext *context,
lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
/// Helper for the entry breakpoint callback. Resolves the load addresses
/// of all dependent modules.
void LoadAllCurrentModules();
/// Computes a value for m_load_offset returning the computed address on
/// success and LLDB_INVALID_ADDRESS on failure.
lldb::addr_t ComputeLoadOffset();
/// Computes a value for m_entry_point returning the computed address on
/// success and LLDB_INVALID_ADDRESS on failure.
lldb::addr_t GetEntryPoint();
/// Checks to see if the target module has changed, updates the target
/// accordingly and returns the target executable module.
lldb::ModuleSP GetTargetExecutable();
/// return the address of the Rendezvous breakpoint
lldb::addr_t FindRendezvousBreakpointAddress();
private:
const lldb_private::SectionList *
GetSectionListFromModule(const lldb::ModuleSP module) const;
DISALLOW_COPY_AND_ASSIGN(DynamicLoaderHexagonDYLD);
};
#endif // liblldb_DynamicLoaderHexagonDYLD_h_

View File

@@ -0,0 +1,368 @@
//===-- HexagonDYLDRendezvous.cpp -------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "HexagonDYLDRendezvous.h"
using namespace lldb;
using namespace lldb_private;
/// Locates the address of the rendezvous structure. Returns the address on
/// success and LLDB_INVALID_ADDRESS on failure.
static addr_t ResolveRendezvousAddress(Process *process) {
addr_t info_location;
addr_t info_addr;
Status error;
info_location = process->GetImageInfoAddress();
if (info_location == LLDB_INVALID_ADDRESS)
return LLDB_INVALID_ADDRESS;
info_addr = process->ReadPointerFromMemory(info_location, error);
if (error.Fail())
return LLDB_INVALID_ADDRESS;
if (info_addr == 0)
return LLDB_INVALID_ADDRESS;
return info_addr;
}
HexagonDYLDRendezvous::HexagonDYLDRendezvous(Process *process)
: m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(),
m_previous(), m_soentries(), m_added_soentries(), m_removed_soentries() {
m_thread_info.valid = false;
// Cache a copy of the executable path
if (m_process) {
Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
if (exe_mod)
exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
}
}
bool HexagonDYLDRendezvous::Resolve() {
const size_t word_size = 4;
Rendezvous info;
size_t address_size;
size_t padding;
addr_t info_addr;
addr_t cursor;
address_size = m_process->GetAddressByteSize();
padding = address_size - word_size;
if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
cursor = info_addr = ResolveRendezvousAddress(m_process);
else
cursor = info_addr = m_rendezvous_addr;
if (cursor == LLDB_INVALID_ADDRESS)
return false;
if (!(cursor = ReadWord(cursor, &info.version, word_size)))
return false;
if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
return false;
if (!(cursor = ReadPointer(cursor, &info.brk)))
return false;
if (!(cursor = ReadWord(cursor, &info.state, word_size)))
return false;
if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
return false;
// The rendezvous was successfully read. Update our internal state.
m_rendezvous_addr = info_addr;
m_previous = m_current;
m_current = info;
return UpdateSOEntries();
}
void HexagonDYLDRendezvous::SetRendezvousAddress(lldb::addr_t addr) {
m_rendezvous_addr = addr;
}
bool HexagonDYLDRendezvous::IsValid() {
return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
}
bool HexagonDYLDRendezvous::UpdateSOEntries() {
SOEntry entry;
if (m_current.map_addr == 0)
return false;
// When the previous and current states are consistent this is the first
// time we have been asked to update. Just take a snapshot of the currently
// loaded modules.
if (m_previous.state == eConsistent && m_current.state == eConsistent)
return TakeSnapshot(m_soentries);
// If we are about to add or remove a shared object clear out the current
// state and take a snapshot of the currently loaded images.
if (m_current.state == eAdd || m_current.state == eDelete) {
// this is a fudge so that we can clear the assert below.
m_previous.state = eConsistent;
// We hit this assert on the 2nd run of this function after running the calc
// example
assert(m_previous.state == eConsistent);
m_soentries.clear();
m_added_soentries.clear();
m_removed_soentries.clear();
return TakeSnapshot(m_soentries);
}
assert(m_current.state == eConsistent);
// Otherwise check the previous state to determine what to expect and update
// accordingly.
if (m_previous.state == eAdd)
return UpdateSOEntriesForAddition();
else if (m_previous.state == eDelete)
return UpdateSOEntriesForDeletion();
return false;
}
bool HexagonDYLDRendezvous::UpdateSOEntriesForAddition() {
SOEntry entry;
iterator pos;
assert(m_previous.state == eAdd);
if (m_current.map_addr == 0)
return false;
for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
if (!ReadSOEntryFromMemory(cursor, entry))
return false;
// Only add shared libraries and not the executable.
// On Linux this is indicated by an empty path in the entry.
// On FreeBSD it is the name of the executable.
if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
continue;
pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
if (pos == m_soentries.end()) {
m_soentries.push_back(entry);
m_added_soentries.push_back(entry);
}
}
return true;
}
bool HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() {
SOEntryList entry_list;
iterator pos;
assert(m_previous.state == eDelete);
if (!TakeSnapshot(entry_list))
return false;
for (iterator I = begin(); I != end(); ++I) {
pos = std::find(entry_list.begin(), entry_list.end(), *I);
if (pos == entry_list.end())
m_removed_soentries.push_back(*I);
}
m_soentries = entry_list;
return true;
}
bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
SOEntry entry;
if (m_current.map_addr == 0)
return false;
for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
if (!ReadSOEntryFromMemory(cursor, entry))
return false;
// Only add shared libraries and not the executable.
// On Linux this is indicated by an empty path in the entry.
// On FreeBSD it is the name of the executable.
if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
continue;
entry_list.push_back(entry);
}
return true;
}
addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst,
size_t size) {
Status error;
*dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
if (error.Fail())
return 0;
return addr + size;
}
addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
Status error;
*dst = m_process->ReadPointerFromMemory(addr, error);
if (error.Fail())
return 0;
return addr + m_process->GetAddressByteSize();
}
std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) {
std::string str;
Status error;
size_t size;
char c;
if (addr == LLDB_INVALID_ADDRESS)
return std::string();
for (;;) {
size = m_process->DoReadMemory(addr, &c, 1, error);
if (size != 1 || error.Fail())
return std::string();
if (c == 0)
break;
else {
str.push_back(c);
addr++;
}
}
return str;
}
bool HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr,
SOEntry &entry) {
entry.clear();
entry.link_addr = addr;
if (!(addr = ReadPointer(addr, &entry.base_addr)))
return false;
if (!(addr = ReadPointer(addr, &entry.path_addr)))
return false;
if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
return false;
if (!(addr = ReadPointer(addr, &entry.next)))
return false;
if (!(addr = ReadPointer(addr, &entry.prev)))
return false;
entry.path = ReadStringFromMemory(entry.path_addr);
return true;
}
bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field,
uint32_t &value) {
Target &target = m_process->GetTarget();
SymbolContextList list;
if (!target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
eSymbolTypeAny, list))
return false;
Address address = list[0].symbol->GetAddress();
addr_t addr = address.GetLoadAddress(&target);
if (addr == LLDB_INVALID_ADDRESS)
return false;
Status error;
value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
if (error.Fail())
return false;
if (field == eSize)
value /= 8; // convert bits to bytes
return true;
}
const HexagonDYLDRendezvous::ThreadInfo &
HexagonDYLDRendezvous::GetThreadInfo() {
if (!m_thread_info.valid) {
bool ok = true;
ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
m_thread_info.dtv_offset);
ok &=
FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
m_thread_info.modid_offset);
ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
m_thread_info.tls_offset);
if (ok)
m_thread_info.valid = true;
}
return m_thread_info;
}
void HexagonDYLDRendezvous::DumpToLog(Log *log) const {
int state = GetState();
if (!log)
return;
log->PutCString("HexagonDYLDRendezvous:");
log->Printf(" Address: %" PRIx64, GetRendezvousAddress());
log->Printf(" Version: %" PRIu64, GetVersion());
log->Printf(" Link : %" PRIx64, GetLinkMapAddress());
log->Printf(" Break : %" PRIx64, GetBreakAddress());
log->Printf(" LDBase : %" PRIx64, GetLDBase());
log->Printf(" State : %s",
(state == eConsistent)
? "consistent"
: (state == eAdd) ? "add" : (state == eDelete) ? "delete"
: "unknown");
iterator I = begin();
iterator E = end();
if (I != E)
log->PutCString("HexagonDYLDRendezvous SOEntries:");
for (int i = 1; I != E; ++I, ++i) {
log->Printf("\n SOEntry [%d] %s", i, I->path.c_str());
log->Printf(" Base : %" PRIx64, I->base_addr);
log->Printf(" Path : %" PRIx64, I->path_addr);
log->Printf(" Dyn : %" PRIx64, I->dyn_addr);
log->Printf(" Next : %" PRIx64, I->next);
log->Printf(" Prev : %" PRIx64, I->prev);
}
}

View File

@@ -0,0 +1,247 @@
//===-- HexagonDYLDRendezvous.h ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_HexagonDYLDRendezvous_H_
#define liblldb_HexagonDYLDRendezvous_H_
// C Includes
// C++ Includes
#include <list>
#include <string>
// Other libraries and framework includes
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
namespace lldb_private {
class Process;
}
/// @class HexagonDYLDRendezvous
/// @brief Interface to the runtime linker.
///
/// A structure is present in a processes memory space which is updated by the
/// runtime liker each time a module is loaded or unloaded. This class provides
/// an interface to this structure and maintains a consistent snapshot of the
/// currently loaded modules.
class HexagonDYLDRendezvous {
// This structure is used to hold the contents of the debug rendezvous
// information (struct r_debug) as found in the inferiors memory. Note that
// the layout of this struct is not binary compatible, it is simply large
// enough to hold the information on both 32 and 64 bit platforms.
struct Rendezvous {
uint64_t version;
lldb::addr_t map_addr;
lldb::addr_t brk;
uint64_t state;
lldb::addr_t ldbase;
Rendezvous()
: version(0), map_addr(LLDB_INVALID_ADDRESS), brk(LLDB_INVALID_ADDRESS),
state(0), ldbase(0) {}
};
public:
// Various metadata supplied by the inferior's threading library to describe
// the per-thread state.
struct ThreadInfo {
bool valid; // whether we read valid metadata
uint32_t dtv_offset; // offset of DTV pointer within pthread
uint32_t dtv_slot_size; // size of one DTV slot
uint32_t modid_offset; // offset of module ID within link_map
uint32_t tls_offset; // offset of TLS pointer within DTV slot
};
HexagonDYLDRendezvous(lldb_private::Process *process);
/// Update the internal snapshot of runtime linker rendezvous and recompute
/// the currently loaded modules.
///
/// This method should be called once one start up, then once each time the
/// runtime linker enters the function given by GetBreakAddress().
///
/// @returns true on success and false on failure.
///
/// @see GetBreakAddress().
bool Resolve();
/// @returns true if this rendezvous has been located in the inferiors
/// address space and false otherwise.
bool IsValid();
/// @returns the address of the rendezvous structure in the inferiors
/// address space.
lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; }
/// Provide the dyld structure address
void SetRendezvousAddress(lldb::addr_t);
/// @returns the version of the rendezvous protocol being used.
uint64_t GetVersion() const { return m_current.version; }
/// @returns address in the inferiors address space containing the linked
/// list of shared object descriptors.
lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; }
/// A breakpoint should be set at this address and Resolve called on each
/// hit.
///
/// @returns the address of a function called by the runtime linker each
/// time a module is loaded/unloaded, or about to be loaded/unloaded.
///
/// @see Resolve()
lldb::addr_t GetBreakAddress() const { return m_current.brk; }
/// In hexagon it is possible that we can know the dyld breakpoint without
/// having to find it from the rendezvous structure
///
void SetBreakAddress(lldb::addr_t addr) { m_current.brk = addr; }
/// Returns the current state of the rendezvous structure.
uint64_t GetState() const { return m_current.state; }
/// @returns the base address of the runtime linker in the inferiors address
/// space.
lldb::addr_t GetLDBase() const { return m_current.ldbase; }
/// @returns the thread layout metadata from the inferiors thread library.
const ThreadInfo &GetThreadInfo();
/// @returns true if modules have been loaded into the inferior since the
/// last call to Resolve().
bool ModulesDidLoad() const { return !m_added_soentries.empty(); }
/// @returns true if modules have been unloaded from the inferior since the
/// last call to Resolve().
bool ModulesDidUnload() const { return !m_removed_soentries.empty(); }
void DumpToLog(lldb_private::Log *log) const;
/// @brief Constants describing the state of the rendezvous.
///
/// @see GetState().
enum RendezvousState {
eConsistent = 0,
eAdd,
eDelete,
};
/// @brief Structure representing the shared objects currently loaded into
/// the inferior process.
///
/// This object is a rough analogue to the struct link_map object which
/// actually lives in the inferiors memory.
struct SOEntry {
lldb::addr_t link_addr; ///< Address of this link_map.
lldb::addr_t base_addr; ///< Base address of the loaded object.
lldb::addr_t path_addr; ///< String naming the shared object.
lldb::addr_t dyn_addr; ///< Dynamic section of shared object.
lldb::addr_t next; ///< Address of next so_entry.
lldb::addr_t prev; ///< Address of previous so_entry.
std::string path; ///< File name of shared object.
SOEntry() { clear(); }
bool operator==(const SOEntry &entry) { return this->path == entry.path; }
void clear() {
link_addr = 0;
base_addr = 0;
path_addr = 0;
dyn_addr = 0;
next = 0;
prev = 0;
path.clear();
}
};
protected:
typedef std::list<SOEntry> SOEntryList;
public:
typedef SOEntryList::const_iterator iterator;
/// Iterators over all currently loaded modules.
iterator begin() const { return m_soentries.begin(); }
iterator end() const { return m_soentries.end(); }
/// Iterators over all modules loaded into the inferior since the last call
/// to Resolve().
iterator loaded_begin() const { return m_added_soentries.begin(); }
iterator loaded_end() const { return m_added_soentries.end(); }
/// Iterators over all modules unloaded from the inferior since the last
/// call to Resolve().
iterator unloaded_begin() const { return m_removed_soentries.begin(); }
iterator unloaded_end() const { return m_removed_soentries.end(); }
protected:
lldb_private::Process *m_process;
// Cached copy of executable pathname
char m_exe_path[PATH_MAX];
/// Location of the r_debug structure in the inferiors address space.
lldb::addr_t m_rendezvous_addr;
/// Current and previous snapshots of the rendezvous structure.
Rendezvous m_current;
Rendezvous m_previous;
/// List of SOEntry objects corresponding to the current link map state.
SOEntryList m_soentries;
/// List of SOEntry's added to the link map since the last call to Resolve().
SOEntryList m_added_soentries;
/// List of SOEntry's removed from the link map since the last call to
/// Resolve().
SOEntryList m_removed_soentries;
/// Threading metadata read from the inferior.
ThreadInfo m_thread_info;
/// Reads an unsigned integer of @p size bytes from the inferior's address
/// space starting at @p addr.
///
/// @returns addr + size if the read was successful and false otherwise.
lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size);
/// Reads an address from the inferior's address space starting at @p addr.
///
/// @returns addr + target address size if the read was successful and
/// 0 otherwise.
lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst);
/// Reads a null-terminated C string from the memory location starting at @p
/// addr.
std::string ReadStringFromMemory(lldb::addr_t addr);
/// Reads an SOEntry starting at @p addr.
bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
/// Updates the current set of SOEntries, the set of added entries, and the
/// set of removed entries.
bool UpdateSOEntries();
bool UpdateSOEntriesForAddition();
bool UpdateSOEntriesForDeletion();
/// Reads the current list of shared objects according to the link map
/// supplied by the runtime linker.
bool TakeSnapshot(SOEntryList &entry_list);
enum PThreadField { eSize, eNElem, eOffset };
bool FindMetadata(const char *name, PThreadField field, uint32_t &value);
};
#endif // liblldb_HexagonDYLDRendezvous_H_