Files
clang-p2996/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
Greg Clayton 63a27afae3 Added support for thread local variables on all Apple OS variants.
We had support that assumed that thread local data for a variable could be determined solely from the module in which the variable exists. While this work for linux, it doesn't work for Apple OSs. The DWARF for thread local variables consists of location opcodes that do something like:

DW_OP_const8u (x)
DW_OP_form_tls_address

or 

DW_OP_const8u (x)
DW_OP_GNU_push_tls_address

The "x" is allowed to be anything that is needed to determine the location of the variable. For Linux "x" is the offset within the TLS data for a given executable (ModuleSP in LLDB). For Apple OS variants, it is the file address of the data structure that contains a pthread key that can be used with pthread_getspecific() and the offset needed. 

This fix passes the "x" along to the thread:

virtual lldb::addr_t
lldb_private::Thread::GetThreadLocalData(const lldb::ModuleSP module, lldb::addr_t tls_file_addr);

Then this is passed along to the DynamicLoader::GetThreadLocalData():

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

This allows each DynamicLoader plug-in do the right thing for the current OS.

The DynamicLoaderMacOSXDYLD was modified to be able to grab the pthread key from the data structure that is in memory and call "void *pthread_getspecific(pthread_key_t key)" to get the value of the thread local storage and it caches it per thread since it never changes.

I had to update the test case to access the thread local data before trying to print it as on Apple OS variants, thread locals are not available unless they have been accessed at least one by the current thread.

I also added a new lldb::ValueType named "eValueTypeVariableThreadLocal" so that we can ask SBValue objects for their ValueType and be able to tell when we have a thread local variable.

<rdar://problem/23308080>

llvm-svn: 274366
2016-07-01 17:17:23 +00:00

400 lines
12 KiB
C++

