diff options
Diffstat (limited to 'lldb/source')
13 files changed, 381 insertions, 26 deletions
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 50879f58388..ad396d499f5 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -38,10 +38,12 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/StackID.h" +#include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; +// TODO- why is this also defined (in a better way) in DWARFDefines.cpp? const char * DW_OP_value_to_name (uint32_t val) { @@ -220,6 +222,7 @@ DW_OP_value_to_name (uint32_t val) // DWARFExpression constructor //---------------------------------------------------------------------- DWARFExpression::DWARFExpression() : + m_module_wp(), m_data(), m_reg_kind (eRegisterKindDWARF), m_loclist_slide (LLDB_INVALID_ADDRESS) @@ -227,6 +230,7 @@ DWARFExpression::DWARFExpression() : } DWARFExpression::DWARFExpression(const DWARFExpression& rhs) : + m_module_wp(rhs.m_module_wp), m_data(rhs.m_data), m_reg_kind (rhs.m_reg_kind), m_loclist_slide(rhs.m_loclist_slide) @@ -234,11 +238,14 @@ DWARFExpression::DWARFExpression(const DWARFExpression& rhs) : } -DWARFExpression::DWARFExpression(const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) : +DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp, const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) : + m_module_wp(), m_data(data, data_offset, data_length), m_reg_kind (eRegisterKindDWARF), m_loclist_slide(LLDB_INVALID_ADDRESS) { + if (module_sp) + m_module_wp = module_sp; } //---------------------------------------------------------------------- @@ -262,11 +269,12 @@ DWARFExpression::SetOpcodeData (const DataExtractor& data) } void -DWARFExpression::CopyOpcodeData (const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) +DWARFExpression::CopyOpcodeData (lldb::ModuleSP module_sp, const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) { const uint8_t *bytes = data.PeekData(data_offset, data_length); if (bytes) { + m_module_wp = module_sp; m_data.SetData(DataBufferSP(new DataBufferHeap(bytes, data_length))); m_data.SetByteOrder(data.GetByteOrder()); m_data.SetAddressByteSize(data.GetAddressByteSize()); @@ -274,8 +282,9 @@ DWARFExpression::CopyOpcodeData (const DataExtractor& data, lldb::offset_t data_ } void -DWARFExpression::SetOpcodeData (const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) +DWARFExpression::SetOpcodeData (lldb::ModuleSP module_sp, const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) { + m_module_wp = module_sp; m_data.SetData(data, data_offset, data_length); } @@ -588,6 +597,9 @@ DWARFExpression::DumpLocation (Stream *s, lldb::offset_t offset, lldb::offset_t // case DW_OP_APPLE_array_ref: // s->PutCString("DW_OP_APPLE_array_ref"); // break; + case DW_OP_GNU_push_tls_address: + s->PutCString("DW_OP_GNU_push_tls_address"); // 0xe0 + break; case DW_OP_APPLE_uninit: s->PutCString("DW_OP_APPLE_uninit"); // 0xF0 break; @@ -919,7 +931,8 @@ GetOpcodeDataSize (const DataExtractor &data, const lldb::offset_t data_offset, case DW_OP_form_tls_address: // 0x9b DWARF3 case DW_OP_call_frame_cfa: // 0x9c DWARF3 case DW_OP_stack_value: // 0x9f DWARF4 - return 0; + case DW_OP_GNU_push_tls_address: // 0xe0 GNU extension + return 0; // Opcodes with a single 1 byte arguments case DW_OP_const1u: // 0x08 1 1-byte constant @@ -1221,6 +1234,8 @@ DWARFExpression::Evaluate Error *error_ptr ) const { + ModuleSP module_sp = m_module_wp.lock(); + if (IsLocationList()) { lldb::offset_t offset = 0; @@ -1268,7 +1283,7 @@ DWARFExpression::Evaluate if (length > 0 && lo_pc <= pc && pc < hi_pc) { - return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, m_data, offset, length, m_reg_kind, initial_value_ptr, result, error_ptr); + return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, module_sp, m_data, offset, length, m_reg_kind, initial_value_ptr, result, error_ptr); } offset += length; } @@ -1280,7 +1295,7 @@ DWARFExpression::Evaluate } // Not a location list, just a single expression. - return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, m_data, 0, m_data.GetByteSize(), m_reg_kind, initial_value_ptr, result, error_ptr); + return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, module_sp, m_data, 0, m_data.GetByteSize(), m_reg_kind, initial_value_ptr, result, error_ptr); } @@ -1292,6 +1307,7 @@ DWARFExpression::Evaluate ClangExpressionVariableList *expr_locals, ClangExpressionDeclMap *decl_map, RegisterContext *reg_ctx, + lldb::ModuleSP opcode_ctx, const DataExtractor& opcodes, const lldb::offset_t opcodes_offset, const lldb::offset_t opcodes_length, @@ -2659,6 +2675,54 @@ DWARFExpression::Evaluate return false; } break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_GNU_push_tls_address + // OPERANDS: none + // DESCRIPTION: Pops a TLS offset from the stack, converts it to + // an absolute value, and pushes it back on. + //---------------------------------------------------------------------- + case DW_OP_GNU_push_tls_address: + { + if (stack.size() < 1) + { + if (error_ptr) + error_ptr->SetErrorString("DW_OP_GNU_push_tls_address needs an argument."); + return false; + } + + if (!exe_ctx || !opcode_ctx) + { + if (error_ptr) + error_ptr->SetErrorString("No context to evaluate TLS within."); + return false; + } + + Thread *thread = exe_ctx->GetThreadPtr(); + if (!thread) + { + if (error_ptr) + error_ptr->SetErrorString("No thread to evaluate TLS within."); + return false; + } + + // Lookup the TLS block address for this thread and module. + addr_t tls_addr = thread->GetThreadLocalData (opcode_ctx); + + if (tls_addr == LLDB_INVALID_ADDRESS) + { + if (error_ptr) + error_ptr->SetErrorString ("No TLS data currently exists for this thread."); + return false; + } + + // Convert the TLS offset into the absolute address. + Scalar tmp = stack.back().ResolveValue(exe_ctx); + stack.back() = tmp + tls_addr; + stack.back().SetValueType (Value::eValueTypeLoadAddress); + } + break; + default: if (log) log->Printf("Unhandled opcode %s in DWARFExpression.", DW_OP_value_to_name(op)); diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index 556df606248..3c5dcc5222a 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -14,6 +14,7 @@ #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" +#include "lldb/Symbol/Symbol.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -55,6 +56,8 @@ DYLDRendezvous::DYLDRendezvous(Process *process) m_added_soentries(), m_removed_soentries() { + m_thread_info.valid = false; + // Cache a copy of the executable path if (m_process) { @@ -284,6 +287,8 @@ bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) { entry.clear(); + + entry.link_addr = addr; if (!(addr = ReadPointer(addr, &entry.base_addr))) return false; @@ -320,6 +325,51 @@ DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) return true; } + +bool +DYLDRendezvous::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; + + Error 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 DYLDRendezvous::ThreadInfo& +DYLDRendezvous::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 DYLDRendezvous::DumpToLog(Log *log) const { diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h index 5f8b013dd4a..ca008931799 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h @@ -48,6 +48,16 @@ class DYLDRendezvous { }; 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 + }; + DYLDRendezvous(lldb_private::Process *process); /// Update the internal snapshot of runtime linker rendezvous and recompute @@ -100,6 +110,10 @@ public: 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 @@ -128,6 +142,7 @@ public: /// 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. @@ -142,6 +157,7 @@ public: } void clear() { + link_addr = 0; base_addr = 0; path_addr = 0; dyn_addr = 0; @@ -194,6 +210,9 @@ protected: /// 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. /// @@ -232,6 +251,10 @@ protected: /// 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 diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 8a0b194446c..cb7adc4f3ec 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -123,7 +123,7 @@ DynamicLoaderPOSIXDYLD::DidAttach() { ModuleList module_list; module_list.Append(executable); - UpdateLoadedSections(executable, load_offset); + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset); LoadAllCurrentModules(); m_process->GetTarget().ModulesDidLoad(module_list); } @@ -144,7 +144,7 @@ DynamicLoaderPOSIXDYLD::DidLaunch() { ModuleList module_list; module_list.Append(executable); - UpdateLoadedSections(executable, load_offset); + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset); ProbeEntry(); m_process->GetTarget().ModulesDidLoad(module_list); } @@ -209,13 +209,15 @@ DynamicLoaderPOSIXDYLD::CanLoadImage() } void -DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t base_addr) +DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr) { SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList(); const SectionList *sections = GetSectionListFromModule(module); assert(sections && "SectionList missing from loaded module."); + m_loaded_modules[module] = link_map_addr; + const size_t num_sections = sections->GetSize(); for (unsigned i = 0; i < num_sections; ++i) @@ -243,6 +245,8 @@ DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module) assert(sections && "SectionList missing from unloaded module."); + m_loaded_modules.erase(module); + const size_t num_sections = sections->GetSize(); for (size_t i = 0; i < num_sections; ++i) { @@ -337,7 +341,7 @@ DynamicLoaderPOSIXDYLD::RefreshModules() for (I = m_rendezvous.loaded_begin(); I != E; ++I) { FileSpec file(I->path.c_str(), true); - ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); + ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr); if (module_sp.get()) { loaded_modules.AppendIfNeeded(module_sp); @@ -439,11 +443,17 @@ DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() return; } + // The rendezvous class doesn't enumerate the main module, so track + // that ourselves here. + ModuleSP executable = GetTargetExecutable(); + m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); + + for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) { const char *module_path = I->path.c_str(); FileSpec file(module_path, false); - ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); + ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr); if (module_sp.get()) { module_list.Append(module_sp); @@ -461,7 +471,7 @@ DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() } ModuleSP -DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_addr) +DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr) { Target &target = m_process->GetTarget(); ModuleList &modules = target.GetImages(); @@ -470,11 +480,11 @@ DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_ad ModuleSpec module_spec (file, target.GetArchitecture()); if ((module_sp = modules.FindFirstModule (module_spec))) { - UpdateLoadedSections(module_sp, base_addr); + UpdateLoadedSections(module_sp, link_map_addr, base_addr); } else if ((module_sp = target.GetSharedModule(module_spec))) { - UpdateLoadedSections(module_sp, base_addr); + UpdateLoadedSections(module_sp, link_map_addr, base_addr); } return module_sp; @@ -537,3 +547,68 @@ DynamicLoaderPOSIXDYLD::GetSectionListFromModule(const ModuleSP module) const } return sections; } + +static int ReadInt(Process *process, addr_t addr) +{ + Error error; + int value = (int)process->ReadUnsignedIntegerFromMemory(addr, sizeof(uint32_t), 0, error); + if (error.Fail()) + return -1; + else + return value; +} + +static addr_t ReadPointer(Process *process, addr_t addr) +{ + Error error; + addr_t value = process->ReadPointerFromMemory(addr, error); + if (error.Fail()) + return LLDB_INVALID_ADDRESS; + else + return value; +} + +lldb::addr_t +DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const lldb::ThreadSP thread) +{ + std::map<ModuleWP, addr_t>::const_iterator it = m_loaded_modules.find (module); + if (it == m_loaded_modules.end()) + return LLDB_INVALID_ADDRESS; + + addr_t link_map = it->second; + if (link_map == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo(); + if (!metadata.valid) + return LLDB_INVALID_ADDRESS; + + // Get the thread pointer. + addr_t tp = thread->GetThreadPointer (); + if (tp == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + // Find the module's modid. + int modid = ReadInt (m_process, link_map + metadata.modid_offset); + if (modid == -1) + return LLDB_INVALID_ADDRESS; + + // Lookup the DTV stucture for this thread. + addr_t dtv_ptr = tp + metadata.dtv_offset; + addr_t dtv = ReadPointer (m_process, dtv_ptr); + if (dtv == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + // Find the TLS block for this module. + addr_t dtv_slot = dtv + metadata.dtv_slot_size*modid; + addr_t tls_block = ReadPointer (m_process, dtv_slot + metadata.tls_offset); + + Module *mod = module.get(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::Performed TLS lookup: " + "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 ", modid=%i, tls_block=0x%" PRIx64 "\n", + mod->GetObjectName().AsCString(""), link_map, tp, modid, tls_block); + + return tls_block; +} diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index 414f12098cf..7997b34195a 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -61,6 +61,9 @@ public: virtual lldb_private::Error CanLoadImage(); + virtual lldb::addr_t + GetThreadLocalData (const lldb::ModuleSP module, const lldb::ThreadSP thread); + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -95,6 +98,9 @@ protected: /// 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. void @@ -117,10 +123,13 @@ protected: /// /// @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 base_addr = 0); + 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. /// @@ -131,7 +140,7 @@ 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 base_addr); + LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t link_map_addr, lldb::addr_t base_addr); /// Resolves the entry point for the current inferior process and sets a /// breakpoint at that address. diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp index a0cda3485c6..bda0cb33097 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp +++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp @@ -19,6 +19,7 @@ #include <sys/socket.h> #include <sys/syscall.h> #include <sys/types.h> +#include <sys/user.h> #include <sys/wait.h> // C++ Includes @@ -46,6 +47,19 @@ #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif +#ifndef PTRACE_GET_THREAD_AREA + #define PTRACE_GET_THREAD_AREA 25 +#endif +#ifndef PTRACE_ARCH_PRCTL + #define PTRACE_ARCH_PRCTL 30 +#endif +#ifndef ARCH_GET_FS + #define ARCH_SET_GS 0x1001 + #define ARCH_SET_FS 0x1002 + #define ARCH_GET_FS 0x1003 + #define ARCH_GET_GS 0x1004 +#endif + // Support hardware breakpoints in case it has not been defined #ifndef TRAP_HWBKPT @@ -703,6 +717,74 @@ WriteRegisterSetOperation::Execute(ProcessMonitor *monitor) } //------------------------------------------------------------------------------ +/// @class ReadThreadPointerOperation +/// @brief Implements ProcessMonitor::ReadThreadPointer. +class ReadThreadPointerOperation : public Operation +{ +public: + ReadThreadPointerOperation(lldb::tid_t tid, lldb::addr_t *addr, bool &result) + : m_tid(tid), m_addr(addr), m_result(result) + { } + + void Execute(ProcessMonitor *monitor); + +private: + lldb::tid_t m_tid; + lldb::addr_t *m_addr; + bool &m_result; +}; + +void +ReadThreadPointerOperation::Execute(ProcessMonitor *monitor) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); + if (log) + log->Printf ("ProcessMonitor::%s()", __FUNCTION__); + + // The process for getting the thread area on Linux is + // somewhat... obscure. There's several different ways depending on + // what arch you're on, and what kernel version you have. + + const ArchSpec& arch = monitor->GetProcess().GetTarget().GetArchitecture(); + switch(arch.GetMachine()) + { + case llvm::Triple::x86: + { + // Find the GS register location for our host architecture. + size_t gs_user_offset = offsetof(struct user, regs); +#ifdef __x86_64__ + gs_user_offset += offsetof(struct user_regs_struct, gs); +#endif +#ifdef __i386__ + gs_user_offset += offsetof(struct user_regs_struct, xgs); +#endif + + // Read the GS register value to get the selector. + errno = 0; + long gs = PTRACE(PTRACE_PEEKUSER, m_tid, (void*)gs_user_offset, NULL, 0); + if (errno) + { + m_result = false; + break; + } + + // Read the LDT base for that selector. + uint32_t tmp[4]; + m_result = (PTRACE(PTRACE_GET_THREAD_AREA, m_tid, (void *)(gs >> 3), &tmp, 0) == 0); + *m_addr = tmp[1]; + break; + } + case llvm::Triple::x86_64: + // Read the FS register base. + m_result = (PTRACE(PTRACE_ARCH_PRCTL, m_tid, m_addr, (void *)ARCH_GET_FS, 0) == 0); + break; + default: + m_result = false; + break; + } +} + +//------------------------------------------------------------------------------ /// @class ResumeOperation /// @brief Implements ProcessMonitor::Resume. class ResumeOperation : public Operation @@ -2106,6 +2188,15 @@ ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, un } bool +ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value) +{ + bool result; + ReadThreadPointerOperation op(tid, &value, result); + DoOperation(&op); + return result; +} + +bool ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo) { bool result; diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.h b/lldb/source/Plugins/Process/Linux/ProcessMonitor.h index 3729e257feb..a087140f407 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.h +++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.h @@ -147,6 +147,10 @@ public: bool WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); + /// Reads the value of the thread-specific pointer for a given thread ID. + bool + ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value); + /// Writes a siginfo_t structure corresponding to the given thread ID to the /// memory region pointed to by @p siginfo. bool diff --git a/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp b/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp index db68875723c..16399748c54 100644 --- a/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -230,6 +230,17 @@ POSIXThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) return reg_ctx_sp; } +lldb::addr_t +POSIXThread::GetThreadPointer () +{ + ProcessMonitor &monitor = GetMonitor(); + addr_t addr; + if (monitor.ReadThreadPointer (GetID(), addr)) + return addr; + else + return LLDB_INVALID_ADDRESS; +} + bool POSIXThread::CalculateStopInfo() { diff --git a/lldb/source/Plugins/Process/POSIX/POSIXThread.h b/lldb/source/Plugins/Process/POSIX/POSIXThread.h index 5490f1f1ea5..51d6645f209 100644 --- a/lldb/source/Plugins/Process/POSIX/POSIXThread.h +++ b/lldb/source/Plugins/Process/POSIX/POSIXThread.h @@ -59,6 +59,9 @@ public: virtual lldb::RegisterContextSP CreateRegisterContextForFrame (lldb_private::StackFrame *frame); + virtual lldb::addr_t + GetThreadPointer (); + //-------------------------------------------------------------------------- // These functions provide a mapping from the register offset // back to the register index or name for use in debugging or log diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 2a01d6a92d9..c19aec3a02c 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -1196,7 +1196,8 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(), unwindplan_regloc.GetDWARFExpressionLength(), process->GetByteOrder(), process->GetAddressByteSize()); - DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength()); + ModuleSP opcode_ctx; + DWARFExpression dwarfexpr (opcode_ctx, dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength()); dwarfexpr.SetRegisterKind (unwindplan_registerkind); Value result; Error error; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 7351f1d9509..5dd81b7bb96 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -763,6 +763,8 @@ DWARFDebugInfoEntry::GetDIENamesAndRanges lldb::offset_t offset; const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + lldb::ModuleSP module = dwarf2Data->GetObjectFile()->GetModule(); + if (abbrevDecl) { const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); @@ -874,7 +876,7 @@ DWARFDebugInfoEntry::GetDIENamesAndRanges { uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); uint32_t block_length = form_value.Unsigned(); - frame_base->SetOpcodeData(debug_info_data, block_offset, block_length); + frame_base->SetOpcodeData(module, debug_info_data, block_offset, block_length); } else { @@ -884,7 +886,7 @@ DWARFDebugInfoEntry::GetDIENamesAndRanges size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset); if (loc_list_length > 0) { - frame_base->SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length); + frame_base->SetOpcodeData(module, debug_loc_data, debug_loc_offset, loc_list_length); if (lo_pc != LLDB_INVALID_ADDRESS) { assert (lo_pc >= cu->GetBaseAddress()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 2579fe07591..c703ce5ed8a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1706,6 +1706,7 @@ SymbolFileDWARF::ParseChildMembers const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); uint32_t member_idx = 0; BitfieldInfo last_field_info; + ModuleSP module = GetObjectFile()->GetModule(); for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) { @@ -1769,6 +1770,7 @@ SymbolFileDWARF::ParseChildMembers NULL, // ClangExpressionVariableList * NULL, // ClangExpressionDeclMap * NULL, // RegisterContext * + module, debug_info_data, block_offset, block_length, @@ -2160,6 +2162,7 @@ SymbolFileDWARF::ParseChildMembers NULL, NULL, NULL, + module, debug_info_data, block_offset, block_length, @@ -7267,6 +7270,7 @@ SymbolFileDWARF::ParseVariableDIE return var_sp; // Already been parsed! const dw_tag_t tag = die->Tag(); + ModuleSP module = GetObjectFile()->GetModule(); if ((tag == DW_TAG_variable) || (tag == DW_TAG_constant) || @@ -7316,7 +7320,7 @@ SymbolFileDWARF::ParseVariableDIE // Retrieve the value as a block expression. uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); uint32_t block_length = form_value.Unsigned(); - location.CopyOpcodeData(debug_info_data, block_offset, block_length); + location.CopyOpcodeData(module, debug_info_data, block_offset, block_length); } else if (DWARFFormValue::IsDataForm(form_value.Form())) { @@ -7324,7 +7328,7 @@ SymbolFileDWARF::ParseVariableDIE const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); uint32_t data_offset = attributes.DIEOffsetAtIndex(i); uint32_t data_length = fixed_form_sizes[form_value.Form()]; - location.CopyOpcodeData(debug_info_data, data_offset, data_length); + location.CopyOpcodeData(module, debug_info_data, data_offset, data_length); } else { @@ -7334,14 +7338,14 @@ SymbolFileDWARF::ParseVariableDIE const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); uint32_t data_offset = attributes.DIEOffsetAtIndex(i); uint32_t data_length = fixed_form_sizes[form_value.Form()]; - location.CopyOpcodeData(debug_info_data, data_offset, data_length); + location.CopyOpcodeData(module, debug_info_data, data_offset, data_length); } else { const char *str = form_value.AsCString(&debug_info_data); uint32_t string_offset = str - (const char *)debug_info_data.GetDataStart(); uint32_t string_length = strlen(str) + 1; - location.CopyOpcodeData(debug_info_data, string_offset, string_length); + location.CopyOpcodeData(module, debug_info_data, string_offset, string_length); } } } @@ -7356,7 +7360,7 @@ SymbolFileDWARF::ParseVariableDIE uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); uint32_t block_length = form_value.Unsigned(); - location.CopyOpcodeData(get_debug_info_data(), block_offset, block_length); + location.CopyOpcodeData(module, get_debug_info_data(), block_offset, block_length); } else { @@ -7366,7 +7370,7 @@ SymbolFileDWARF::ParseVariableDIE size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset); if (loc_list_length > 0) { - location.CopyOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length); + location.CopyOpcodeData(module, debug_loc_data, debug_loc_offset, loc_list_length); assert (func_low_pc != LLDB_INVALID_ADDRESS); location.SetLocationListSlide (func_low_pc - dwarf_cu->GetBaseAddress()); } diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 0ef91e8a650..1e33565a4c5 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -1857,6 +1857,24 @@ Thread::SettingsTerminate () { } +lldb::addr_t +Thread::GetThreadPointer () +{ + return LLDB_INVALID_ADDRESS; +} + +addr_t +Thread::GetThreadLocalData (const ModuleSP module) +{ + // The default implementation is to ask the dynamic loader for it. + // This can be overridden for specific platforms. + DynamicLoader *loader = GetProcess()->GetDynamicLoader(); + if (loader) + return loader->GetThreadLocalData (module, shared_from_this()); + else + return LLDB_INVALID_ADDRESS; +} + lldb::StackFrameSP Thread::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr) { |