Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
//===-- DynamicLoaderHexagon.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_DynamicLoaderHexagon_H_
#define liblldb_DynamicLoaderHexagon_H_

// C Includes
// C++ Includes
// Other libraries and framework includes
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Target/DynamicLoader.h"

#include "HexagonDYLDRendezvous.h"

class DynamicLoaderHexagonDYLD : public lldb_private::DynamicLoader
{
public:

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);

DynamicLoaderHexagonDYLD(lldb_private::Process *process);

virtual
~DynamicLoaderHexagonDYLD();

//------------------------------------------------------------------
// DynamicLoader protocol
//------------------------------------------------------------------

virtual void
DidAttach();

virtual void
DidLaunch();

virtual lldb::ThreadPlanSP
GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
bool stop_others);

virtual lldb_private::Error
CanLoadImage();

virtual lldb::addr_t
GetThreadLocalData (const lldb::ModuleSP module, const lldb::ThreadSP thread);

//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
virtual lldb_private::ConstString
GetPluginName();

virtual uint32_t
GetPluginVersion();

virtual void
GetPluginCommandHelp(const char *command, lldb_private::Stream *strm);

virtual lldb_private::Error
ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm);

virtual lldb_private::Log *
EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command);

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);

/// Removes the loaded sections from the target in @p module.
///
/// @param module The module to traverse.
void
UnloadSections(const lldb::ModuleSP module);

/// 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);

/// 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:
DISALLOW_COPY_AND_ASSIGN(DynamicLoaderHexagonDYLD);

const lldb_private::SectionList *
GetSectionListFromModule(const lldb::ModuleSP module) const;
};

#endif // liblldb_DynamicLoaderHexagonDYLD_H_

Large diffs are not rendered by default.

279 changes: 279 additions & 0 deletions lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
//===-- 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_
14 changes: 14 additions & 0 deletions lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
##===- source/Plugins/DynamicLoader/Hexagon-DYLD/Makefile ----*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##

LLDB_LEVEL := ../../../..
LIBRARYNAME := lldbPluginDynamicLoaderHexagon
BUILD_ARCHIVE = 1

include $(LLDB_LEVEL)/Makefile
3 changes: 2 additions & 1 deletion lldb/source/Plugins/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ LLDB_LEVEL := ../..
include $(LLDB_LEVEL)/../../Makefile.config


DIRS := ABI/MacOSX-arm ABI/MacOSX-arm64 ABI/MacOSX-i386 ABI/SysV-x86_64 \
DIRS := ABI/MacOSX-arm ABI/MacOSX-arm64 ABI/MacOSX-i386 ABI/SysV-x86_64 ABI/SysV-hexagon \
Disassembler/llvm \
ObjectContainer/BSD-Archive ObjectFile/ELF ObjectFile/PECOFF \
ObjectFile/JIT SymbolFile/DWARF SymbolFile/Symtab Process/Utility \
Expand All @@ -22,6 +22,7 @@ DIRS := ABI/MacOSX-arm ABI/MacOSX-arm64 ABI/MacOSX-i386 ABI/SysV-x86_64 \
LanguageRuntime/CPlusPlus/ItaniumABI \
LanguageRuntime/ObjC/AppleObjCRuntime \
DynamicLoader/POSIX-DYLD \
DynamicLoader/Hexagon-DYLD \
OperatingSystem/Python \
SymbolVendor/ELF

Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ ELFHeader::GetRelocationJumpSlotType() const
case EM_ARM:
slot = R_ARM_JUMP_SLOT;
break;
case EM_HEXAGON:
slot = R_HEX_JMP_SLOT;
break;
}

return slot;
Expand Down