//===-- DynamicLoaderMacOSXDYLD.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_DynamicLoaderMacOSXDYLD_h_
#define liblldb_DynamicLoaderMacOSXDYLD_h_
// C Includes
// C++ Includes
#include <map>
#include <mutex>
#include <vector>
// Other libraries and framework includes
// Project includes
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/UUID.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/SafeMachO.h"
class DynamicLoaderMacOSXDYLD : public lldb_private::DynamicLoader
{
public:
DynamicLoaderMacOSXDYLD(lldb_private::Process *process);
~DynamicLoaderMacOSXDYLD() override;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
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);
//------------------------------------------------------------------
/// Called after attaching a process.
///
/// Allow DynamicLoader plug-ins to execute some code after
/// attaching to a process.
//------------------------------------------------------------------
void
DidAttach() override;
void
DidLaunch() override;
bool
ProcessDidExec() override;
lldb::ThreadPlanSP
GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
bool stop_others) override;
size_t
FindEquivalentSymbols(lldb_private::Symbol *original_symbol,
lldb_private::ModuleList &module_list,
lldb_private::SymbolContextList &equivalent_symbols) override;
lldb_private::Error
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;
bool
AlwaysRelyOnEHUnwindInfo(lldb_private::SymbolContext &sym_ctx) override;
protected:
void
PrivateInitialize (lldb_private::Process *process);
void
PrivateProcessStateChanged (lldb_private::Process *process,
lldb::StateType state);
bool
LocateDYLD ();
bool
DidSetNotificationBreakpoint () const;
void
Clear (bool clear_process);
void
PutToLog (lldb_private::Log *log) const;
bool
ReadDYLDInfoFromMemoryAndSetNotificationCallback (lldb::addr_t addr);
static bool
NotifyBreakpointHit (void *baton,
lldb_private::StoppointCallbackContext *context,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);
uint32_t
AddrByteSize();
static lldb::ByteOrder
GetByteOrderFromMagic (uint32_t magic);
bool
ReadMachHeader (lldb::addr_t addr,
llvm::MachO::mach_header *header,
lldb_private::DataExtractor *load_command_data);
class Segment
{
public:
Segment() :
name(),
vmaddr(LLDB_INVALID_ADDRESS),
vmsize(0),
fileoff(0),
filesize(0),
maxprot(0),
initprot(0),
nsects(0),
flags(0)
{
}
lldb_private::ConstString name;
lldb::addr_t vmaddr;
lldb::addr_t vmsize;
lldb::addr_t fileoff;
lldb::addr_t filesize;
uint32_t maxprot;
uint32_t initprot;
uint32_t nsects;
uint32_t flags;
bool
operator==(const Segment& rhs) const
{
return name == rhs.name && vmaddr == rhs.vmaddr && vmsize == rhs.vmsize;
}
void
PutToLog (lldb_private::Log *log,
lldb::addr_t slide) const;
};
struct DYLDImageInfo
{
lldb::addr_t address; // Address of mach header for this dylib
lldb::addr_t slide; // The amount to slide all segments by if there is a global slide.
lldb::addr_t mod_date; // Modification date for this dylib
lldb_private::FileSpec file_spec; // Resolved path for this dylib
lldb_private::UUID uuid; // UUID for this dylib if it has one, else all zeros
llvm::MachO::mach_header header; // The mach header for this image
std::vector<Segment> segments; // All segment vmaddr and vmsize pairs for this executable (from memory of inferior)
uint32_t load_stop_id; // The process stop ID that the sections for this image were loaded
DYLDImageInfo() :
address(LLDB_INVALID_ADDRESS),
slide(0),
mod_date(0),
file_spec(),
uuid(),
header(),
segments(),
load_stop_id(0)
{
}
void
Clear(bool load_cmd_data_only)
{
if (!load_cmd_data_only)
{
address = LLDB_INVALID_ADDRESS;
slide = 0;
mod_date = 0;
file_spec.Clear();
::memset (&header, 0, sizeof(header));
}
uuid.Clear();
segments.clear();
load_stop_id = 0;
}
bool
operator == (const DYLDImageInfo& rhs) const
{
return address == rhs.address
&& slide == rhs.slide
&& mod_date == rhs.mod_date
&& file_spec == rhs.file_spec
&& uuid == rhs.uuid
&& memcmp(&header, &rhs.header, sizeof(header)) == 0
&& segments == rhs.segments;
}
bool
UUIDValid() const
{
return uuid.IsValid();
}
uint32_t
GetAddressByteSize ()
{
if (header.cputype)
{
if (header.cputype & llvm::MachO::CPU_ARCH_ABI64)
return 8;
else
return 4;
}
return 0;
}
lldb::ByteOrder
GetByteOrder();
lldb_private::ArchSpec
GetArchitecture () const
{
return lldb_private::ArchSpec (lldb_private::eArchTypeMachO, header.cputype, header.cpusubtype);
}
const Segment *
FindSegment (const lldb_private::ConstString &name) const;
void
PutToLog (lldb_private::Log *log) const;
typedef std::vector<DYLDImageInfo> collection;
typedef collection::iterator iterator;
typedef collection::const_iterator const_iterator;
};
struct DYLDAllImageInfos
{
uint32_t version;
uint32_t dylib_info_count; // Version >= 1
lldb::addr_t dylib_info_addr; // Version >= 1
lldb::addr_t notification; // Version >= 1
bool processDetachedFromSharedRegion; // Version >= 1
bool libSystemInitialized; // Version >= 2
lldb::addr_t dyldImageLoadAddress; // Version >= 2
DYLDAllImageInfos() :
version (0),
dylib_info_count (0),
dylib_info_addr (LLDB_INVALID_ADDRESS),
notification (LLDB_INVALID_ADDRESS),
processDetachedFromSharedRegion (false),
libSystemInitialized (false),
dyldImageLoadAddress (LLDB_INVALID_ADDRESS)
{
}
void
Clear()
{
version = 0;
dylib_info_count = 0;
dylib_info_addr = LLDB_INVALID_ADDRESS;
notification = LLDB_INVALID_ADDRESS;
processDetachedFromSharedRegion = false;
libSystemInitialized = false;
dyldImageLoadAddress = LLDB_INVALID_ADDRESS;
}
bool
IsValid() const
{
return version >= 1 || version <= 6;
}
};
typedef std::map<uint64_t, lldb::addr_t> PthreadKeyToTLSMap;
typedef std::map<lldb::user_id_t, PthreadKeyToTLSMap> ThreadIDToTLSMap;
void
RegisterNotificationCallbacks();
void
UnregisterNotificationCallbacks();
uint32_t
ParseLoadCommands (const lldb_private::DataExtractor& data,
DYLDImageInfo& dylib_info,
lldb_private::FileSpec *lc_id_dylinker);
bool
UpdateImageLoadAddress(lldb_private::Module *module,
DYLDImageInfo& info);
bool
UnloadImageLoadAddress (lldb_private::Module *module,
DYLDImageInfo& info);
lldb::ModuleSP
FindTargetModuleForDYLDImageInfo (DYLDImageInfo &image_info,
bool can_create,
bool *did_create_ptr);
DYLDImageInfo *
GetImageInfo (lldb_private::Module *module);
bool
NeedToLocateDYLD () const;
bool
SetNotificationBreakpoint ();
// There is a little tricky bit where you might initially attach while dyld is updating
// the all_image_infos, and you can't read the infos, so you have to continue and pick it
// up when you hit the update breakpoint. At that point, you need to run this initialize
// function, but when you do it that way you DON'T need to do the extra work you would at
// the breakpoint.
// So this function will only do actual work if the image infos haven't been read yet.
// If it does do any work, then it will return true, and false otherwise. That way you can
// call it in the breakpoint action, and if it returns true you're done.
bool
InitializeFromAllImageInfos ();
bool
ReadAllImageInfosStructure ();
bool
AddModulesUsingInfosFromDebugserver (lldb_private::StructuredData::ObjectSP image_details, DYLDImageInfo::collection &image_infos);
bool
AddModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count);
bool
AddModulesUsingImageInfos (DYLDImageInfo::collection &image_infos);
bool
RemoveModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count);
void
UpdateImageInfosHeaderAndLoadCommands(DYLDImageInfo::collection &image_infos,
uint32_t infos_count,
bool update_executable);
bool
ReadImageInfos (lldb::addr_t image_infos_addr,
uint32_t image_infos_count,
DYLDImageInfo::collection &image_infos);
lldb::ModuleSP
GetPThreadLibraryModule();
lldb_private::Address
GetPthreadSetSpecificAddress();
DYLDImageInfo m_dyld; // Info about the current dyld being used
lldb::ModuleWP m_dyld_module_wp;
lldb::ModuleWP m_libpthread_module_wp;
lldb_private::Address m_pthread_getspecific_addr;
lldb::addr_t m_dyld_all_image_infos_addr;
DYLDAllImageInfos m_dyld_all_image_infos;
ThreadIDToTLSMap m_tid_to_tls_map;
uint32_t m_dyld_all_image_infos_stop_id;
lldb::user_id_t m_break_id;
DYLDImageInfo::collection m_dyld_image_infos; // Current shared libraries information
uint32_t m_dyld_image_infos_stop_id; // The process stop ID that "m_dyld_image_infos" is valid for
mutable std::recursive_mutex m_mutex;
lldb_private::Process::Notifications m_notification_callbacks;
bool m_process_image_addr_is_all_images_infos;
private:
DISALLOW_COPY_AND_ASSIGN (DynamicLoaderMacOSXDYLD);
};
#endif // liblldb_DynamicLoaderMacOSXDYLD_h_