diff options
Diffstat (limited to 'source/Plugins')
48 files changed, 2206 insertions, 1134 deletions
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index 61c3c64d4fc3..e9b8a9f573a3 100644 --- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -35,6 +35,7 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/StackFrame.h" @@ -127,6 +128,7 @@ public: bool got_op = false; DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC(); const ArchSpec &arch = llvm_disasm.GetArchitecture(); + const lldb::ByteOrder byte_order = data.GetByteOrder(); const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize(); const uint32_t max_op_byte_size = arch.GetMaximumOpcodeByteSize(); @@ -135,26 +137,26 @@ public: // Fixed size instructions, just read that amount of data. if (!data.ValidOffsetForDataOfSize(data_offset, min_op_byte_size)) return false; - + switch (min_op_byte_size) { case 1: - m_opcode.SetOpcode8 (data.GetU8 (&data_offset)); + m_opcode.SetOpcode8 (data.GetU8 (&data_offset), byte_order); got_op = true; break; case 2: - m_opcode.SetOpcode16 (data.GetU16 (&data_offset)); + m_opcode.SetOpcode16 (data.GetU16 (&data_offset), byte_order); got_op = true; break; case 4: - m_opcode.SetOpcode32 (data.GetU32 (&data_offset)); + m_opcode.SetOpcode32 (data.GetU32 (&data_offset), byte_order); got_op = true; break; case 8: - m_opcode.SetOpcode64 (data.GetU64 (&data_offset)); + m_opcode.SetOpcode64 (data.GetU64 (&data_offset), byte_order); got_op = true; break; @@ -177,20 +179,20 @@ public: uint32_t thumb_opcode = data.GetU16(&data_offset); if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0)) { - m_opcode.SetOpcode16 (thumb_opcode); + m_opcode.SetOpcode16 (thumb_opcode, byte_order); m_is_valid = true; } else { thumb_opcode <<= 16; thumb_opcode |= data.GetU16(&data_offset); - m_opcode.SetOpcode16_2 (thumb_opcode); + m_opcode.SetOpcode16_2 (thumb_opcode, byte_order); m_is_valid = true; } } else { - m_opcode.SetOpcode32 (data.GetU32(&data_offset)); + m_opcode.SetOpcode32 (data.GetU32(&data_offset), byte_order); m_is_valid = true; } } @@ -303,12 +305,13 @@ public: inst_size = m_opcode.GetByteSize(); StreamString mnemonic_strm; lldb::offset_t offset = 0; + lldb::ByteOrder byte_order = data.GetByteOrder(); switch (inst_size) { case 1: { const uint8_t uval8 = data.GetU8 (&offset); - m_opcode.SetOpcode8 (uval8); + m_opcode.SetOpcode8 (uval8, byte_order); m_opcode_name.assign (".byte"); mnemonic_strm.Printf("0x%2.2x", uval8); } @@ -316,7 +319,7 @@ public: case 2: { const uint16_t uval16 = data.GetU16(&offset); - m_opcode.SetOpcode16(uval16); + m_opcode.SetOpcode16(uval16, byte_order); m_opcode_name.assign (".short"); mnemonic_strm.Printf("0x%4.4x", uval16); } @@ -324,7 +327,7 @@ public: case 4: { const uint32_t uval32 = data.GetU32(&offset); - m_opcode.SetOpcode32(uval32); + m_opcode.SetOpcode32(uval32, byte_order); m_opcode_name.assign (".long"); mnemonic_strm.Printf("0x%8.8x", uval32); } @@ -332,7 +335,7 @@ public: case 8: { const uint64_t uval64 = data.GetU64(&offset); - m_opcode.SetOpcode64(uval64); + m_opcode.SetOpcode64(uval64, byte_order); m_opcode_name.assign (".quad"); mnemonic_strm.Printf("0x%16.16" PRIx64, uval64); } @@ -432,7 +435,8 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns m_subtarget_info_ap.reset(curr_target->createMCSubtargetInfo(triple, "", features_str)); - m_asm_info_ap.reset(curr_target->createMCAsmInfo(*curr_target->createMCRegInfo(triple), triple)); + std::unique_ptr<llvm::MCRegisterInfo> reg_info(curr_target->createMCRegInfo(triple)); + m_asm_info_ap.reset(curr_target->createMCAsmInfo(*reg_info, triple)); if (m_instr_info_ap.get() == NULL || m_reg_info_ap.get() == NULL || m_subtarget_info_ap.get() == NULL || m_asm_info_ap.get() == NULL) { diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 4284558c4409..286b1ef62d9a 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -150,46 +150,6 @@ DynamicLoaderPOSIXDYLD::DidLaunch() } } -ModuleSP -DynamicLoaderPOSIXDYLD::GetTargetExecutable() -{ - Target &target = m_process->GetTarget(); - ModuleSP executable = target.GetExecutableModule(); - - if (executable.get()) - { - if (executable->GetFileSpec().Exists()) - { - ModuleSpec module_spec (executable->GetFileSpec(), executable->GetArchitecture()); - ModuleSP module_sp (new Module (module_spec)); - - // Check if the executable has changed and set it to the target executable if they differ. - if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid()) - { - if (module_sp->GetUUID() != executable->GetUUID()) - executable.reset(); - } - else if (executable->FileHasChanged()) - { - executable.reset(); - } - - if (!executable.get()) - { - executable = target.GetSharedModule(module_spec); - if (executable.get() != target.GetExecutableModulePointer()) - { - // Don't load dependent images since we are in dyld where we will know - // and find out about all images that are loaded - const bool get_dependent_images = false; - target.SetExecutableModule(executable, get_dependent_images); - } - } - } - } - return executable; -} - Error DynamicLoaderPOSIXDYLD::ExecutePluginCommand(Args &command, Stream *strm) { @@ -211,48 +171,17 @@ DynamicLoaderPOSIXDYLD::CanLoadImage() void 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) - { - SectionSP section_sp (sections->GetSectionAtIndex(i)); - lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr; - lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section_sp); - - // If the file address of the section is zero then this is not an - // allocatable/loadable section (property of ELF sh_addr). Skip it. - if (new_load_addr == base_addr) - continue; - - if (old_load_addr == LLDB_INVALID_ADDRESS || - old_load_addr != new_load_addr) - load_list.SetSectionLoadAddress(section_sp, new_load_addr); - } + UpdateLoadedSectionsCommon(module, base_addr); } void DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module) { - SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList(); - const SectionList *sections = GetSectionListFromModule(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) - { - SectionSP section_sp (sections->GetSectionAtIndex(i)); - load_list.SetSectionUnloaded(section_sp); - } + UnloadSectionsCommon(module); } void @@ -470,26 +399,6 @@ DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() m_process->GetTarget().ModulesDidLoad(module_list); } -ModuleSP -DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr) -{ - Target &target = m_process->GetTarget(); - ModuleList &modules = target.GetImages(); - ModuleSP module_sp; - - ModuleSpec module_spec (file, target.GetArchitecture()); - if ((module_sp = modules.FindFirstModule (module_spec))) - { - UpdateLoadedSections(module_sp, link_map_addr, base_addr); - } - else if ((module_sp = target.GetSharedModule(module_spec))) - { - UpdateLoadedSections(module_sp, link_map_addr, base_addr); - } - - return module_sp; -} - addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() { @@ -533,41 +442,6 @@ DynamicLoaderPOSIXDYLD::GetEntryPoint() return m_entry_point; } -const SectionList * -DynamicLoaderPOSIXDYLD::GetSectionListFromModule(const ModuleSP module) const -{ - SectionList *sections = nullptr; - if (module.get()) - { - ObjectFile *obj_file = module->GetObjectFile(); - if (obj_file) - { - sections = obj_file->GetSectionList(); - } - } - 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) { @@ -589,26 +463,27 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const l return LLDB_INVALID_ADDRESS; // Find the module's modid. - int modid = ReadInt (m_process, link_map + metadata.modid_offset); + int modid_size = 4; // FIXME(spucci): This isn't right for big-endian 64-bit + int64_t modid = ReadUnsignedIntWithSizeInBytes (link_map + metadata.modid_offset, modid_size); 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); + addr_t dtv = ReadPointer (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); + addr_t tls_block = ReadPointer (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); + "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 ", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n", + mod->GetObjectName().AsCString(""), link_map, tp, (int64_t)modid, tls_block); return tls_block; } diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index 7997b34195a4..9ced5da8a015 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -126,7 +126,7 @@ protected: /// @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 + virtual void UpdateLoadedSections(lldb::ModuleSP module, lldb::addr_t link_map_addr, lldb::addr_t base_addr); @@ -134,14 +134,9 @@ protected: /// Removes the loaded sections from the target in @p module. /// /// @param module The module to traverse. - void + virtual 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); - /// Resolves the entry point for the current inferior process and sets a /// breakpoint at that address. void @@ -173,16 +168,8 @@ protected: 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(); - private: DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD); - - const lldb_private::SectionList * - GetSectionListFromModule(const lldb::ModuleSP module) const; }; #endif // liblldb_DynamicLoaderPOSIXDYLD_H_ diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp index 274ba328ad1f..86cf45013a4d 100644 --- a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp +++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp @@ -134,7 +134,7 @@ DynamicLoaderStatic::LoadAllImagesAtFileAddresses () SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); if (section_sp) { - if (m_process->GetTarget().GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress())) + if (m_process->GetTarget().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress())) changed = true; } } diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index db03f4536188..f1cb41d5a913 100644 --- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -289,37 +289,65 @@ EmulateInstructionARM::GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, Reg uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber () const { - if (m_opcode_mode == eModeThumb) + bool is_apple = false; + if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple) + is_apple = true; + switch (m_arch.GetTriple().getOS()) { - switch (m_arch.GetTriple().getOS()) - { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: - return 7; + is_apple = true; + break; default: break; - } } - return 11; + + /* On Apple iOS et al, the frame pointer register is always r7. + * Typically on other ARM systems, thumb code uses r7; arm code uses r11. + */ + + uint32_t fp_regnum = 11; + + if (is_apple) + fp_regnum = 7; + + if (m_opcode_mode == eModeThumb) + fp_regnum = 7; + + return fp_regnum; } uint32_t EmulateInstructionARM::GetFramePointerDWARFRegisterNumber () const { - if (m_opcode_mode == eModeThumb) + bool is_apple = false; + if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple) + is_apple = true; + switch (m_arch.GetTriple().getOS()) { - switch (m_arch.GetTriple().getOS()) - { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: - return dwarf_r7; + is_apple = true; + break; default: break; - } } - return dwarf_r11; + + /* On Apple iOS et al, the frame pointer register is always r7. + * Typically on other ARM systems, thumb code uses r7; arm code uses r11. + */ + + uint32_t fp_regnum = dwarf_r11; + + if (is_apple) + fp_regnum = dwarf_r7; + + if (m_opcode_mode == eModeThumb) + fp_regnum = dwarf_r7; + + return fp_regnum; } // Push Multiple Registers stores multiple registers to the stack, storing to @@ -12889,18 +12917,18 @@ EmulateInstructionARM::ReadInstruction () { if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0)) { - m_opcode.SetOpcode16 (thumb_opcode); + m_opcode.SetOpcode16 (thumb_opcode, GetByteOrder()); } else { - m_opcode.SetOpcode32 ((thumb_opcode << 16) | MemARead(read_inst_context, pc + 2, 2, 0, &success)); + m_opcode.SetOpcode32 ((thumb_opcode << 16) | MemARead(read_inst_context, pc + 2, 2, 0, &success), GetByteOrder()); } } } else { m_opcode_mode = eModeARM; - m_opcode.SetOpcode32 (MemARead(read_inst_context, pc, 4, 0, &success)); + m_opcode.SetOpcode32 (MemARead(read_inst_context, pc, 4, 0, &success), GetByteOrder()); } } } @@ -13510,15 +13538,15 @@ EmulateInstructionARM::TestEmulation (Stream *out_stream, ArchSpec &arch, Option if (arch.GetTriple().getArch() == llvm::Triple::arm) { m_opcode_mode = eModeARM; - m_opcode.SetOpcode32 (test_opcode); + m_opcode.SetOpcode32 (test_opcode, GetByteOrder()); } else if (arch.GetTriple().getArch() == llvm::Triple::thumb) { m_opcode_mode = eModeThumb; if (test_opcode < 0x10000) - m_opcode.SetOpcode16 (test_opcode); + m_opcode.SetOpcode16 (test_opcode, GetByteOrder()); else - m_opcode.SetOpcode32 (test_opcode); + m_opcode.SetOpcode32 (test_opcode, GetByteOrder()); } else diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index f3c2d63729ae..9781dcb093ac 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -23,6 +23,7 @@ #include "lldb/Symbol/TypeList.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -402,7 +403,9 @@ ItaniumABILanguageRuntime::CreateExceptionBreakpoint (bool catch_bp, FileSpecList filter_modules; BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions); SearchFilterSP filter_sp (CreateExceptionSearchFilter ()); - return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, false); + const bool hardware = false; + const bool resolve_indirect_functions = false; + return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, hardware, resolve_indirect_functions); } void diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 7bdacfe14cde..02db05b3c6b2 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -24,6 +24,7 @@ #include "lldb/Core/Stream.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Host/Host.h" @@ -462,6 +463,49 @@ ObjectFileELF::IsExecutable() const return m_header.e_entry != 0; } +bool +ObjectFileELF::SetLoadAddress (Target &target, + lldb::addr_t value, + bool value_is_offset) +{ + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) + { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList (); + if (section_list) + { + 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) + { + // 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)) + { + if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + changed = num_loaded_sections > 0; + return num_loaded_sections > 0; + } + else + { + // Not sure how to slide an ELF file given the base address + // of the ELF file in memory + } + } + } + return changed; +} + ByteOrder ObjectFileELF::GetByteOrder() const { diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index a2ab9b8f3703..9b7c073d902d 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -118,6 +118,11 @@ public: virtual bool ParseHeader(); + virtual bool + SetLoadAddress (lldb_private::Target &target, + lldb::addr_t value, + bool value_is_offset); + virtual lldb::ByteOrder GetByteOrder() const; diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index 37b324197350..7ca337e797da 100644 --- a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -190,6 +190,13 @@ OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list, auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure threads_list stays alive PythonList threads_list(m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp)); + + const uint32_t num_cores = core_thread_list.GetSize(false); + + // Make a map so we can keep track of which cores were used from the + // core_thread list. Any real threads/cores that weren't used should + // later be put back into the "new_thread_list". + std::vector<bool> core_used_map(num_cores, false); if (threads_list) { if (log) @@ -207,18 +214,26 @@ OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list, PythonDictionary thread_dict(threads_list.GetItemAtIndex(i)); if (thread_dict) { - ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_dict, core_thread_list, old_thread_list, NULL)); + ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_dict, core_thread_list, old_thread_list, core_used_map, NULL)); if (thread_sp) new_thread_list.AddThread(thread_sp); } } } } - - // No new threads added from the thread info array gotten from python, just - // display the core threads. - if (new_thread_list.GetSize(false) == 0) - new_thread_list = core_thread_list; + + // Any real core threads that didn't end up backing a memory thread should + // still be in the main thread list, and they should be inserted at the beginning + // of the list + uint32_t insert_idx = 0; + for (uint32_t core_idx = 0; core_idx < num_cores; ++core_idx) + { + if (core_used_map[core_idx] == false) + { + new_thread_list.InsertThread (core_thread_list.GetThreadAtIndex(core_idx, false), insert_idx); + ++insert_idx; + } + } return new_thread_list.GetSize(false) > 0; } @@ -227,6 +242,7 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo (PythonDictionary &thread_dict, ThreadList &core_thread_list, ThreadList &old_thread_list, + std::vector<bool> &core_used_map, bool *did_create_ptr) { ThreadSP thread_sp; @@ -282,6 +298,10 @@ OperatingSystemPython::CreateThreadFromThreadInfo (PythonDictionary &thread_dict ThreadSP core_thread_sp (core_thread_list.GetThreadAtIndex(core_number, false)); if (core_thread_sp) { + // Keep track of which cores were set as the backing thread for memory threads... + if (core_number < core_used_map.size()) + core_used_map[core_number] = true; + ThreadSP backing_core_thread_sp (core_thread_sp->GetBackingThread()); if (backing_core_thread_sp) { @@ -398,12 +418,13 @@ OperatingSystemPython::CreateThread (lldb::tid_t tid, addr_t context) auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure thread_info_dict stays alive PythonDictionary thread_info_dict (m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context)); + std::vector<bool> core_used_map; if (thread_info_dict) { ThreadList core_threads(m_process); ThreadList &thread_list = m_process->GetThreadList(); bool did_create = false; - ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_info_dict, core_threads, thread_list, &did_create)); + ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_info_dict, core_threads, thread_list, core_used_map, &did_create)); if (did_create) thread_list.AddThread(thread_sp); return thread_sp; diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h index 077039e50d56..3b7dd264dc62 100644 --- a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h +++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h @@ -93,6 +93,7 @@ protected: CreateThreadFromThreadInfo (lldb_private::PythonDictionary &thread_dict, lldb_private::ThreadList &core_thread_list, lldb_private::ThreadList &old_thread_list, + std::vector<bool> &core_used_map, bool *did_create_ptr); DynamicRegisterInfo * diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index da29c16ac3ab..7eca67ac7f57 100644 --- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -142,7 +142,8 @@ PlatformFreeBSD::Terminate () /// Default Constructor //------------------------------------------------------------------ PlatformFreeBSD::PlatformFreeBSD (bool is_host) : -Platform(is_host) +Platform(is_host), +m_remote_platform_sp() { } @@ -312,6 +313,7 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_64_x86_64: + case ArchSpec::eCore_x86_64_x86_64h: { static const uint8_t g_i386_opcode[] = { 0xCC }; trap_opcode = g_i386_opcode; @@ -571,14 +573,14 @@ PlatformFreeBSD::GetGroupName (uint32_t gid) // From PlatformMacOSX only Error -PlatformFreeBSD::GetFile (const FileSpec &platform_file, - const UUID *uuid_ptr, - FileSpec &local_file) +PlatformFreeBSD::GetFileWithUUID (const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file) { if (IsRemote()) { if (m_remote_platform_sp) - return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file); + return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file); } // Default to the local case @@ -673,3 +675,9 @@ PlatformFreeBSD::GetStatus (Stream &strm) Platform::GetStatus(strm); } + +void +PlatformFreeBSD::CalculateTrapHandlerSymbolNames () +{ + m_trap_handlers.push_back (ConstString ("_sigtramp")); +} diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h index 11d1cd609779..0682eacc5a43 100644 --- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h +++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h @@ -144,8 +144,8 @@ public: // Only on PlatformMacOSX: virtual lldb_private::Error - GetFile (const lldb_private::FileSpec &platform_file, - const lldb_private::UUID* uuid, lldb_private::FileSpec &local_file); + GetFileWithUUID (const lldb_private::FileSpec &platform_file, + const lldb_private::UUID* uuid, lldb_private::FileSpec &local_file); lldb_private::Error GetSharedModule (const lldb_private::ModuleSpec &module_spec, @@ -160,6 +160,9 @@ public: virtual void GetStatus (lldb_private::Stream &strm); + virtual void + CalculateTrapHandlerSymbolNames (); + protected: lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote freebsd OS diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index b5f92dcc3dcd..bb07d999c4c2 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -589,3 +589,8 @@ PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path) return Platform::SetRemoteWorkingDirectory(path); } +void +PlatformPOSIX::CalculateTrapHandlerSymbolNames () +{ + m_trap_handlers.push_back (ConstString ("_sigtramp")); +} diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 336e0f90fcad..130c84bdface 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -111,8 +111,11 @@ public: uint64_t &low, uint64_t &high); + virtual void + CalculateTrapHandlerSymbolNames (); + protected: - std::auto_ptr<lldb_private::OptionGroupOptions> m_options; + std::unique_ptr<lldb_private::OptionGroupOptions> m_options; lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote POSIX-compliant OS diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 248abaf6fea7..ce5645ea74fe 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -119,9 +119,9 @@ PlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file, } Error -PlatformRemoteGDBServer::GetFile (const FileSpec &platform_file, - const UUID *uuid_ptr, - FileSpec &local_file) +PlatformRemoteGDBServer::GetFileWithUUID (const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file) { // Default to the local case local_file = platform_file; @@ -418,7 +418,21 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid); + ArchSpec remote_arch = GetRemoteSystemArchitecture(); + llvm::Triple &remote_triple = remote_arch.GetTriple(); + uint16_t port = 0; + if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS) + { + // When remote debugging to iOS, we use a USB mux that always talks + // to localhost, so we will need the remote debugserver to accept connections + // only from localhost, no matter what our current hostname is + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost"); + } + else + { + // All other hosts should use their actual hostname + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL); + } if (port == 0) { @@ -492,7 +506,21 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid); + ArchSpec remote_arch = GetRemoteSystemArchitecture(); + llvm::Triple &remote_triple = remote_arch.GetTriple(); + uint16_t port = 0; + if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS) + { + // When remote debugging to iOS, we use a USB mux that always talks + // to localhost, so we will need the remote debugserver to accept connections + // only from localhost, no matter what our current hostname is + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost"); + } + else + { + // All other hosts should use their actual hostname + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL); + } if (port == 0) { @@ -673,3 +701,9 @@ PlatformRemoteGDBServer::RunShellCommand (const char *command, // Shou { return m_gdb_client.RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); } + +void +PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames () +{ + m_trap_handlers.push_back (ConstString ("_sigtramp")); +} diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 808fb5ed61cc..e236e97c8bb3 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -73,9 +73,9 @@ public: GetDescription (); virtual lldb_private::Error - GetFile (const lldb_private::FileSpec &platform_file, - const lldb_private::UUID *uuid_ptr, - lldb_private::FileSpec &local_file); + GetFileWithUUID (const lldb_private::FileSpec &platform_file, + const lldb_private::UUID *uuid_ptr, + lldb_private::FileSpec &local_file); virtual bool GetProcessInfo (lldb::pid_t pid, @@ -209,6 +209,9 @@ public: std::string *command_output, // Pass NULL if you don't want the command output uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish + virtual void + CalculateTrapHandlerSymbolNames (); + protected: GDBRemoteCommunicationClient m_gdb_client; std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp new file mode 100644 index 000000000000..493f36ca8b48 --- /dev/null +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp @@ -0,0 +1,69 @@ +//===-- FreeBSDThread.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/State.h" + +// Project includes +#include "FreeBSDThread.h" +#include "ProcessFreeBSD.h" +#include "ProcessPOSIXLog.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------------ +// Constructors and destructors. + +FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid) + : POSIXThread(process, tid) +{ +} + +FreeBSDThread::~FreeBSDThread() +{ +} + +//------------------------------------------------------------------------------ +// ProcessInterface protocol. + +void +FreeBSDThread::WillResume(lldb::StateType resume_state) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log) + log->Printf("tid %lu resume_state = %s", GetID(), + lldb_private::StateAsCString(resume_state)); + ProcessSP process_sp(GetProcess()); + ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get()); + int signo = GetResumeSignal(); + bool signo_valid = process->GetUnixSignals().SignalIsValid(signo); + + switch (resume_state) + { + case eStateSuspended: + case eStateStopped: + process->m_suspend_tids.push_back(GetID()); + break; + case eStateRunning: + process->m_run_tids.push_back(GetID()); + if (signo_valid) + process->m_resume_signo = signo; + break; + case eStateStepping: + process->m_step_tids.push_back(GetID()); + if (signo_valid) + process->m_resume_signo = signo; + break; + default: + break; + } +} diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.h b/source/Plugins/Process/FreeBSD/FreeBSDThread.h new file mode 100644 index 000000000000..8741075cb60b --- /dev/null +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.h @@ -0,0 +1,39 @@ +//===-- FreeBSDThread.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_FreeBSDThread_H_ +#define liblldb_FreeBSDThread_H_ + +// Other libraries and framework includes +#include "POSIXThread.h" + +//------------------------------------------------------------------------------ +// @class FreeBSDThread +// @brief Abstraction of a FreeBSD thread. +class FreeBSDThread + : public POSIXThread +{ +public: + + //------------------------------------------------------------------ + // Constructors and destructors + //------------------------------------------------------------------ + FreeBSDThread(lldb_private::Process &process, lldb::tid_t tid); + + virtual ~FreeBSDThread(); + + //-------------------------------------------------------------------------- + // FreeBSDThread internal API. + + // POSIXThread override + virtual void + WillResume(lldb::StateType resume_state); +}; + +#endif // #ifndef liblldb_FreeBSDThread_H_ diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index 952ec95f5873..083f08ebba84 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -23,7 +23,7 @@ #include "ProcessPOSIXLog.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" #include "ProcessMonitor.h" -#include "POSIXThread.h" +#include "FreeBSDThread.h" using namespace lldb; using namespace lldb_private; @@ -140,29 +140,136 @@ ProcessFreeBSD::DoDetach(bool keep_stopped) return error; } +Error +ProcessFreeBSD::DoResume() +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + + // FreeBSD's ptrace() uses 0 to indicate "no signal is to be sent." + int resume_signal = 0; + + SetPrivateState(eStateRunning); + + Mutex::Locker lock(m_thread_list.GetMutex()); + bool do_step = false; + + for (tid_collection::const_iterator t_pos = m_run_tids.begin(), t_end = m_run_tids.end(); t_pos != t_end; ++t_pos) + { + m_monitor->ThreadSuspend(*t_pos, false); + } + for (tid_collection::const_iterator t_pos = m_step_tids.begin(), t_end = m_step_tids.end(); t_pos != t_end; ++t_pos) + { + m_monitor->ThreadSuspend(*t_pos, false); + do_step = true; + } + for (tid_collection::const_iterator t_pos = m_suspend_tids.begin(), t_end = m_suspend_tids.end(); t_pos != t_end; ++t_pos) + { + m_monitor->ThreadSuspend(*t_pos, true); + // XXX Cannot PT_CONTINUE properly with suspended threads. + do_step = true; + } + + if (log) + log->Printf("process %lu resuming (%s)", GetID(), do_step ? "step" : "continue"); + if (do_step) + m_monitor->SingleStep(GetID(), resume_signal); + else + m_monitor->Resume(GetID(), resume_signal); + + return Error(); +} + bool ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) { - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("ProcessFreeBSD::%s() (pid = %" PRIu64 ")", __FUNCTION__, GetID()); - - bool has_updated = false; - const lldb::pid_t pid = GetID(); - // Update the process thread list with this new thread. - // FIXME: We should be using tid, not pid. - assert(m_monitor); - ThreadSP thread_sp (old_thread_list.FindThreadByID (pid, false)); - if (!thread_sp) { - ProcessSP me = this->shared_from_this(); - thread_sp.reset(new POSIXThread(*me, pid)); - has_updated = true; + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + if (log) + log->Printf("ProcessFreeBSD::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); + + std::vector<lldb::pid_t> tds; + if (!GetMonitor().GetCurrentThreadIDs(tds)) + { + return false; } - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("ProcessFreeBSD::%s() updated tid = %" PRIu64, __FUNCTION__, pid); + ThreadList old_thread_list_copy(old_thread_list); + for (size_t i = 0; i < tds.size(); ++i) + { + tid_t tid = tds[i]; + ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByID(tid, false)); + if (!thread_sp) + { + thread_sp.reset(new FreeBSDThread(*this, tid)); + if (log) + log->Printf("ProcessFreeBSD::%s new tid = %" PRIu64, __FUNCTION__, tid); + } + else + { + if (log) + log->Printf("ProcessFreeBSD::%s existing tid = %" PRIu64, __FUNCTION__, tid); + } + new_thread_list.AddThread(thread_sp); + } + for (size_t i = 0; i < old_thread_list_copy.GetSize(false); ++i) + { + ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false)); + if (old_thread_sp) + { + if (log) + log->Printf("ProcessFreeBSD::%s remove tid", __FUNCTION__); + } + } - new_thread_list.AddThread(thread_sp); + return true; +} - return has_updated; // the list has been updated +Error +ProcessFreeBSD::WillResume() +{ + m_suspend_tids.clear(); + m_run_tids.clear(); + m_step_tids.clear(); + return ProcessPOSIX::WillResume(); } + +void +ProcessFreeBSD::SendMessage(const ProcessMessage &message) +{ + Mutex::Locker lock(m_message_mutex); + + switch (message.GetKind()) + { + case ProcessMessage::eInvalidMessage: + return; + + case ProcessMessage::eAttachMessage: + SetPrivateState(eStateStopped); + return; + + case ProcessMessage::eLimboMessage: + case ProcessMessage::eExitMessage: + m_exit_status = message.GetExitStatus(); + SetExitStatus(m_exit_status, NULL); + break; + + case ProcessMessage::eSignalMessage: + case ProcessMessage::eSignalDeliveredMessage: + case ProcessMessage::eBreakpointMessage: + case ProcessMessage::eTraceMessage: + case ProcessMessage::eWatchpointMessage: + case ProcessMessage::eCrashMessage: + SetPrivateState(eStateStopped); + break; + + case ProcessMessage::eNewThreadMessage: + assert(0 && "eNewThreadMessage unexpected on FreeBSD"); + break; + + case ProcessMessage::eExecMessage: + SetPrivateState(eStateStopped); + break; + } + + m_message_queue.push(message); +} + diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h index fb549745b80c..d6ae3462c73b 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h @@ -60,6 +60,15 @@ public: virtual bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list); + virtual lldb_private::Error + DoResume(); + + virtual lldb_private::Error + WillResume(); + + virtual void + SendMessage(const ProcessMessage &message); + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -80,6 +89,16 @@ public: EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command); +protected: + friend class FreeBSDThread; + + typedef std::vector<lldb::tid_t> tid_collection; + tid_collection m_suspend_tids; + tid_collection m_run_tids; + tid_collection m_step_tids; + + int m_resume_signo; + }; -#endif // liblldb_MacOSXProcess_H_ +#endif // liblldb_ProcessFreeBSD_H_ diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index ac5357916501..3b260538b190 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -560,6 +560,31 @@ LwpInfoOperation::Execute(ProcessMonitor *monitor) } //------------------------------------------------------------------------------ +/// @class ThreadSuspendOperation +/// @brief Implements ProcessMonitor::ThreadSuspend. +class ThreadSuspendOperation : public Operation +{ +public: + ThreadSuspendOperation(lldb::tid_t tid, bool suspend, bool &result) + : m_tid(tid), m_suspend(suspend), m_result(result) { } + + void Execute(ProcessMonitor *monitor); + +private: + lldb::tid_t m_tid; + bool m_suspend; + bool &m_result; +} ; + +void +ThreadSuspendOperation::Execute(ProcessMonitor *monitor) +{ + m_result = !PTRACE(m_suspend ? PT_SUSPEND : PT_RESUME, m_tid, NULL, 0); +} + + + +//------------------------------------------------------------------------------ /// @class EventMessageOperation /// @brief Implements ProcessMonitor::GetEventMessage. class EventMessageOperation : public Operation @@ -871,7 +896,8 @@ ProcessMonitor::Launch(LaunchArgs *args) eDupStdoutFailed, eDupStderrFailed, eChdirFailed, - eExecFailed + eExecFailed, + eSetGidFailed }; // Child process. @@ -882,7 +908,8 @@ ProcessMonitor::Launch(LaunchArgs *args) exit(ePtraceFailed); // Do not inherit setgid powers. - setgid(getgid()); + if (setgid(getgid()) != 0) + exit(eSetGidFailed); // Let us have our own process group. setpgid(0, 0); @@ -947,6 +974,9 @@ ProcessMonitor::Launch(LaunchArgs *args) case eExecFailed: args->m_error.SetErrorString("Child exec failed."); break; + case eSetGidFailed: + args->m_error.SetErrorString("Child setgid failed."); + break; default: args->m_error.SetErrorString("Child returned unknown exit status."); break; @@ -1041,6 +1071,29 @@ FINISH: return args->m_error.Success(); } +size_t +ProcessMonitor::GetCurrentThreadIDs(std::vector<lldb::tid_t>&thread_ids) +{ + lwpid_t *tids; + int tdcnt; + + thread_ids.clear(); + + tdcnt = PTRACE(PT_GETNUMLWPS, m_pid, NULL, 0); + if (tdcnt <= 0) + return 0; + tids = (lwpid_t *)malloc(tdcnt * sizeof(*tids)); + if (tids == NULL) + return 0; + if (PTRACE(PT_GETLWPLIST, m_pid, (void *)tids, tdcnt) < 0) { + free(tids); + return 0; + } + thread_ids = std::vector<lldb::tid_t>(tids, tids + tdcnt); + free(tids); + return thread_ids.size(); +} + bool ProcessMonitor::MonitorCallback(void *callback_baton, lldb::pid_t pid, @@ -1073,11 +1126,11 @@ ProcessMonitor::MonitorCallback(void *callback_baton, switch (plwp.pl_siginfo.si_signo) { case SIGTRAP: - message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, pid); + message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, plwp.pl_lwpid); break; default: - message = MonitorSignal(monitor, &plwp.pl_siginfo, pid); + message = MonitorSignal(monitor, &plwp.pl_siginfo, plwp.pl_lwpid); break; } @@ -1090,7 +1143,7 @@ ProcessMonitor::MonitorCallback(void *callback_baton, ProcessMessage ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid) + const siginfo_t *info, lldb::tid_t tid) { ProcessMessage message; @@ -1111,26 +1164,26 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, // state of "limbo" until we are explicitly commanded to detach, // destroy, resume, etc. unsigned long data = 0; - if (!monitor->GetEventMessage(pid, &data)) + if (!monitor->GetEventMessage(tid, &data)) data = -1; if (log) - log->Printf ("ProcessMonitor::%s() received exit? event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid); - message = ProcessMessage::Limbo(pid, (data >> 8)); + log->Printf ("ProcessMonitor::%s() received exit? event, data = %lx, tid = %" PRIu64, __FUNCTION__, data, tid); + message = ProcessMessage::Limbo(tid, (data >> 8)); break; } case 0: case TRAP_TRACE: if (log) - log->Printf ("ProcessMonitor::%s() received trace event, pid = %" PRIu64, __FUNCTION__, pid); - message = ProcessMessage::Trace(pid); + log->Printf ("ProcessMonitor::%s() received trace event, tid = %" PRIu64, __FUNCTION__, tid); + message = ProcessMessage::Trace(tid); break; case SI_KERNEL: case TRAP_BRKPT: if (log) - log->Printf ("ProcessMonitor::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid); - message = ProcessMessage::Break(pid); + log->Printf ("ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64, __FUNCTION__, tid); + message = ProcessMessage::Break(tid); break; } @@ -1139,7 +1192,7 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, ProcessMessage ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid) + const siginfo_t *info, lldb::tid_t tid) { ProcessMessage message; int signo = info->si_signo; @@ -1163,9 +1216,9 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, "SI_USER", info->si_pid); if (info->si_pid == getpid()) - return ProcessMessage::SignalDelivered(pid, signo); + return ProcessMessage::SignalDelivered(tid, signo); else - return ProcessMessage::Signal(pid, signo); + return ProcessMessage::Signal(tid, signo); } if (log) @@ -1174,30 +1227,30 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, if (signo == SIGSEGV) { lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr); ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info); - return ProcessMessage::Crash(pid, reason, signo, fault_addr); + return ProcessMessage::Crash(tid, reason, signo, fault_addr); } if (signo == SIGILL) { lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr); ProcessMessage::CrashReason reason = GetCrashReasonForSIGILL(info); - return ProcessMessage::Crash(pid, reason, signo, fault_addr); + return ProcessMessage::Crash(tid, reason, signo, fault_addr); } if (signo == SIGFPE) { lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr); ProcessMessage::CrashReason reason = GetCrashReasonForSIGFPE(info); - return ProcessMessage::Crash(pid, reason, signo, fault_addr); + return ProcessMessage::Crash(tid, reason, signo, fault_addr); } if (signo == SIGBUS) { lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr); ProcessMessage::CrashReason reason = GetCrashReasonForSIGBUS(info); - return ProcessMessage::Crash(pid, reason, signo, fault_addr); + return ProcessMessage::Crash(tid, reason, signo, fault_addr); } // Everything else is "normal" and does not require any special action on // our part. - return ProcessMessage::Signal(pid, signo); + return ProcessMessage::Signal(tid, signo); } ProcessMessage::CrashReason @@ -1508,6 +1561,15 @@ ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &ptrace_err) } bool +ProcessMonitor::ThreadSuspend(lldb::tid_t tid, bool suspend) +{ + bool result; + ThreadSuspendOperation op(tid, suspend, result); + DoOperation(&op); + return result; +} + +bool ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message) { bool result; diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 44219c4eb9e3..84bbac16e5e5 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -104,8 +104,6 @@ public: /// dependent) offset. /// /// This method is provided for use by RegisterContextFreeBSD derivatives. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, unsigned size, lldb_private::RegisterValue &value); @@ -114,49 +112,35 @@ public: /// (architecture dependent) offset. /// /// This method is provided for use by RegisterContextFreeBSD derivatives. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, const lldb_private::RegisterValue &value); /// Reads all general purpose registers into the specified buffer. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size); /// Reads all floating point registers into the specified buffer. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size); /// Reads the specified register set into the specified buffer. /// /// This method is provided for use by RegisterContextFreeBSD derivatives. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); /// Writes all general purpose registers into the specified buffer. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size); /// Writes all floating point registers into the specified buffer. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size); /// Writes the specified register set into the specified buffer. /// /// This method is provided for use by RegisterContextFreeBSD derivatives. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); @@ -164,11 +148,19 @@ public: bool ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value); + /// Returns current thread IDs in process + size_t + GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids); + /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID /// to the memory region pointed to by @p lwpinfo. bool GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no); + /// Suspends or unsuspends a thread prior to process resume or step. + bool + ThreadSuspend(lldb::tid_t tid, bool suspend); + /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) /// corresponding to the given thread IDto the memory pointed to by @p /// message. diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp index 16399748c544..8d4c71ff269a 100644 --- a/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -83,6 +83,7 @@ POSIXThread::GetMonitor() return process.GetMonitor(); } +// Overridden by FreeBSDThread; this is used only on Linux. void POSIXThread::RefreshStateAfterStop() { @@ -150,8 +151,6 @@ POSIXThread::GetRegisterContext() { case ArchSpec::eCore_mips64: { - RegisterInfoInterface *reg_interface = NULL; - switch (target_arch.GetTriple().getOS()) { case llvm::Triple::FreeBSD: @@ -257,6 +256,7 @@ POSIXThread::GetUnwinder() return m_unwinder_ap.get(); } +// Overridden by FreeBSDThread; this is used only on Linux. void POSIXThread::WillResume(lldb::StateType resume_state) { diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index 70ad3a66d9ef..62394623c59d 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -200,7 +200,7 @@ ProcessPOSIX::GetFilePath( Error ProcessPOSIX::DoLaunch (Module *module, - const ProcessLaunchInfo &launch_info) + ProcessLaunchInfo &launch_info) { Error error; assert(m_monitor == NULL); @@ -632,20 +632,6 @@ ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr) return error; } -addr_t -ProcessPOSIX::ResolveIndirectFunction(const Address *address, Error &error) -{ - addr_t function_addr = LLDB_INVALID_ADDRESS; - if (address == NULL) { - error.SetErrorStringWithFormat("unable to determine direct function call for NULL address"); - } else if (!InferiorCall(this, address, function_addr)) { - function_addr = LLDB_INVALID_ADDRESS; - error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s", - address->CalculateSymbolContextSymbol()->GetName().AsCString()); - } - return function_addr; -} - size_t ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) { diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h index 790041be321a..7f705d33fe68 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -58,7 +58,7 @@ public: virtual lldb_private::Error DoLaunch (lldb_private::Module *exe_module, - const lldb_private::ProcessLaunchInfo &launch_info); + lldb_private::ProcessLaunchInfo &launch_info); virtual void DidLaunch(); @@ -104,9 +104,6 @@ public: virtual lldb_private::Error DoDeallocateMemory(lldb::addr_t ptr); - virtual lldb::addr_t - ResolveIndirectFunction(const lldb_private::Address *address, lldb_private::Error &error); - virtual size_t GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); @@ -148,7 +145,8 @@ public: // ProcessPOSIX internal API. /// Registers the given message with this process. - void SendMessage(const ProcessMessage &message); + virtual void + SendMessage(const ProcessMessage &message); ProcessMonitor & GetMonitor() { assert(m_monitor); return *m_monitor; } diff --git a/source/Plugins/Process/Utility/HistoryThread.cpp b/source/Plugins/Process/Utility/HistoryThread.cpp index 521136295fd5..d045bc7e10d7 100644 --- a/source/Plugins/Process/Utility/HistoryThread.cpp +++ b/source/Plugins/Process/Utility/HistoryThread.cpp @@ -25,7 +25,7 @@ HistoryThread::HistoryThread (lldb_private::Process &process, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid) : - Thread (process, LLDB_INVALID_THREAD_ID), + Thread (process, tid), m_framelist_mutex(), m_framelist(), m_pcs (pcs), diff --git a/source/Plugins/Process/Utility/HistoryThread.h b/source/Plugins/Process/Utility/HistoryThread.h index 01fdd1608706..f9a431d8340b 100644 --- a/source/Plugins/Process/Utility/HistoryThread.h +++ b/source/Plugins/Process/Utility/HistoryThread.h @@ -22,6 +22,16 @@ namespace lldb_private { +//---------------------------------------------------------------------- +/// @class HistoryThread HistoryThread.h "HistoryThread.h" +/// @brief A thread object representing a backtrace from a previous point in the process execution +/// +/// This subclass of Thread is used to provide a backtrace from earlier in +/// process execution. It is given a backtrace list of pc addresses and +/// optionally a stop_id of when those pc addresses were collected, and it will +/// create stack frames for them. +//---------------------------------------------------------------------- + class HistoryThread : public lldb_private::Thread { public: diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 6d1b04f7f1a7..1d5d19fad25f 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -34,9 +34,16 @@ using namespace lldb; using namespace lldb_private; -bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, - addr_t addr, addr_t length, unsigned prot, - unsigned flags, addr_t fd, addr_t offset) { +bool +lldb_private::InferiorCallMmap (Process *process, + addr_t &allocated_addr, + addr_t addr, + addr_t length, + unsigned prot, + unsigned flags, + addr_t fd, + addr_t offset) +{ Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL) return false; @@ -139,8 +146,11 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, return false; } -bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, - addr_t length) { +bool +lldb_private::InferiorCallMunmap (Process *process, + addr_t addr, + addr_t length) +{ Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL) return false; @@ -209,7 +219,14 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, return false; } -bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) { +// FIXME: This has nothing to do with Posix, it is just a convenience function that calls a +// function of the form "void * (*)(void)". We should find a better place to put this. + +bool +lldb_private::InferiorCall (Process *process, + const Address *address, + addr_t &returned_func) +{ Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL || address == NULL) return false; @@ -233,7 +250,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); if (call_plan_sp) { - StreamFile error_strm; + StreamString error_strm; // This plan is a utility plan, so set it to discard itself when done. call_plan_sp->SetIsMasterPlan (true); call_plan_sp->SetOkayToDiscard(true); diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index c19aec3a02c7..f87db5810740 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -21,15 +21,17 @@ #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" -#include "lldb/Target/DynamicLoader.h" #include "RegisterContextLLDB.h" @@ -75,13 +77,44 @@ RegisterContextLLDB::RegisterContextLLDB // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet if (IsFrameZero() - || next_frame->m_frame_type == eSigtrampFrame + || next_frame->m_frame_type == eTrapHandlerFrame || next_frame->m_frame_type == eDebuggerFrame) { m_all_registers_available = true; } } +bool +RegisterContextLLDB::IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset) +{ + if (!unwind_plan_sp) + return false; + + // check if m_current_pc is valid + if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) + { + // yes - current offset can be used as is + valid_pc_offset = m_current_offset; + return true; + } + + // if m_current_offset <= 0, we've got nothing else to try + if (m_current_offset <= 0) + return false; + + // check pc - 1 to see if it's valid + Address pc_minus_one (m_current_pc); + pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1); + if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one)) + { + // *valid_pc_offset = m_current_offset - 1; + valid_pc_offset = m_current_pc.GetOffset() - 1; + return true; + } + + return false; +} + // Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently // executing frame. @@ -95,6 +128,7 @@ RegisterContextLLDB::InitializeZerothFrame() if (reg_ctx_sp.get() == NULL) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("frame does not have a register context"); return; } @@ -103,6 +137,7 @@ RegisterContextLLDB::InitializeZerothFrame() if (current_pc == LLDB_INVALID_ADDRESS) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("frame does not have a pc"); return; } @@ -117,7 +152,7 @@ RegisterContextLLDB::InitializeZerothFrame() current_pc = abi->FixCodeAddress(current_pc); // Initialize m_current_pc, an Address object, based on current_pc, an addr_t. - process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_pc, m_current_pc); + m_current_pc.SetLoadAddress (current_pc, &process->GetTarget()); // If we don't have a Module for some reason, we're not going to find symbol/function information - just // stick in some reasonable defaults and hope we can unwind past this frame. @@ -137,11 +172,9 @@ RegisterContextLLDB::InitializeZerothFrame() AddressRange addr_range; m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range); - static ConstString g_sigtramp_name ("_sigtramp"); - if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) || - (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name)) + if (IsTrapHandlerSymbol (process, m_sym_ctx)) { - m_frame_type = eSigtrampFrame; + m_frame_type = eTrapHandlerFrame; } else { @@ -197,6 +230,7 @@ RegisterContextLLDB::InitializeZerothFrame() if (!active_row.get()) { + UnwindLogMsg ("could not find an unwindplan row for this frame's pc"); m_frame_type = eNotAValidFrame; return; } @@ -205,6 +239,7 @@ RegisterContextLLDB::InitializeZerothFrame() addr_t cfa_regval = LLDB_INVALID_ADDRESS; if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) { + UnwindLogMsg ("could not read CFA register for this frame."); m_frame_type = eNotAValidFrame; return; } @@ -229,17 +264,20 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (IsFrameZero ()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("non-zeroth frame tests positive for IsFrameZero -- that shouldn't happen."); return; } if (!GetNextFrame().get() || !GetNextFrame()->IsValid()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("Could not get next frame, marking this frame as invalid."); return; } if (!m_thread.GetRegisterContext()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("Could not get register context for this thread, marking this frame as invalid."); return; } @@ -265,6 +303,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (pc == 0) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("this frame has a pc of 0x0"); return; } @@ -276,7 +315,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (abi) pc = abi->FixCodeAddress(pc); - process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc); + m_current_pc.SetLoadAddress (pc, &process->GetTarget()); // If we don't have a Module for some reason, we're not going to find symbol/function information - just // stick in some reasonable defaults and hope we can unwind past this frame. @@ -304,6 +343,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() { // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now. m_frame_type = eNotAValidFrame; + UnwindLogMsg ("pc is in a non-executable section of memory and this isn't the 2nd frame in the stack walk."); return; } } @@ -352,6 +392,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() && (permissions & ePermissionsReadable) == 0) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("the CFA points to a region of memory that is not readable"); return; } } @@ -366,10 +407,15 @@ RegisterContextLLDB::InitializeNonZerothFrame() return; } m_frame_type = eNotAValidFrame; + UnwindLogMsg ("could not find any symbol for this pc, or a default unwind plan, to continue unwind."); return; } bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function... + // This will handle the case where the saved pc does not point to + // a function/symbol because it is beyond the bounds of the correct + // function and there's no symbol there. ResolveSymbolContextForAddress + // will fail to find a symbol, back up the pc by 1 and re-search. uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction | eSymbolContextSymbol, m_sym_ctx, resolve_tail_call_address); @@ -392,18 +438,35 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (m_sym_ctx_valid == false) decr_pc_and_recompute_addr_range = true; - // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), and - // our "current" pc is the start of a function or our "current" pc is one past the end of a function... + // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), + // and our "current" pc is the start of a function... if (m_sym_ctx_valid - && GetNextFrame()->m_frame_type != eSigtrampFrame + && GetNextFrame()->m_frame_type != eTrapHandlerFrame && GetNextFrame()->m_frame_type != eDebuggerFrame && addr_range.GetBaseAddress().IsValid() - && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()) + && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() + && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()) { - if (addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset() || - addr_range.GetBaseAddress().GetOffset() + addr_range.GetByteSize() == m_current_pc.GetOffset()) + decr_pc_and_recompute_addr_range = true; + } + + // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc" + // value is pointing to the next function, e.g. if a function ends with a CALL instruction. + // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function + // to the ABI plugin and consult that. + if (decr_pc_and_recompute_addr_range) + { + Address temporary_pc(m_current_pc); + temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); + m_sym_ctx.Clear(false); + m_sym_ctx_valid = false; + if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + { + m_sym_ctx_valid = true; + } + if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) { - decr_pc_and_recompute_addr_range = true; + m_sym_ctx_valid = false; } } @@ -428,11 +491,9 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_current_offset_backed_up_one = -1; } - static ConstString sigtramp_name ("_sigtramp"); - if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name) - || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name)) + if (IsTrapHandlerSymbol (process, m_sym_ctx)) { - m_frame_type = eSigtrampFrame; + m_frame_type = eTrapHandlerFrame; } else { @@ -467,9 +528,10 @@ RegisterContextLLDB::InitializeNonZerothFrame() else { m_full_unwind_plan_sp = GetFullUnwindPlanForFrame (); - if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + int valid_offset = -1; + if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset)) { - active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (valid_offset); row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); if (active_row.get() && log) { @@ -483,6 +545,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (!active_row.get()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("could not find unwind row for this pc"); return; } @@ -551,7 +614,7 @@ RegisterContextLLDB::IsFrameZero () const // // On entry to this method, // -// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct, // 2. m_sym_ctx should already be filled in, and // 3. m_current_pc should have the current pc value for this frame // 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -573,7 +636,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame () return unwind_plan_sp; // If we're in _sigtramp(), unwinding past this frame requires special knowledge. - if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame) + if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame) return unwind_plan_sp; unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread); @@ -602,7 +665,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame () // On entry to this method, // -// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct, // 2. m_sym_ctx should already be filled in, and // 3. m_current_pc should have the current pc value for this frame // 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -627,7 +690,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () bool behaves_like_zeroth_frame = false; if (IsFrameZero () - || GetNextFrame()->m_frame_type == eSigtrampFrame + || GetNextFrame()->m_frame_type == eTrapHandlerFrame || GetNextFrame()->m_frame_type == eDebuggerFrame) { behaves_like_zeroth_frame = true; @@ -648,7 +711,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () uint32_t permissions; addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()); if (current_pc_addr == 0 - || (process->GetLoadAddressPermissions(current_pc_addr, permissions) + || (process->GetLoadAddressPermissions (current_pc_addr, permissions) && (permissions & ePermissionsExecutable) == 0)) { unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); @@ -697,7 +760,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // is properly encoded in the eh_frame section, so prefer that if available. // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of // how to unwind out of sigtramp. - if (m_frame_type == eSigtrampFrame) + if (m_frame_type == eTrapHandlerFrame) { m_fast_unwind_plan_sp.reset(); unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); @@ -735,7 +798,8 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + int valid_offset = -1; + if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); return unwind_plan_sp; @@ -744,7 +808,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible. unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); return unwind_plan_sp; @@ -915,6 +979,12 @@ RegisterContextLLDB::IsValid () const return m_frame_type != eNotAValidFrame; } +bool +RegisterContextLLDB::IsTrapHandlerFrame () const +{ + return m_frame_type == eTrapHandlerFrame; +} + // A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther // up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after // frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the @@ -927,6 +997,35 @@ RegisterContextLLDB::IsSkipFrame () const return m_frame_type == eSkipFrame; } +bool +RegisterContextLLDB::IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const +{ + PlatformSP platform_sp (process->GetTarget().GetPlatform()); + if (platform_sp) + { + const std::vector<ConstString> trap_handler_names (platform_sp->GetTrapHandlerSymbolNames()); + for (ConstString name : trap_handler_names) + { + if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || + (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) + { + return true; + } + } + } + const std::vector<ConstString> user_specified_trap_handler_names (m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames()); + for (ConstString name : user_specified_trap_handler_names) + { + if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || + (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) + { + return true; + } + } + + return false; +} + // Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value? enum UnwindLLDB::RegisterSearchResult @@ -1161,7 +1260,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_cfa + offset; m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset", lldb_regnum); + UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset %d", lldb_regnum, offset); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } @@ -1171,7 +1270,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_cfa + offset; m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset", lldb_regnum); + UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset %d", lldb_regnum, offset); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } @@ -1550,3 +1649,4 @@ RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...) } } + diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h index dc6d8c61fa4a..bf9dd9a29319 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -73,6 +73,9 @@ public: IsValid () const; bool + IsTrapHandlerFrame () const; + + bool GetCFA (lldb::addr_t& cfa); bool @@ -86,7 +89,7 @@ private: enum FrameType { eNormalFrame, - eSigtrampFrame, + eTrapHandlerFrame, eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger eSkipFrame, // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack @@ -120,6 +123,19 @@ private: bool IsSkipFrame () const; + + //------------------------------------------------------------------ + /// Determines if a SymbolContext is a trap handler or not + /// + /// Given a SymbolContext, determines if this is a trap handler function + /// aka asynchronous signal handler. + /// + /// @return + /// Returns true if the SymbolContext is a trap handler. + //------------------------------------------------------------------ + bool + IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const; + // Provide a location for where THIS function saved the CALLER's register value // Or a frame "below" this one saved it, i.e. a function called by this one, preserved a register that this // function didn't modify/use. @@ -164,6 +180,10 @@ private: void UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); + bool + IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset); + + lldb_private::Thread& m_thread; /// diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index 552ae501bd21..a3a7002ea099 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -26,8 +26,21 @@ using namespace lldb_private; UnwindLLDB::UnwindLLDB (Thread &thread) : Unwind (thread), m_frames(), - m_unwind_complete(false) + m_unwind_complete(false), + m_user_supplied_trap_handler_functions() { + ProcessSP process_sp(thread.GetProcess()); + if (process_sp) + { + Args args; + process_sp->GetTarget().GetUserSpecifiedTrapHandlerNames (args); + size_t count = args.GetArgumentCount(); + for (size_t i = 0; i < count; i++) + { + const char *func_name = args.GetArgumentAtIndex(i); + m_user_supplied_trap_handler_functions.push_back (ConstString (func_name)); + } + } } uint32_t @@ -95,7 +108,13 @@ UnwindLLDB::AddFirstFrame () first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; m_frames.push_back (first_cursor_sp); return true; + unwind_done: + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + if (log) + { + log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); + } m_unwind_complete = true; return false; } @@ -138,7 +157,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } if (reg_ctx_sp.get() == NULL) + { + if (log) + log->Printf ("%*sFrame %d did not get a RegisterContext, stopping.", + cur_idx < 100 ? cur_idx : 100, "", cur_idx); goto unwind_done; + } if (!reg_ctx_sp->IsValid()) { @@ -160,12 +184,18 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa)) { - if (log) + // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not have + // its (constructed) CFA aligned correctly -- don't do the abi alignment check for + // these. + if (reg_ctx_sp->IsTrapHandlerFrame() == false) { - log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); + if (log) + { + log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", + cur_idx < 100 ? cur_idx : 100, "", cur_idx); + } + goto unwind_done; } - goto unwind_done; } if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc)) { @@ -185,12 +215,26 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } goto unwind_done; } + if (!m_frames.empty()) + { + // Infinite loop where the current cursor is the same as the previous one... + if (m_frames.back()->start_pc == cursor_sp->start_pc && m_frames.back()->cfa == cursor_sp->cfa) + { + if (log) + log->Printf ("th%d pc of this frame is the same as the previous frame and CFAs for both frames are identical -- stopping unwind", m_thread.GetIndexID()); + goto unwind_done; + } + } cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; m_frames.push_back (cursor_sp); return true; unwind_done: + if (log) + { + log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); + } m_unwind_complete = true; return false; } diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h index 5725654a6869..eb5400389df3 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.h +++ b/source/Plugins/Process/Utility/UnwindLLDB.h @@ -13,6 +13,7 @@ #include <vector> #include "lldb/lldb-public.h" +#include "lldb/Core/ConstString.h" #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/RegisterContext.h" @@ -90,6 +91,24 @@ protected: SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, uint32_t starting_frame_num, bool pc_register); + //------------------------------------------------------------------ + /// Provide the list of user-specified trap handler functions + /// + /// The Platform is one source of trap handler function names; that + /// may be augmented via a setting. The setting needs to be converted + /// into an array of ConstStrings before it can be used - we only want + /// to do that once per thread so it's here in the UnwindLLDB object. + /// + /// @return + /// Vector of ConstStrings of trap handler function names. May be + /// empty. + //------------------------------------------------------------------ + const std::vector<ConstString> & + GetUserSpecifiedTrapHandlerFunctionNames () + { + return m_user_supplied_trap_handler_functions; + } + private: struct Cursor @@ -110,6 +129,7 @@ private: // number of frames, etc. Otherwise we've only gone as far as directly asked, and m_frames.size() // is how far we've currently gone. + std::vector<ConstString> m_user_supplied_trap_handler_functions; bool AddOneMoreFrame (ABI *abi); bool AddFirstFrame (); diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 93641ede1bc7..7ea5c89e7df4 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -131,7 +131,8 @@ ProcessElfCore::AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *head VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() && - last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) + last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() && + last_entry->GetByteSize() == last_entry->data.GetByteSize()) { last_entry->SetRangeEnd (range_entry.GetRangeEnd()); last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd()); @@ -294,9 +295,13 @@ ProcessElfCore::DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error & size_t zero_fill_size = 0; // Padding lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address - if (file_end > offset) - bytes_left = file_end - offset; + // Figure out how many on-disk bytes remain in this segment + // starting at the given offset + if (file_end > file_start + offset) + bytes_left = file_end - (file_start + offset); + // Figure out how many bytes we need to zero-fill if we are + // reading more bytes than available in the on-disk segment if (bytes_to_read > bytes_left) { zero_fill_size = bytes_to_read - bytes_left; @@ -365,12 +370,12 @@ enum { // Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details. static void -ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data, +ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, ArchSpec &arch) { lldb::offset_t offset = 0; - bool have_padding = (arch.GetMachine() == llvm::Triple::mips64 || - arch.GetMachine() == llvm::Triple::x86_64); + bool lp64 = (arch.GetMachine() == llvm::Triple::mips64 || + arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); @@ -380,23 +385,26 @@ ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data, log->Printf("FreeBSD PRSTATUS unexpected version %d", pr_version); } - if (have_padding) - offset += 4; - offset += 28; // pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate - thread_data->signo = data.GetU32(&offset); // pr_cursig + // Skip padding, pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate + if (lp64) + offset += 32; + else + offset += 16; + + thread_data.signo = data.GetU32(&offset); // pr_cursig offset += 4; // pr_pid - if (have_padding) + if (lp64) offset += 4; size_t len = data.GetByteSize() - offset; - thread_data->gpregset = DataExtractor(data, offset, len); + thread_data.gpregset = DataExtractor(data, offset, len); } static void -ParseFreeBSDThrMisc(ThreadData *thread_data, DataExtractor &data) +ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data) { lldb::offset_t offset = 0; - thread_data->name = data.GetCStr(&offset, 20); + thread_data.name = data.GetCStr(&offset, 20); } /// Parse Thread context from PT_NOTE segment and store it in the thread list @@ -418,13 +426,13 @@ ParseFreeBSDThrMisc(ThreadData *thread_data, DataExtractor &data) /// For case (b) there may be either one NT_PRPSINFO per thread, or a single /// one that applies to all threads (depending on the platform type). void -ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header, +ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) { assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE); lldb::offset_t offset = 0; - ThreadData *thread_data = new ThreadData(); + std::unique_ptr<ThreadData> thread_data(new ThreadData); bool have_prstatus = false; bool have_prpsinfo = false; @@ -447,7 +455,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * assert(thread_data->gpregset.GetByteSize() > 0); // Add the new thread to thread list m_thread_data.push_back(*thread_data); - thread_data = new ThreadData(); + *thread_data = ThreadData(); have_prstatus = false; have_prpsinfo = false; } @@ -464,7 +472,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * { case NT_FREEBSD_PRSTATUS: have_prstatus = true; - ParseFreeBSDPrStatus(thread_data, note_data, arch); + ParseFreeBSDPrStatus(*thread_data, note_data, arch); break; case NT_FREEBSD_FPREGSET: thread_data->fpregset = note_data; @@ -473,7 +481,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * have_prpsinfo = true; break; case NT_FREEBSD_THRMISC: - ParseFreeBSDThrMisc(thread_data, note_data); + ParseFreeBSDThrMisc(*thread_data, note_data); break; case NT_FREEBSD_PROCSTAT_AUXV: // FIXME: FreeBSD sticks an int at the beginning of the note diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp index 610506c20a0b..3e09c7bc2032 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp @@ -63,8 +63,16 @@ RegisterContextCorePOSIX_x86_64::WriteFPR() bool RegisterContextCorePOSIX_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { - value = *(uint64_t *)(m_gpregset + reg_info->byte_offset); - return true; + switch (reg_info->byte_size) + { + case 4: + value = *(uint32_t *)(m_gpregset + reg_info->byte_offset); + return true; + case 8: + value = *(uint64_t *)(m_gpregset + reg_info->byte_offset); + return true; + } + return false; } bool diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 3bda86dc0f73..cadcf53ca543 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -17,6 +17,7 @@ #include "ThreadElfCore.h" #include "ProcessElfCore.h" #include "RegisterContextLinux_x86_64.h" +#include "RegisterContextFreeBSD_i386.h" #include "RegisterContextFreeBSD_mips64.h" #include "RegisterContextFreeBSD_x86_64.h" #include "RegisterContextPOSIXCore_mips64.h" @@ -85,45 +86,66 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get()); ArchSpec arch = process->GetArchitecture(); - switch (arch.GetMachine()) + RegisterInfoInterface *reg_interface = NULL; + + switch (arch.GetTriple().getOS()) { - case llvm::Triple::mips64: - switch (arch.GetTriple().getOS()) + case llvm::Triple::FreeBSD: + { + switch (arch.GetMachine()) { - case llvm::Triple::FreeBSD: - m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, new RegisterContextFreeBSD_mips64(arch), m_gpregset_data, m_fpregset_data)); + case llvm::Triple::mips64: + reg_interface = new RegisterContextFreeBSD_mips64(arch); + break; + case llvm::Triple::x86: + reg_interface = new RegisterContextFreeBSD_i386(arch); + break; + case llvm::Triple::x86_64: + reg_interface = new RegisterContextFreeBSD_x86_64(arch); break; default: - if (log) - log->Printf ("elf-core::%s:: OS(%d) not supported", - __FUNCTION__, arch.GetTriple().getOS()); - assert (false && "OS not supported"); break; } break; - case llvm::Triple::x86_64: - switch (arch.GetTriple().getOS()) + } + + case llvm::Triple::Linux: + { + switch (arch.GetMachine()) { - case llvm::Triple::FreeBSD: - m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, new RegisterContextFreeBSD_x86_64(arch), m_gpregset_data, m_fpregset_data)); - break; - case llvm::Triple::Linux: - m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, new RegisterContextLinux_x86_64(arch), m_gpregset_data, m_fpregset_data)); + case llvm::Triple::x86_64: + reg_interface = new RegisterContextLinux_x86_64(arch); break; default: - if (log) - log->Printf ("elf-core::%s:: OS(%d) not supported", - __FUNCTION__, arch.GetTriple().getOS()); - assert (false && "OS not supported"); break; } break; + } + + default: + break; + } + + if (!reg_interface) { + if (log) + log->Printf ("elf-core::%s:: Architecture(%d) or OS(%d) not supported", + __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS()); + assert (false && "Architecture or OS not supported"); + } + + switch (arch.GetMachine()) + { + case llvm::Triple::mips64: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; default: - if (log) - log->Printf ("elf-core::%s:: Architecture(%d) not supported", - __FUNCTION__, arch.GetMachine()); - assert (false && "Architecture not supported"); + break; } + reg_ctx_sp = m_thread_reg_ctx_sp; } else if (m_unwinder_ap.get()) diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index f67e1b5d49c3..1ec75a4bc7af 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -13,9 +13,11 @@ // C Includes #include <limits.h> #include <string.h> +#include <sys/stat.h> // C++ Includes // Other libraries and framework includes +#include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Log.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" @@ -143,7 +145,9 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, m_private_is_running (false), m_history (512), m_send_acks (true), - m_is_platform (is_platform) + m_is_platform (is_platform), + m_listen_thread (LLDB_INVALID_HOST_THREAD), + m_listen_url () { } @@ -195,14 +199,14 @@ GDBRemoteCommunication::SendNack () return bytes_written; } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length) { Mutex::Locker locker(m_sequence_mutex); return SendPacketNoLock (payload, payload_length); } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length) { if (IsConnected()) @@ -235,32 +239,32 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le if (bytes_written == packet.GetSize()) { if (GetSendAcks ()) - { - if (GetAck () != '+') - { - if (log) - log->Printf("get ack failed..."); - return 0; - } - } + return GetAck (); + else + return PacketResult::Success; } else { if (log) log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData()); } - return bytes_written; } - return 0; + return PacketResult::ErrorSendFailed; } -char +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck () { StringExtractorGDBRemote packet; - if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()) == 1) - return packet.GetChar(); - return 0; + PacketResult result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()); + if (result == PacketResult::Success) + { + if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck) + return PacketResult::Success; + else + return PacketResult::ErrorSendAck; + } + return result; } bool @@ -280,7 +284,7 @@ GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec) { uint8_t buffer[8192]; @@ -290,9 +294,10 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac // Check for a packet from our cache first without trying any reading... if (CheckForPacket (NULL, 0, packet)) - return packet.GetStringRef().size(); + return PacketResult::Success; bool timed_out = false; + bool disconnected = false; while (IsConnected() && !timed_out) { lldb::ConnectionStatus status = eConnectionStatusNoConnection; @@ -309,7 +314,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac if (bytes_read > 0) { if (CheckForPacket (buffer, bytes_read, packet)) - return packet.GetStringRef().size(); + return PacketResult::Success; } else { @@ -326,13 +331,19 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac case eConnectionStatusNoConnection: case eConnectionStatusLostConnection: case eConnectionStatusError: + disconnected = true; Disconnect(); break; } } } - packet.Clear (); - return 0; + packet.Clear (); + if (disconnected) + return PacketResult::ErrorDisconnected; + if (timed_out) + return PacketResult::ErrorReplyTimeout; + else + return PacketResult::ErrorReplyFailed; } bool @@ -538,18 +549,65 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri } Error -GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, - const char *unix_socket_name, // For handshaking - lldb_private::ProcessLaunchInfo &launch_info) +GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port) { Error error; + if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread)) + { + error.SetErrorString("listen thread already running"); + } + else + { + char listen_url[512]; + if (hostname && hostname[0]) + snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port); + else + snprintf(listen_url, sizeof(listen_url), "listen://%i", port); + m_listen_url = listen_url; + SetConnection(new ConnectionFileDescriptor()); + m_listen_thread = Host::ThreadCreate (listen_url, GDBRemoteCommunication::ListenThread, this, &error); + } + return error; +} + +bool +GDBRemoteCommunication::JoinListenThread () +{ + if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread)) + { + Host::ThreadJoin(m_listen_thread, NULL, NULL); + m_listen_thread = LLDB_INVALID_HOST_THREAD; + } + return true; +} + +lldb::thread_result_t +GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg) +{ + GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; + Error error; + ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection (); + + if (connection) + { + // Do the listen on another thread so we can continue on... + if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess) + comm->SetConnection(NULL); + } + return NULL; +} + +Error +GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, + uint16_t in_port, + lldb_private::ProcessLaunchInfo &launch_info, + uint16_t &out_port) +{ + out_port = in_port; + Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; - // This function will fill in the launch information for the debugserver - // instance that gets launched. - launch_info.Clear(); - char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); @@ -591,19 +649,88 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); - debugserver_args.AppendArgument(debugserver_url); + + // If a host and port is supplied then use it + char host_and_port[128]; + if (hostname) + { + snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); + debugserver_args.AppendArgument(host_and_port); + } + else + { + host_and_port[0] = '\0'; + } + // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); // make debugserver run in its own session so signals generated by // special terminal key sequences (^C) don't affect debugserver debugserver_args.AppendArgument("--setsid"); - - if (unix_socket_name && unix_socket_name[0]) + + char named_pipe_path[PATH_MAX]; + named_pipe_path[0] = '\0'; + + bool listen = false; + if (host_and_port[0]) { - debugserver_args.AppendArgument("--unix-socket"); - debugserver_args.AppendArgument(unix_socket_name); + // Create a temporary file to get the stdout/stderr and redirect the + // output of the command into this file. We will later read this file + // if all goes well and fill the data into "command_output_ptr" + + if (in_port == 0) + { + // Binding to port zero, we need to figure out what port it ends up + // using using a named pipe... + FileSpec tmpdir_file_spec; + if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + { + tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX"); + strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path)); + } + else + { + strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path)); + } + + if (::mktemp (named_pipe_path)) + { +#if defined(_MSC_VER) + if ( false ) +#else + if (::mkfifo(named_pipe_path, 0600) == 0) +#endif + { + debugserver_args.AppendArgument("--named-pipe"); + debugserver_args.AppendArgument(named_pipe_path); + } + } + } + else + { + listen = true; + } + } + else + { + // No host and port given, so lets listen on our end and make the debugserver + // connect to us.. + error = StartListenThread ("localhost", 0); + if (error.Fail()) + return error; + + ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); + out_port = connection->GetBoundPort(3); + assert (out_port != 0); + char port_cstr[32]; + snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port); + // Send the host and port down that debugserver and specify an option + // so that it connects back to the port we are listening to in this process + debugserver_args.AppendArgument("--reverse-connect"); + debugserver_args.AppendArgument(port_cstr); } + const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) { @@ -617,46 +744,41 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } - // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); - // debugserver_args.AppendArgument("--log-flags=0x802e0e"); - // We currently send down all arguments, attach pids, or attach - // process names in dedicated GDB server packets, so we don't need - // to pass them as arguments. This is currently because of all the - // things we need to setup prior to launching: the environment, - // current working dir, file actions, etc. -#if 0 - // Now append the program arguments - if (inferior_argv) + // Close STDIN, STDOUT and STDERR. We might need to redirect them + // to "/dev/null" if we run into any problems. + launch_info.AppendCloseFileAction (STDIN_FILENO); + launch_info.AppendCloseFileAction (STDOUT_FILENO); + launch_info.AppendCloseFileAction (STDERR_FILENO); + + error = Host::LaunchProcess(launch_info); + + if (named_pipe_path[0]) { - // Terminate the debugserver args so we can now append the inferior args - debugserver_args.AppendArgument("--"); - - for (int i = 0; inferior_argv[i] != NULL; ++i) - debugserver_args.AppendArgument (inferior_argv[i]); + File name_pipe_file; + error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); + if (error.Success()) + { + char port_cstr[256]; + port_cstr[0] = '\0'; + size_t num_bytes = sizeof(port_cstr); + error = name_pipe_file.Read(port_cstr, num_bytes); + assert (error.Success()); + assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); + out_port = Args::StringToUInt32(port_cstr, 0); + name_pipe_file.Close(); + } + Host::Unlink(named_pipe_path); } - else if (attach_pid != LLDB_INVALID_PROCESS_ID) + else if (listen) { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); - debugserver_args.AppendArgument (arg_cstr); + } - else if (attach_name && attach_name[0]) + else { - if (wait_for_launch) - debugserver_args.AppendArgument ("--waitfor"); - else - debugserver_args.AppendArgument ("--attach"); - debugserver_args.AppendArgument (attach_name); + // Make sure we actually connect with the debugserver... + JoinListenThread(); } -#endif - - // Close STDIN, STDOUT and STDERR. We might need to redirect them - // to "/dev/null" if we run into any problems. -// launch_info.AppendCloseFileAction (STDIN_FILENO); -// launch_info.AppendCloseFileAction (STDOUT_FILENO); -// launch_info.AppendCloseFileAction (STDERR_FILENO); - - error = Host::LaunchProcess(launch_info); } else { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index a1077957c6a6..d8361113ddc8 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -35,6 +35,19 @@ public: { eBroadcastBitRunPacketSent = kLoUserBroadcastBit }; + + enum class PacketResult + { + Success = 0, // Success + ErrorSendFailed, // Error sending the packet + ErrorSendAck, // Didn't get an ack back after sending a packet + ErrorReplyFailed, // Error getting the reply + ErrorReplyTimeout, // Timed out waiting for reply + ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that was sent + ErrorReplyAck, // Sending reply ack failed + ErrorDisconnected, // We were disconnected + ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request + }; //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ @@ -45,7 +58,7 @@ public: virtual ~GDBRemoteCommunication(); - char + PacketResult GetAck (); size_t @@ -109,9 +122,10 @@ public: // supplied connection URL. //------------------------------------------------------------------ lldb_private::Error - StartDebugserverProcess (const char *connect_url, - const char *unix_socket_name, - lldb_private::ProcessLaunchInfo &launch_info); + StartDebugserverProcess (const char *hostname, + uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit + lldb_private::ProcessLaunchInfo &launch_info, + uint16_t &out_port); void DumpHistory(lldb_private::Stream &strm); @@ -223,15 +237,15 @@ protected: mutable bool m_dumped_to_log; }; - size_t + PacketResult SendPacket (const char *payload, size_t payload_length); - size_t + PacketResult SendPacketNoLock (const char *payload, size_t payload_length); - size_t + PacketResult WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response, uint32_t timeout_usec); @@ -242,7 +256,7 @@ protected: // Classes that inherit from GDBRemoteCommunication can see and modify these //------------------------------------------------------------------ uint32_t m_packet_timeout; -#ifdef LLDB_CONFIGURATION_DEBUG +#ifdef ENABLE_MUTEX_ERROR_CHECKING lldb_private::TrackingMutex m_sequence_mutex; #else lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time @@ -256,9 +270,22 @@ protected: // a single process + lldb_private::Error + StartListenThread (const char *hostname = "localhost", + uint16_t port = 0); + + bool + JoinListenThread (); + static lldb::thread_result_t + ListenThread (lldb::thread_arg_t arg); private: + + lldb::thread_t m_listen_thread; + std::string m_listen_url; + + //------------------------------------------------------------------ // For GDBRemoteCommunication only //------------------------------------------------------------------ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 2690992eeed3..aa60ec1b4a27 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -66,6 +66,9 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_prepare_for_reg_writing_reply (eLazyBoolCalculate), m_supports_p (eLazyBoolCalculate), m_supports_QSaveRegisterState (eLazyBoolCalculate), + m_supports_qXfer_libraries_read (eLazyBoolCalculate), + m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate), + m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -84,6 +87,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_async_mutex (Mutex::eMutexTypeRecursive), m_async_packet_predicate (false), m_async_packet (), + m_async_result (PacketResult::Success), m_async_response (), m_async_signal (-1), m_thread_id_to_used_usec_map (), @@ -95,7 +99,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_os_build (), m_os_kernel (), m_hostname (), - m_default_packet_timeout (0) + m_default_packet_timeout (0), + m_max_packet_size (0) { } @@ -117,6 +122,14 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) // fail to send the handshake ack, there is no reason to continue... if (SendAck()) { + // Wait for any responses that might have been queued up in the remote + // GDB server and flush them all + StringExtractorGDBRemote response; + PacketResult packet_result = PacketResult::Success; + const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response + while (packet_result == PacketResult::Success) + packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec); + // The return value from QueryNoAckModeSupported() is true if the packet // was sent and _any_ response (including UNIMPLEMENTED) was received), // or false if no response was received. This quickly tells us if we have @@ -140,6 +153,46 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) } bool +GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported () +{ + if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return (m_supports_augmented_libraries_svr4_read == eLazyBoolYes); +} + +bool +GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported () +{ + if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return (m_supports_qXfer_libraries_svr4_read == eLazyBoolYes); +} + +bool +GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported () +{ + if (m_supports_qXfer_libraries_read == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return (m_supports_qXfer_libraries_read == eLazyBoolYes); +} + +uint64_t +GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() +{ + if (m_max_packet_size == 0) + { + GetRemoteQSupported(); + } + return m_max_packet_size; +} + +bool GDBRemoteCommunicationClient::QueryNoAckModeSupported () { if (m_supports_not_sending_acks == eLazyBoolCalculate) @@ -148,7 +201,7 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported () m_supports_not_sending_acks = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false)) + if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { @@ -169,7 +222,7 @@ GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported () m_supports_threads_in_stop_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false)) + if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_threads_in_stop_reply = eLazyBoolYes; @@ -185,7 +238,7 @@ GDBRemoteCommunicationClient::GetVAttachOrWaitSupported () m_attach_or_wait_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false)) + if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_attach_or_wait_reply = eLazyBoolYes; @@ -205,7 +258,7 @@ GDBRemoteCommunicationClient::GetSyncThreadStateSupported () m_prepare_for_reg_writing_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false)) + if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_prepare_for_reg_writing_reply = eLazyBoolYes; @@ -236,6 +289,9 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_memory_region_info = eLazyBoolCalculate; m_prepare_for_reg_writing_reply = eLazyBoolCalculate; m_attach_or_wait_reply = eLazyBoolCalculate; + m_supports_qXfer_libraries_read = eLazyBoolCalculate; + m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; + m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; m_supports_qProcessInfoPID = true; m_supports_qfProcessInfo = true; @@ -251,8 +307,50 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_QEnvironmentHexEncoded = true; m_host_arch.Clear(); m_process_arch.Clear(); + + m_max_packet_size = 0; } +void +GDBRemoteCommunicationClient::GetRemoteQSupported () +{ + // Clear out any capabilities we expect to see in the qSupported response + m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; + m_supports_qXfer_libraries_read = eLazyBoolNo; + m_supports_augmented_libraries_svr4_read = eLazyBoolNo; + m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qSupported", + response, + /*send_async=*/false) == PacketResult::Success) + { + const char *response_cstr = response.GetStringRef().c_str(); + if (::strstr (response_cstr, "qXfer:libraries-svr4:read+")) + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; + if (::strstr (response_cstr, "augmented-libraries-svr4-read")) + { + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied + m_supports_augmented_libraries_svr4_read = eLazyBoolYes; + } + if (::strstr (response_cstr, "qXfer:libraries:read+")) + m_supports_qXfer_libraries_read = eLazyBoolYes; + + const char *packet_size_str = ::strstr (response_cstr, "PacketSize="); + if (packet_size_str) + { + StringExtractorGDBRemote packet_response(packet_size_str + strlen("PacketSize=")); + m_max_packet_size = packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); + if (m_max_packet_size == 0) + { + m_max_packet_size = UINT64_MAX; // Must have been a garbled response + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + if (log) + log->Printf ("Garbled PacketSize spec in qSupported response"); + } + } + } +} bool GDBRemoteCommunicationClient::GetThreadSuffixSupported () @@ -261,7 +359,7 @@ GDBRemoteCommunicationClient::GetThreadSuffixSupported () { StringExtractorGDBRemote response; m_supports_thread_suffix = eLazyBoolNo; - if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false)) + if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_thread_suffix = eLazyBoolYes; @@ -281,7 +379,7 @@ GDBRemoteCommunicationClient::GetVContSupported (char flavor) m_supports_vCont_C = eLazyBoolNo; m_supports_vCont_s = eLazyBoolNo; m_supports_vCont_S = eLazyBoolNo; - if (SendPacketAndWaitForResponse("vCont?", response, false)) + if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().c_str(); if (::strstr (response_cstr, ";c")) @@ -345,7 +443,7 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) else snprintf(packet, sizeof(packet), "p0"); - if (SendPacketAndWaitForResponse(packet, response, false)) + if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsNormalResponse()) m_supports_p = eLazyBoolYes; @@ -354,7 +452,63 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) return m_supports_p; } -size_t +GDBRemoteCommunicationClient::PacketResult +GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses +( + const char *payload_prefix, + std::string &response_string +) +{ + Mutex::Locker locker; + if (!GetSequenceMutex(locker, + "ProcessGDBRemote::SendPacketsAndConcatenateResponses() failed due to not getting the sequence mutex")) + { + Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); + if (log) + log->Printf("error: failed to get packet sequence mutex, not sending packets with prefix '%s'", + payload_prefix); + return PacketResult::ErrorNoSequenceLock; + } + + response_string = ""; + std::string payload_prefix_str(payload_prefix); + unsigned int response_size = 0x1000; + if (response_size > GetRemoteMaxPacketSize()) { // May send qSupported packet + response_size = GetRemoteMaxPacketSize(); + } + + for (unsigned int offset = 0; true; offset += response_size) + { + StringExtractorGDBRemote this_response; + // Construct payload + char sizeDescriptor[128]; + snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset, response_size); + PacketResult result = SendPacketAndWaitForResponse((payload_prefix_str + sizeDescriptor).c_str(), + this_response, + /*send_async=*/false); + if (result != PacketResult::Success) + return result; + + const std::string &this_string = this_response.GetStringRef(); + + // Check for m or l as first character; l seems to mean this is the last chunk + char first_char = *this_string.c_str(); + if (first_char != 'm' && first_char != 'l') + { + return PacketResult::ErrorReplyInvalid; + } + // Skip past m or l + const char *s = this_string.c_str() + 1; + + // Concatenate the result so far + response_string += s; + if (first_char == 'l') + // We're done + return PacketResult::Success; + } +} + +GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketAndWaitForResponse ( const char *payload, @@ -368,7 +522,18 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse send_async); } -size_t +GDBRemoteCommunicationClient::PacketResult +GDBRemoteCommunicationClient::SendPacketAndWaitForResponseNoLock (const char *payload, + size_t payload_length, + StringExtractorGDBRemote &response) +{ + PacketResult packet_result = SendPacketNoLock (payload, payload_length); + if (packet_result == PacketResult::Success) + packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); + return packet_result; +} + +GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketAndWaitForResponse ( const char *payload, @@ -377,18 +542,13 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse bool send_async ) { + PacketResult packet_result = PacketResult::ErrorSendFailed; Mutex::Locker locker; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); size_t response_len = 0; if (GetSequenceMutex (locker)) { - if (SendPacketNoLock (payload, payload_length)) - response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); - else - { - if (log) - log->Printf("error: failed to send '%*s'", (int) payload_length, payload); - } + packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); } else { @@ -424,6 +584,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse // Swap the response buffer to avoid malloc and string copy response.GetStringRef().swap (m_async_response.GetStringRef()); response_len = response.GetStringRef().size(); + packet_result = m_async_result; } else { @@ -456,13 +617,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse if (log) log->Printf ("async: got lock without sending interrupt"); // Send the packet normally since we got the lock - if (SendPacketNoLock (payload, payload_length)) - response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); - else - { - if (log) - log->Printf("error: failed to send '%*s'", (int) payload_length, payload); - } + packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); } } else @@ -483,12 +638,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload); } } - if (response_len == 0) - { - if (log) - log->Printf("error: failed to get response for '%*s'", (int) payload_length, payload); - } - return response_len; + return packet_result; } static const char *end_delimiter = "--end--;"; @@ -615,7 +765,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse { if (log) log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); - if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) == 0) + if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) state = eStateInvalid; m_private_is_running.SetValue (true, eBroadcastAlways); @@ -626,7 +776,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse if (log) log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%s)", __FUNCTION__, continue_packet.c_str()); - if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX)) + if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX) == PacketResult::Success) { if (response.Empty()) state = eStateInvalid; @@ -683,7 +833,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse // packet to make sure it doesn't get in the way StringExtractorGDBRemote extra_stop_reply_packet; uint32_t timeout_usec = 1000; - if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec)) + if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec) == PacketResult::Success) { switch (extra_stop_reply_packet.GetChar()) { @@ -747,11 +897,12 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); // We are supposed to send an asynchronous packet while - // we are running. + // we are running. m_async_response.Clear(); if (m_async_packet.empty()) { - if (packet_log) + m_async_result = PacketResult::ErrorSendFailed; + if (packet_log) packet_log->Printf ("async: error: empty async packet"); } @@ -760,10 +911,10 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse if (packet_log) packet_log->Printf ("async: sending packet"); - SendPacketAndWaitForResponse (&m_async_packet[0], - m_async_packet.size(), - m_async_response, - false); + m_async_result = SendPacketAndWaitForResponse (&m_async_packet[0], + m_async_packet.size(), + m_async_response, + false); } // Let the other thread that was trying to send the async // packet know that the packet has been sent and response is @@ -973,7 +1124,7 @@ lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID () { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false)) + if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success) { if (response.GetChar() == 'Q') if (response.GetChar() == 'C') @@ -987,7 +1138,7 @@ GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) { error_str.clear(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false)) + if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -1050,7 +1201,7 @@ GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &laun } StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1097,7 +1248,7 @@ GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_valu { packet.PutCString("QEnvironmentHexEncoded:"); packet.PutBytesAsRawHex8 (name_equal_value, strlen(name_equal_value)); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1113,7 +1264,7 @@ GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_valu else if (m_supports_QEnvironment) { packet.Printf("QEnvironment:%s", name_equal_value); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1136,7 +1287,7 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) StreamString packet; packet.Printf("QLaunchArch:%s", arch); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1236,7 +1387,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { m_qHostInfo_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qHostInfo", response, false)) + if (SendPacketAndWaitForResponse ("qHostInfo", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { @@ -1248,6 +1399,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) std::string os_name; std::string vendor_name; std::string triple; + std::string distribution_id; uint32_t pointer_byte_size = 0; StringExtractor extractor; ByteOrder byte_order = eByteOrderInvalid; @@ -1281,6 +1433,13 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) extractor.GetHexByteString (triple); ++num_keys_decoded; } + else if (name.compare ("distribution_id") == 0) + { + extractor.GetStringRef ().swap (value); + extractor.SetFilePos (0); + extractor.GetHexByteString (distribution_id); + ++num_keys_decoded; + } else if (name.compare("os_build") == 0) { extractor.GetStringRef().swap(value); @@ -1455,7 +1614,9 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { assert (byte_order == m_host_arch.GetByteOrder()); } - } + } + if (!distribution_id.empty ()) + m_host_arch.SetDistributionId (distribution_id.c_str ()); } } } @@ -1474,7 +1635,7 @@ GDBRemoteCommunicationClient::SendAttach char packet[64]; const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, pid); assert (packet_len < (int)sizeof(packet)); - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsErrorResponse()) return response.GetError(); @@ -1514,7 +1675,7 @@ GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) permissions & lldb::ePermissionsExecutable ? "x" : ""); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (!response.IsErrorResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); @@ -1537,7 +1698,7 @@ GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr) const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -1563,7 +1724,7 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped) const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:"); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { m_supports_detach_stay_stopped = eLazyBoolYes; } @@ -1580,15 +1741,15 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped) } else { - size_t num_sent = SendPacket ("D1", 2); - if (num_sent == 0) + PacketResult packet_result = SendPacket ("D1", 2); + if (packet_result != PacketResult::Success) error.SetErrorString ("Sending extended disconnect packet failed."); } } else { - size_t num_sent = SendPacket ("D", 1); - if (num_sent == 0) + PacketResult packet_result = SendPacket ("D", 1); + if (packet_result != PacketResult::Success) error.SetErrorString ("Sending disconnect packet failed."); } return error; @@ -1608,7 +1769,7 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr, const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { std::string name; std::string value; @@ -1711,7 +1872,7 @@ GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num) const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { m_supports_watchpoint_support_info = eLazyBoolYes; std::string name; @@ -1773,7 +1934,7 @@ GDBRemoteCommunicationClient::SetSTDIN (char const *path) packet.PutBytesAsRawHex8(path, strlen(path)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1795,7 +1956,7 @@ GDBRemoteCommunicationClient::SetSTDOUT (char const *path) packet.PutBytesAsRawHex8(path, strlen(path)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1817,7 +1978,7 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path) packet.PutBytesAsRawHex8(path, strlen(path)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1833,7 +1994,7 @@ bool GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd) { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false)) + if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) return false; @@ -1855,7 +2016,7 @@ GDBRemoteCommunicationClient::SetWorkingDir (char const *path) packet.PutBytesAsRawHex8(path, strlen(path)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1874,7 +2035,7 @@ GDBRemoteCommunicationClient::SetDisableASLR (bool enable) const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDisableASLR:%i", enable ? 1 : 0); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1893,6 +2054,11 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot std::string name; std::string value; StringExtractor extractor; + + uint32_t cpu = LLDB_INVALID_CPUTYPE; + uint32_t sub = 0; + std::string vendor; + std::string os_type; while (response.GetNameColonValue(name, value)) { @@ -1938,6 +2104,32 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot extractor.GetHexByteString (value); process_info.GetExecutableFile().SetFile (value.c_str(), false); } + else if (name.compare("cputype") == 0) + { + cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); + } + else if (name.compare("cpusubtype") == 0) + { + sub = Args::StringToUInt32 (value.c_str(), 0, 16); + } + else if (name.compare("vendor") == 0) + { + vendor = value; + } + else if (name.compare("ostype") == 0) + { + os_type = value; + } + } + + if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty()) + { + if (vendor == "apple") + { + process_info.GetArchitecture().SetArchitecture (eArchTypeMachO, cpu, sub); + process_info.GetArchitecture().GetTriple().setVendorName (llvm::StringRef (vendor)); + process_info.GetArchitecture().GetTriple().setOSName (llvm::StringRef (os_type)); + } } if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) @@ -1957,7 +2149,7 @@ GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceIn const int packet_len = ::snprintf (packet, sizeof (packet), "qProcessInfoPID:%" PRIu64, pid); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { return DecodeProcessInfoResponse (response, process_info); } @@ -1981,7 +2173,7 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () GetHostInfo (); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qProcessInfo", response, false)) + if (SendPacketAndWaitForResponse ("qProcessInfo", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { @@ -2141,7 +2333,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat } } StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { do { @@ -2151,7 +2343,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat process_infos.Append(process_info); response.GetStringRef().clear(); response.SetFilePos(0); - } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false)); + } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false) == PacketResult::Success); } else { @@ -2172,7 +2364,7 @@ GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name) const int packet_len = ::snprintf (packet, sizeof (packet), "qUserName:%i", uid); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { @@ -2202,7 +2394,7 @@ GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name) const int packet_len = ::snprintf (packet, sizeof (packet), "qGroupName:%i", gid); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { @@ -2296,32 +2488,36 @@ GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t } StringExtractorGDBRemote response; - return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) > 0; - return false; + return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success; } uint16_t -GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid) +GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname) { pid = LLDB_INVALID_PROCESS_ID; StringExtractorGDBRemote response; StreamString stream; stream.PutCString("qLaunchGDBServer;"); std::string hostname; - if (Host::GetHostname (hostname)) - { - // Make the GDB server we launch only accept connections from this host - stream.Printf("host:%s;", hostname.c_str()); - } + if (remote_accept_hostname && remote_accept_hostname[0]) + hostname = remote_accept_hostname; else { - // Make the GDB server we launch accept connections from any host since we can't figure out the hostname - stream.Printf("host:*;"); + if (Host::GetHostname (hostname)) + { + // Make the GDB server we launch only accept connections from this host + stream.Printf("host:%s;", hostname.c_str()); + } + else + { + // Make the GDB server we launch accept connections from any host since we can't figure out the hostname + stream.Printf("host:*;"); + } } const char *packet = stream.GetData(); int packet_len = stream.GetSize(); - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { std::string name; std::string value; @@ -2347,7 +2543,7 @@ GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid) int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -2369,7 +2565,7 @@ GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid) packet_len = ::snprintf (packet, sizeof(packet), "Hg%" PRIx64, tid); assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { @@ -2395,7 +2591,7 @@ GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid) assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { @@ -2409,7 +2605,7 @@ GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid) bool GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response) { - if (SendPacketAndWaitForResponse("?", 1, response, false)) + if (SendPacketAndWaitForResponse("?", 1, response, false) == PacketResult::Success) return response.IsNormalResponse(); return false; } @@ -2422,7 +2618,7 @@ GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtracto char packet[256]; int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid); assert (packet_len < (int)sizeof(packet)); - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_qThreadStopInfo = false; @@ -2463,7 +2659,7 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, true)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, true) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -2497,9 +2693,10 @@ GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thr sequence_mutex_unavailable = false; StringExtractorGDBRemote response; - for (SendPacketNoLock ("qfThreadInfo", strlen("qfThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); - response.IsNormalResponse(); - SendPacketNoLock ("qsThreadInfo", strlen("qsThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ())) + PacketResult packet_result; + for (packet_result = SendPacketAndWaitForResponseNoLock ("qfThreadInfo", strlen("qfThreadInfo"), response); + packet_result == PacketResult::Success && response.IsNormalResponse(); + packet_result = SendPacketAndWaitForResponseNoLock ("qsThreadInfo", strlen("qsThreadInfo"), response)) { char ch = response.GetChar(); if (ch == 'l') @@ -2539,7 +2736,7 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr() if (!IsRunning()) { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false)) + if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false) == PacketResult::Success) { if (response.IsNormalResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); @@ -2569,7 +2766,7 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, // const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return Error("malformed reply"); @@ -2608,7 +2805,7 @@ GDBRemoteCommunicationClient::MakeDirectory (const char *path, const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); } @@ -2628,7 +2825,7 @@ GDBRemoteCommunicationClient::SetFilePermissions (const char *path, const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); } @@ -2679,7 +2876,7 @@ GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec, const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return ParseHostIOPacketResponse (response, UINT64_MAX, error); } @@ -2695,7 +2892,7 @@ GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd, const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return ParseHostIOPacketResponse (response, -1, error) == 0; } @@ -2713,7 +2910,7 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return UINT64_MAX; @@ -2733,7 +2930,7 @@ GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &fil const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') { @@ -2780,7 +2977,7 @@ GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd, const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return 0; @@ -2819,7 +3016,7 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') { @@ -2861,7 +3058,7 @@ GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst) const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() == 'F') { @@ -2902,7 +3099,7 @@ GDBRemoteCommunicationClient::Unlink (const char *path) const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() == 'F') { @@ -2942,7 +3139,7 @@ GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_ const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return false; @@ -2966,7 +3163,7 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return false; @@ -2998,7 +3195,7 @@ GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, String else packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); assert (packet_len < ((int)sizeof(packet) - 1)); - return SendPacketAndWaitForResponse(packet, response, false); + return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; } } return false; @@ -3024,7 +3221,7 @@ GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractor else packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); - return SendPacketAndWaitForResponse(packet, response, false); + return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; } } return false; @@ -3051,7 +3248,7 @@ GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false)) + if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) { @@ -3094,7 +3291,7 @@ GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t sa StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false)) + if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 564afbb2911c..a1e982b3ec4e 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -47,17 +47,38 @@ public: bool HandshakeWithServer (lldb_private::Error *error_ptr); - size_t + PacketResult SendPacketAndWaitForResponse (const char *send_payload, StringExtractorGDBRemote &response, bool send_async); - size_t + PacketResult SendPacketAndWaitForResponse (const char *send_payload, size_t send_length, StringExtractorGDBRemote &response, bool send_async); + // For packets which specify a range of output to be returned, + // return all of the output via a series of request packets of the form + // <prefix>0,<size> + // <prefix><size>,<size> + // <prefix><size>*2,<size> + // <prefix><size>*3,<size> + // ... + // until a "$l..." packet is received, indicating the end. + // (size is in hex; this format is used by a standard gdbserver to + // return the given portion of the output specified by <prefix>; + // for example, "qXfer:libraries-svr4:read::fff,1000" means + // "return a chunk of the xml description file for shared + // library load addresses, where the chunk starts at offset 0xfff + // and continues for 0x1000 bytes"). + // Concatenate the resulting server response packets together and + // return in response_string. If any packet fails, the return value + // indicates that failure and the returned string value is undefined. + PacketResult + SendPacketsAndConcatenateResponses (const char *send_payload_prefix, + std::string &response_string); + lldb::StateType SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process, const char *packet_payload, @@ -94,7 +115,7 @@ public: GetLaunchSuccess (std::string &error_str); uint16_t - LaunchGDBserverAndGetPort (lldb::pid_t &pid); + LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname); bool KillSpawnedProcess (lldb::pid_t pid); @@ -248,6 +269,9 @@ public: const lldb_private::ArchSpec & GetProcessArchitecture (); + void + GetRemoteQSupported(); + bool GetVContSupported (char flavor); @@ -359,6 +383,18 @@ public: bool SetCurrentThreadForRun (uint64_t tid); + bool + GetQXferLibrariesReadSupported (); + + bool + GetQXferLibrariesSVR4ReadSupported (); + + uint64_t + GetRemoteMaxPacketSize(); + + bool + GetAugmentedLibrariesSVR4ReadSupported (); + lldb_private::LazyBool SupportsAllocDeallocMemory () // const { @@ -458,6 +494,11 @@ public: protected: + PacketResult + SendPacketAndWaitForResponseNoLock (const char *payload, + size_t payload_length, + StringExtractorGDBRemote &response); + bool GetCurrentProcessInfo (); @@ -484,7 +525,10 @@ protected: lldb_private::LazyBool m_prepare_for_reg_writing_reply; lldb_private::LazyBool m_supports_p; lldb_private::LazyBool m_supports_QSaveRegisterState; - + lldb_private::LazyBool m_supports_qXfer_libraries_read; + lldb_private::LazyBool m_supports_qXfer_libraries_svr4_read; + lldb_private::LazyBool m_supports_augmented_libraries_svr4_read; + bool m_supports_qProcessInfoPID:1, m_supports_qfProcessInfo:1, @@ -511,6 +555,7 @@ protected: lldb_private::Mutex m_async_mutex; lldb_private::Predicate<bool> m_async_packet_predicate; std::string m_async_packet; + PacketResult m_async_result; StringExtractorGDBRemote m_async_response; int m_async_signal; // We were asked to deliver a signal to the inferior process. bool m_interrupt_sent; @@ -526,6 +571,7 @@ protected: std::string m_os_kernel; std::string m_hostname; uint32_t m_default_packet_timeout; + uint64_t m_max_packet_size; // as returned by qSupported bool DecodeProcessInfoResponse (StringExtractorGDBRemote &response, diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 7cc3a05304d4..df95542d2c0f 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -25,6 +25,7 @@ #include "lldb/Host/File.h" #include "lldb/Host/Host.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" // Project includes @@ -40,6 +41,7 @@ using namespace lldb_private; //---------------------------------------------------------------------- GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), + m_platform_sp (Platform::GetDefaultPlatform ()), m_async_thread (LLDB_INVALID_HOST_THREAD), m_process_launch_info (), m_process_launch_error (), @@ -52,6 +54,23 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : { } +GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform, + const lldb::PlatformSP& platform_sp) : + GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), + m_platform_sp (platform_sp), + m_async_thread (LLDB_INVALID_HOST_THREAD), + m_process_launch_info (), + m_process_launch_error (), + m_spawned_pids (), + m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), + m_proc_infos (), + m_proc_infos_index (0), + m_port_map (), + m_port_offset(0) +{ + assert(platform_sp); +} + //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- @@ -90,154 +109,249 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, bool &quit) { StringExtractorGDBRemote packet; - if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec)) + PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec); + if (packet_result == PacketResult::Success) { const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType (); switch (packet_type) { - case StringExtractorGDBRemote::eServerPacketType_nack: - case StringExtractorGDBRemote::eServerPacketType_ack: - break; - - case StringExtractorGDBRemote::eServerPacketType_invalid: - error.SetErrorString("invalid packet"); - quit = true; - break; - - case StringExtractorGDBRemote::eServerPacketType_interrupt: - error.SetErrorString("interrupt received"); - interrupt = true; - break; + case StringExtractorGDBRemote::eServerPacketType_nack: + case StringExtractorGDBRemote::eServerPacketType_ack: + break; + + case StringExtractorGDBRemote::eServerPacketType_invalid: + error.SetErrorString("invalid packet"); + quit = true; + break; + + case StringExtractorGDBRemote::eServerPacketType_interrupt: + error.SetErrorString("interrupt received"); + interrupt = true; + break; + + default: + case StringExtractorGDBRemote::eServerPacketType_unimplemented: + packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); + break; - case StringExtractorGDBRemote::eServerPacketType_unimplemented: - return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0; + case StringExtractorGDBRemote::eServerPacketType_A: + packet_result = Handle_A (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_A: - return Handle_A (packet); + case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: + packet_result = Handle_qfProcessInfo (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: - return Handle_qfProcessInfo (packet); + case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: + packet_result = Handle_qsProcessInfo (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: - return Handle_qsProcessInfo (packet); + case StringExtractorGDBRemote::eServerPacketType_qC: + packet_result = Handle_qC (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qC: - return Handle_qC (packet); + case StringExtractorGDBRemote::eServerPacketType_qHostInfo: + packet_result = Handle_qHostInfo (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qHostInfo: - return Handle_qHostInfo (packet); + case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer: + packet_result = Handle_qLaunchGDBServer (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer: - return Handle_qLaunchGDBServer (packet); + case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess: + packet_result = Handle_qKillSpawnedProcess (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess: - return Handle_qKillSpawnedProcess (packet); + case StringExtractorGDBRemote::eServerPacketType_k: + packet_result = Handle_k (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: - return Handle_qLaunchSuccess (packet); + case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: + packet_result = Handle_qLaunchSuccess (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qGroupName: - return Handle_qGroupName (packet); + case StringExtractorGDBRemote::eServerPacketType_qGroupName: + packet_result = Handle_qGroupName (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: + packet_result = Handle_qProcessInfoPID (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qSpeedTest: + packet_result = Handle_qSpeedTest (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qUserName: + packet_result = Handle_qUserName (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: + packet_result = Handle_qGetWorkingDir(packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QEnvironment: + packet_result = Handle_QEnvironment (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QLaunchArch: + packet_result = Handle_QLaunchArch (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR: + packet_result = Handle_QSetDisableASLR (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: + packet_result = Handle_QSetSTDIN (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT: + packet_result = Handle_QSetSTDOUT (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR: + packet_result = Handle_QSetSTDERR (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir: + packet_result = Handle_QSetWorkingDir (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: + packet_result = Handle_QStartNoAckMode (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: + packet_result = Handle_qPlatform_mkdir (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: + packet_result = Handle_qPlatform_chmod (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell: + packet_result = Handle_qPlatform_shell (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: - return Handle_qProcessInfoPID (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_open: + packet_result = Handle_vFile_Open (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qSpeedTest: - return Handle_qSpeedTest (packet); - - case StringExtractorGDBRemote::eServerPacketType_qUserName: - return Handle_qUserName (packet); - - case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: - return Handle_qGetWorkingDir(packet); - - case StringExtractorGDBRemote::eServerPacketType_QEnvironment: - return Handle_QEnvironment (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_close: + packet_result = Handle_vFile_Close (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QLaunchArch: - return Handle_QLaunchArch (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_pread: + packet_result = Handle_vFile_pRead (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR: - return Handle_QSetDisableASLR (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: + packet_result = Handle_vFile_pWrite (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: - return Handle_QSetSTDIN (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_size: + packet_result = Handle_vFile_Size (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT: - return Handle_QSetSTDOUT (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_mode: + packet_result = Handle_vFile_Mode (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR: - return Handle_QSetSTDERR (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_exists: + packet_result = Handle_vFile_Exists (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir: - return Handle_QSetWorkingDir (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_stat: + packet_result = Handle_vFile_Stat (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: - return Handle_QStartNoAckMode (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_md5: + packet_result = Handle_vFile_MD5 (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: - return Handle_qPlatform_mkdir (packet); - - case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: - return Handle_qPlatform_chmod (packet); - - case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell: - return Handle_qPlatform_shell (packet); - - case StringExtractorGDBRemote::eServerPacketType_vFile_open: - return Handle_vFile_Open (packet); - - case StringExtractorGDBRemote::eServerPacketType_vFile_close: - return Handle_vFile_Close (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: + packet_result = Handle_vFile_symlink (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: + packet_result = Handle_vFile_unlink (packet); + break; + } + } + else + { + if (!IsConnected()) + { + error.SetErrorString("lost connection"); + quit = true; + } + else + { + error.SetErrorString("timeout"); + } + } + return packet_result == PacketResult::Success; +} - case StringExtractorGDBRemote::eServerPacketType_vFile_pread: - return Handle_vFile_pRead (packet); +lldb_private::Error +GDBRemoteCommunicationServer::SetLaunchArguments (const char *const args[], int argc) +{ + if ((argc < 1) || !args || !args[0] || !args[0][0]) + return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); - case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: - return Handle_vFile_pWrite (packet); + m_process_launch_info.SetArguments (const_cast<const char**> (args), true); + return lldb_private::Error (); +} - case StringExtractorGDBRemote::eServerPacketType_vFile_size: - return Handle_vFile_Size (packet); +lldb_private::Error +GDBRemoteCommunicationServer::SetLaunchFlags (unsigned int launch_flags) +{ + m_process_launch_info.GetFlags ().Set (launch_flags); + return lldb_private::Error (); +} - case StringExtractorGDBRemote::eServerPacketType_vFile_mode: - return Handle_vFile_Mode (packet); +lldb_private::Error +GDBRemoteCommunicationServer::LaunchProcess () +{ + if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) + return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); - case StringExtractorGDBRemote::eServerPacketType_vFile_exists: - return Handle_vFile_Exists (packet); + // specify the process monitor if not already set. This should + // generally be what happens since we need to reap started + // processes. + if (!m_process_launch_info.GetMonitorProcessCallback ()) + m_process_launch_info.SetMonitorProcessCallback(ReapDebuggedProcess, this, false); - case StringExtractorGDBRemote::eServerPacketType_vFile_stat: - return Handle_vFile_Stat (packet); + lldb_private::Error error = m_platform_sp->LaunchProcess (m_process_launch_info); + if (!error.Success ()) + { + fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); + return error; + } - case StringExtractorGDBRemote::eServerPacketType_vFile_md5: - return Handle_vFile_MD5 (packet); + printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID()); - case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: - return Handle_vFile_symlink (packet); - - case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: - return Handle_vFile_unlink (packet); - } - return true; - } - else + // add to list of spawned processes. On an lldb-gdbserver, we + // would expect there to be only one. + lldb::pid_t pid; + if ( (pid = m_process_launch_info.GetProcessID()) != LLDB_INVALID_PROCESS_ID ) { - if (!IsConnected()) - error.SetErrorString("lost connection"); - else - error.SetErrorString("timeout"); + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(pid); } - return false; + return error; } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) { // TODO: Log the packet we aren't handling... return SendPacketNoLock ("", 0); } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) { char packet[16]; @@ -247,7 +361,7 @@ GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendOKResponse () { return SendPacketNoLock ("OK", 2); @@ -256,10 +370,10 @@ GDBRemoteCommunicationServer::SendOKResponse () bool GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr) { - return GetAck(); + return GetAck() == PacketResult::Success; } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet) { StreamString response; @@ -272,6 +386,14 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); + const char* distribution_id = host_arch.GetDistributionId ().AsCString (); + if (distribution_id) + { + response.PutCString("distribution_id:"); + response.PutCStringAsRawHex8(distribution_id); + response.PutCString(";"); + } + uint32_t cpu = host_arch.GetMachOCPUType(); uint32_t sub = host_arch.GetMachOCPUSubType(); if (cpu != LLDB_INVALID_CPUTYPE) @@ -351,7 +473,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet } #endif // #if defined(__APPLE__) - return SendPacketNoLock (response.GetData(), response.GetSize()) > 0; + return SendPacketNoLock (response.GetData(), response.GetSize()); } static void @@ -377,7 +499,7 @@ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &r } } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) { // Packet format: "qProcessInfoPID:%i" where %i is the pid @@ -396,7 +518,7 @@ GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote & return SendErrorResponse (1); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; @@ -497,7 +619,7 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa return SendErrorResponse (3); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet) { if (m_proc_infos_index < m_proc_infos.GetSize()) @@ -510,7 +632,7 @@ GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &pa return SendErrorResponse (4); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet) { // Packet format: "qUserName:%i" where %i is the uid @@ -530,7 +652,7 @@ GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet) { // Packet format: "qGroupName:%i" where %i is the gid @@ -549,7 +671,7 @@ GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packe return SendErrorResponse (6); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("qSpeedTest:")); @@ -641,7 +763,7 @@ AcceptPortFromInferior (void *arg) // return false; //} -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) { // The 'A' packet is the most over designed packet ever here with @@ -708,8 +830,11 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) if (success) { + // FIXME: remove linux restriction once eLaunchFlagDebug is supported +#if !defined (__linux__) m_process_launch_info.GetFlags().Set (eLaunchFlagDebug); - m_process_launch_error = Host::LaunchProcess (m_process_launch_info); +#endif + m_process_launch_error = LaunchProcess (); if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { return SendOKResponse (); @@ -718,7 +843,7 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) return SendErrorResponse (8); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet) { lldb::pid_t pid = m_process_launch_info.GetProcessID(); @@ -762,11 +887,30 @@ GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton, } bool +GDBRemoteCommunicationServer::DebuggedProcessReaped (lldb::pid_t pid) +{ + // reap a process that we were debugging (but not debugserver) + Mutex::Locker locker (m_spawned_pids_mutex); + return m_spawned_pids.erase(pid) > 0; +} + +bool +GDBRemoteCommunicationServer::ReapDebuggedProcess (void *callback_baton, + lldb::pid_t pid, + bool exited, + int signal, // Zero for no signal + int status) // Exit value of process if signal is zero +{ + GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton; + server->DebuggedProcessReaped (pid); + return true; +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) { #ifdef _WIN32 - // No unix sockets on windows - return false; + return SendErrorResponse(9); #else // Spawn a local debugserver as a platform so we can then attach or launch // a process... @@ -775,7 +919,6 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote { // Sleep and wait a bit for debugserver to start to listen... ConnectionFileDescriptor file_conn; - char connect_url[PATH_MAX]; Error error; std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp @@ -796,45 +939,23 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). - lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD; - const char *unix_socket_name = NULL; - char unix_socket_name_buf[PATH_MAX] = "/tmp/XXXXXXXXX"; - - if (port == 0) - { - if (::mkstemp (unix_socket_name_buf) == 0) - { - unix_socket_name = unix_socket_name_buf; - ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); - accept_thread = Host::ThreadCreate (unix_socket_name, - AcceptPortFromInferior, - connect_url, - &error); - } - else - { - error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno)); - } - } if (error.Success()) { // Spawn a debugserver and try to get the port it listens to. ProcessLaunchInfo debugserver_launch_info; - StreamString host_and_port; if (hostname.empty()) hostname = "localhost"; - host_and_port.Printf("%s:%u", hostname.c_str(), port); - const char *host_and_port_cstr = host_and_port.GetString().c_str(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) - log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); + log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port); debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); - error = StartDebugserverProcess (host_and_port_cstr, - unix_socket_name, - debugserver_launch_info); + error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(), + port, + debugserver_launch_info, + port); lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); @@ -854,45 +975,17 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote if (error.Success()) { - bool success = false; + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + assert (response_len < sizeof(response)); + PacketResult packet_result = SendPacketNoLock (response, response_len); - if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) - { - thread_result_t accept_thread_result = NULL; - if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) - { - if (accept_thread_result) - { - port = (intptr_t)accept_thread_result; - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; - } - } - } - else - { - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; - - } - Host::Unlink (unix_socket_name); - - if (!success) + if (packet_result != PacketResult::Success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) ::kill (debugserver_pid, SIGINT); } - return success; - } - else if (accept_thread) - { - Host::Unlink (unix_socket_name); + return packet_result; } } } @@ -901,59 +994,124 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote } bool -GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid) { - // Spawn a local debugserver as a platform so we can then attach or launch - // a process... - - if (m_is_platform) + // make sure we know about this process { - packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return false; + } - lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); + // first try a SIGTERM (standard kill) + Host::Kill (pid, SIGTERM); - // Scope for locker + // check if that worked + for (size_t i=0; i<10; ++i) + { { Mutex::Locker locker (m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return SendErrorResponse (10); + { + // it is now killed + return true; + } } - Host::Kill (pid, SIGTERM); + usleep (10000); + } + + // check one more time after the final usleep + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } + + // the launched process still lives. Now try killling it again, + // this time with an unblockable signal. + Host::Kill (pid, SIGKILL); - for (size_t i=0; i<10; ++i) + for (size_t i=0; i<10; ++i) + { { - // Scope for locker + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return SendOKResponse(); + // it is now killed + return true; } - usleep (10000); } + usleep (10000); + } + + // check one more time after the final usleep + // Scope for locker + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } + + // no luck - the process still lives + return false; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); + + lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); - // Scope for locker + // verify that we know anything about this pid. + // Scope for locker + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return SendOKResponse(); + // not a pid we know about + return SendErrorResponse (10); } - Host::Kill (pid, SIGKILL); + } + + // go ahead and attempt to kill the spawned process + if (KillSpawnedProcess (pid)) + return SendOKResponse (); + else + return SendErrorResponse (11); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet) +{ + // ignore for now if we're lldb_platform + if (m_is_platform) + return SendUnimplementedResponse (packet.GetStringRef().c_str()); - for (size_t i=0; i<10; ++i) + // shutdown all spawned processes + std::set<lldb::pid_t> spawned_pids_copy; + + // copy pids + { + Mutex::Locker locker (m_spawned_pids_mutex); + spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ()); + } + + // nuke the spawned processes + for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it) + { + lldb::pid_t spawned_pid = *it; + if (!KillSpawnedProcess (spawned_pid)) { - // Scope for locker - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return SendOKResponse(); - } - usleep (10000); + fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid); } } - return SendErrorResponse (11); + + // TODO figure out how to shut down gracefully at this point + return SendOKResponse (); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet) { if (m_process_launch_error.Success()) @@ -964,7 +1122,7 @@ GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &p return SendPacketNoLock (response.GetData(), response.GetSize()); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QEnvironment:")); @@ -977,7 +1135,7 @@ GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &pa return SendErrorResponse (12); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QLaunchArch:")); @@ -992,7 +1150,7 @@ GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &pack return SendErrorResponse(13); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetDisableASLR:")); @@ -1003,7 +1161,7 @@ GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote & return SendOKResponse (); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetWorkingDir:")); @@ -1027,7 +1185,7 @@ GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &p return SendOKResponse (); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) { StreamString response; @@ -1043,8 +1201,7 @@ GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &p else { response.PutBytesAsRawHex8(cwd, strlen(cwd)); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendPacketNoLock(response.GetData(), response.GetSize()); } } else @@ -1053,8 +1210,7 @@ GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &p if (working_dir && working_dir[0]) { response.PutBytesAsRawHex8(working_dir, strlen(working_dir)); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendPacketNoLock(response.GetData(), response.GetSize()); } else { @@ -1063,7 +1219,7 @@ GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &p } } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDIN:")); @@ -1080,7 +1236,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet return SendErrorResponse (15); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDOUT:")); @@ -1097,7 +1253,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packe return SendErrorResponse (16); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDERR:")); @@ -1114,16 +1270,16 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe return SendErrorResponse (17); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) { // Send response first before changing m_send_acks to we ack this packet - SendOKResponse (); + PacketResult packet_result = SendOKResponse (); m_send_acks = false; - return true; + return packet_result; } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_mkdir:")); @@ -1141,7 +1297,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote & return SendErrorResponse(20); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_chmod:")); @@ -1160,7 +1316,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote & return SendErrorResponse(19); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:open:")); @@ -1176,7 +1332,6 @@ GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packe mode_t mode = packet.GetHexMaxU32(false, 0600); Error error; int fd = ::open (path.c_str(), flags, mode); - printf ("open('%s', flags=0x%x, mode=%o) fd = %i (%s)\n", path.c_str(), flags, mode, fd, fd == -1 ? strerror(errno) : "<success>"); const int save_errno = fd == -1 ? errno : 0; StreamString response; response.PutChar('F'); @@ -1190,7 +1345,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packe return SendErrorResponse(18); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:close:")); @@ -1215,7 +1370,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &pack return SendPacketNoLock(response.GetData(), response.GetSize()); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet) { #ifdef _WIN32 @@ -1257,7 +1412,7 @@ GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &pack #endif } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) { #ifdef _WIN32 @@ -1294,7 +1449,7 @@ GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &pac #endif } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:size:")); @@ -1316,7 +1471,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packe return SendErrorResponse(22); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:mode:")); @@ -1335,7 +1490,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packe return SendErrorResponse(23); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:exists:")); @@ -1356,7 +1511,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac return SendErrorResponse(24); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:symlink:")); @@ -1370,7 +1525,7 @@ GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &pa return SendPacketNoLock(response.GetData(), response.GetSize()); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:unlink:")); @@ -1382,7 +1537,7 @@ GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &pac return SendPacketNoLock(response.GetData(), response.GetSize()); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_shell:")); @@ -1424,13 +1579,13 @@ GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote & return SendErrorResponse(24); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet) { return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented"); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:MD5:")); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 721ea5012b33..913c6b673cfb 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -37,6 +37,9 @@ public: //------------------------------------------------------------------ GDBRemoteCommunicationServer(bool is_platform); + GDBRemoteCommunicationServer(bool is_platform, + const lldb::PlatformSP& platform_sp); + virtual ~GDBRemoteCommunicationServer(); @@ -138,7 +141,55 @@ public: m_port_offset = port_offset; } + //------------------------------------------------------------------ + /// Specify the program to launch and its arguments. + /// + /// The LaunchProcess () command can be executed to do the lauching. + /// + /// @param[in] args + /// The command line to launch. + /// + /// @param[in] argc + /// The number of elements in the args array of cstring pointers. + /// + /// @return + /// An Error object indicating the success or failure of making + /// the setting. + //------------------------------------------------------------------ + lldb_private::Error + SetLaunchArguments (const char *const args[], int argc); + + //------------------------------------------------------------------ + /// Specify the launch flags for the process. + /// + /// The LaunchProcess () command can be executed to do the lauching. + /// + /// @param[in] launch_flags + /// The launch flags to use when launching this process. + /// + /// @return + /// An Error object indicating the success or failure of making + /// the setting. + //------------------------------------------------------------------ + lldb_private::Error + SetLaunchFlags (unsigned int launch_flags); + + //------------------------------------------------------------------ + /// Launch a process with the current launch settings. + /// + /// This method supports running an lldb-gdbserver or similar + /// server in a situation where the startup code has been provided + /// with all the information for a child process to be launched. + /// + /// @return + /// An Error object indicating the success or failure of the + /// launch. + //------------------------------------------------------------------ + lldb_private::Error + LaunchProcess (); + protected: + lldb::PlatformSP m_platform_sp; lldb::thread_t m_async_thread; lldb_private::ProcessLaunchInfo m_process_launch_info; lldb_private::Error m_process_launch_error; @@ -148,120 +199,123 @@ protected: uint32_t m_proc_infos_index; PortMap m_port_map; uint16_t m_port_offset; - - size_t + + PacketResult SendUnimplementedResponse (const char *packet); - size_t + PacketResult SendErrorResponse (uint8_t error); - size_t + PacketResult SendOKResponse (); - bool + PacketResult Handle_A (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qLaunchSuccess (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qHostInfo (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); - bool + PacketResult + Handle_k (StringExtractorGDBRemote &packet); + + PacketResult Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qfProcessInfo (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qsProcessInfo (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qC (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qUserName (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qGroupName (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qSpeedTest (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QEnvironment (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QLaunchArch (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetDisableASLR (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QStartNoAckMode (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetSTDIN (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetSTDOUT (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetSTDERR (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Open (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Close (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_pRead (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_pWrite (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Size (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Mode (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Exists (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_symlink (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_unlink (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Stat (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_MD5 (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qPlatform_shell (StringExtractorGDBRemote &packet); private: @@ -275,6 +329,19 @@ private: int signal, int status); + bool + DebuggedProcessReaped (lldb::pid_t pid); + + static bool + ReapDebuggedProcess (void *callback_baton, + lldb::pid_t pid, + bool exited, + int signal, + int status); + + bool + KillSpawnedProcess (lldb::pid_t pid); + //------------------------------------------------------------------ // For GDBRemoteCommunicationServer only //------------------------------------------------------------------ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index c291df786d10..73b9b3e8267e 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -275,7 +275,7 @@ GDBRemoteRegisterContext::SetPrimordialRegister(const lldb_private::RegisterInfo if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -298,7 +298,7 @@ GDBRemoteRegisterContext::SyncThreadState(Process *process) if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) InvalidateAllRegisters(); @@ -363,7 +363,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo * if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { SetAllRegisterValid (false); if (response.IsOKResponse()) @@ -519,7 +519,7 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsErrorResponse()) return false; @@ -591,7 +591,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data if (gdb_comm.SendPacketAndWaitForResponse (G_packet, G_packet_len, response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -660,7 +660,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) ++num_restored; diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 7f1fbefc1b7e..e1989eb1dd14 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -34,7 +34,6 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" -#include "lldb/Core/InputReader.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -95,7 +94,7 @@ using namespace lldb_private; namespace { - + static PropertyDefinition g_properties[] = { @@ -187,7 +186,7 @@ get_random_port () if (!rand_initialized) { time_t seed = time(NULL); - + rand_initialized = true; srand(seed); } @@ -386,7 +385,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { response_type = response.GetResponseType(); if (response_type == StringExtractorGDBRemote::eResponse) @@ -537,6 +536,10 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); } + else + { + break; // ensure exit before reg_num is incremented + } } else { @@ -645,13 +648,20 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) // We have a valid process SetID (pid); GetThreadList(); - if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false)) + if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success) { - if (!m_target.GetArchitecture().IsValid()) { // Make sure we have an architecture - m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + if (!m_target.GetArchitecture().IsValid()) + { + if (m_gdb_comm.GetProcessArchitecture().IsValid()) + { + m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + } + else + { + m_target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); + } } - const StateType state = SetThreadStopInfo (m_last_stop_packet); if (state == eStateStopped) { @@ -690,7 +700,7 @@ ProcessGDBRemote::WillLaunchOrAttach () // Process Control //---------------------------------------------------------------------- Error -ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_info) +ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) { Error error; @@ -728,23 +738,10 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_ ObjectFile * object_file = exe_module->GetObjectFile(); if (object_file) { - char host_port[128]; - snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); - char connect_url[128]; - snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); - // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - error = StartDebugserverProcess (host_port, launch_info); - if (error.Fail()) - { - if (log) - log->Printf("failed to start debugserver process: %s", error.AsCString()); - return error; - } - - error = ConnectToDebugserver (connect_url); + error = LaunchAndConnectToDebugserver (launch_info); } if (error.Success()) @@ -848,10 +845,18 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_ return error; } - if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false)) + if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success) { - if (!m_target.GetArchitecture().IsValid()) { // Make sure we have an architecture - m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + if (!m_target.GetArchitecture().IsValid()) + { + if (m_gdb_comm.GetProcessArchitecture().IsValid()) + { + m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + } + else + { + m_target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); + } } SetPrivateState (SetThreadStopInfo (m_last_stop_packet)); @@ -886,31 +891,35 @@ Error ProcessGDBRemote::ConnectToDebugserver (const char *connect_url) { Error error; - // Sleep and wait a bit for debugserver to start to listen... - std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); - if (conn_ap.get()) + // Only connect if we have a valid connect URL + + if (connect_url && connect_url[0]) { - const uint32_t max_retry_count = 50; - uint32_t retry_count = 0; - while (!m_gdb_comm.IsConnected()) + std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); + if (conn_ap.get()) { - if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) + const uint32_t max_retry_count = 50; + uint32_t retry_count = 0; + while (!m_gdb_comm.IsConnected()) { - m_gdb_comm.SetConnection (conn_ap.release()); - break; - } - else if (error.WasInterrupted()) - { - // If we were interrupted, don't keep retrying. - break; - } - - retry_count++; - - if (retry_count >= max_retry_count) - break; + if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) + { + m_gdb_comm.SetConnection (conn_ap.release()); + break; + } + else if (error.WasInterrupted()) + { + // If we were interrupted, don't keep retrying. + break; + } + + retry_count++; + + if (retry_count >= max_retry_count) + break; - usleep (100000); + usleep (100000); + } } } @@ -1040,12 +1049,7 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - char host_port[128]; - snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); - char connect_url[128]; - snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); - - error = StartDebugserverProcess (host_port, attach_info); + error = LaunchAndConnectToDebugserver (attach_info); if (error.Fail()) { @@ -1055,10 +1059,6 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process SetExitStatus (-1, error_string); } - else - { - error = ConnectToDebugserver (connect_url); - } } if (error.Success()) @@ -1072,29 +1072,8 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process return error; } -size_t -ProcessGDBRemote::AttachInputReaderCallback -( - void *baton, - InputReader *reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - if (notification == eInputReaderGotToken) - { - ProcessGDBRemote *gdb_process = (ProcessGDBRemote *)baton; - if (gdb_process->m_waiting_for_attach) - gdb_process->m_waiting_for_attach = false; - reader->SetIsDone(true); - return 1; - } - return 0; -} - Error -ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait_for_launch, const ProcessAttachInfo &attach_info) +ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info) { Error error; // Clear out and clean up from any current state @@ -1105,12 +1084,8 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - char host_port[128]; - snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); - char connect_url[128]; - snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); + error = LaunchAndConnectToDebugserver (attach_info); - error = StartDebugserverProcess (host_port, attach_info); if (error.Fail()) { const char *error_string = error.AsCString(); @@ -1119,17 +1094,13 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait SetExitStatus (-1, error_string); } - else - { - error = ConnectToDebugserver (connect_url); - } } if (error.Success()) { StreamString packet; - if (wait_for_launch) + if (attach_info.GetWaitForLaunch()) { if (!m_gdb_comm.GetVAttachOrWaitSupported()) { @@ -1199,7 +1170,11 @@ ProcessGDBRemote::DoResume () bool continue_packet_error = false; if (m_gdb_comm.HasAnyVContSupport ()) { - if (m_continue_c_tids.size() == num_threads) + if (m_continue_c_tids.size() == num_threads || + (m_continue_c_tids.empty() && + m_continue_C_tids.empty() && + m_continue_s_tids.empty() && + m_continue_S_tids.empty())) { // All threads are continuing, just send a "c" packet continue_packet.PutCString ("c"); @@ -2026,7 +2001,7 @@ ProcessGDBRemote::DoDestroy () bool send_async = true; const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (3); - if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async)) + if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async) == GDBRemoteCommunication::PacketResult::Success) { char packet_cmd = response.GetChar(0); @@ -2128,7 +2103,7 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro const int packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size); assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true)) + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsNormalResponse()) { @@ -2164,7 +2139,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); packet.PutBytesAsRawHex8(buf, size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true)) + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) { @@ -2546,14 +2521,7 @@ ProcessGDBRemote::DoSignal (int signo) } Error -ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url) -{ - ProcessLaunchInfo launch_info; - return StartDebugserverProcess(debugserver_url, launch_info); -} - -Error -ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const ProcessInfo &process_info) // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...") +ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info) { Error error; if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) @@ -2562,141 +2530,55 @@ ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const Pr static FileSpec g_debugserver_file_spec; ProcessLaunchInfo debugserver_launch_info; - char debugserver_path[PATH_MAX]; - FileSpec &debugserver_file_spec = debugserver_launch_info.GetExecutableFile(); - - // Always check to see if we have an environment override for the path - // to the debugserver to use and use it if we do. - const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); - if (env_debugserver_path) - debugserver_file_spec.SetFile (env_debugserver_path, false); - else - debugserver_file_spec = g_debugserver_file_spec; - bool debugserver_exists = debugserver_file_spec.Exists(); - if (!debugserver_exists) - { - // The debugserver binary is in the LLDB.framework/Resources - // directory. - if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) - { - debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); - debugserver_exists = debugserver_file_spec.Exists(); - if (debugserver_exists) - { - g_debugserver_file_spec = debugserver_file_spec; - } - else - { - g_debugserver_file_spec.Clear(); - debugserver_file_spec.Clear(); - } - } - } - - if (debugserver_exists) - { - debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); - - m_stdio_communication.Clear(); - - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - - Args &debugserver_args = debugserver_launch_info.GetArguments(); - char arg_cstr[PATH_MAX]; + debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); + debugserver_launch_info.SetUserID(process_info.GetUserID()); - // Start args with "debugserver /file/path -r --" - debugserver_args.AppendArgument(debugserver_path); - debugserver_args.AppendArgument(debugserver_url); - // use native registers, not the GDB registers - debugserver_args.AppendArgument("--native-regs"); - // make debugserver run in its own session so signals generated by - // special terminal key sequences (^C) don't affect debugserver - debugserver_args.AppendArgument("--setsid"); - - const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); - if (env_debugserver_log_file) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); - debugserver_args.AppendArgument(arg_cstr); - } - - const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); - if (env_debugserver_log_flags) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); - debugserver_args.AppendArgument(arg_cstr); - } -// debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); -// debugserver_args.AppendArgument("--log-flags=0x802e0e"); - - // We currently send down all arguments, attach pids, or attach - // process names in dedicated GDB server packets, so we don't need - // to pass them as arguments. This is currently because of all the - // things we need to setup prior to launching: the environment, - // current working dir, file actions, etc. -#if 0 - // Now append the program arguments - if (inferior_argv) - { - // Terminate the debugserver args so we can now append the inferior args - debugserver_args.AppendArgument("--"); - - for (int i = 0; inferior_argv[i] != NULL; ++i) - debugserver_args.AppendArgument (inferior_argv[i]); - } - else if (attach_pid != LLDB_INVALID_PROCESS_ID) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); - debugserver_args.AppendArgument (arg_cstr); - } - else if (attach_name && attach_name[0]) - { - if (wait_for_launch) - debugserver_args.AppendArgument ("--waitfor"); - else - debugserver_args.AppendArgument ("--attach"); - debugserver_args.AppendArgument (attach_name); - } +#if defined (__APPLE__) && defined (__arm__) + // On iOS, still do a local connection using a random port + const char *hostname = "localhost"; + uint16_t port = get_random_port (); +#else + // Set hostname being NULL to do the reverse connect where debugserver + // will bind to port zero and it will communicate back to us the port + // that we will connect to + const char *hostname = NULL; + uint16_t port = 0; #endif - - ProcessLaunchInfo::FileAction file_action; - - // Close STDIN, STDOUT and STDERR. We might need to redirect them - // to "/dev/null" if we run into any problems. - file_action.Close (STDIN_FILENO); - debugserver_launch_info.AppendFileAction (file_action); - file_action.Close (STDOUT_FILENO); - debugserver_launch_info.AppendFileAction (file_action); - file_action.Close (STDERR_FILENO); - debugserver_launch_info.AppendFileAction (file_action); - - if (log) - { - StreamString strm; - debugserver_args.Dump (&strm); - log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData()); - } - debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); - debugserver_launch_info.SetUserID(process_info.GetUserID()); + error = m_gdb_comm.StartDebugserverProcess (hostname, + port, + debugserver_launch_info, + port); - error = Host::LaunchProcess(debugserver_launch_info); + if (error.Success ()) + m_debugserver_pid = debugserver_launch_info.GetProcessID(); + else + m_debugserver_pid = LLDB_INVALID_PROCESS_ID; - if (error.Success ()) - m_debugserver_pid = debugserver_launch_info.GetProcessID(); - else - m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) + StartAsyncThread (); + + if (error.Fail()) + { + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (error.Fail() || log) - error.PutToLog(log, "Host::LaunchProcess (launch_info) => pid=%" PRIu64 ", path='%s'", m_debugserver_pid, debugserver_path); + if (log) + log->Printf("failed to start debugserver process: %s", error.AsCString()); + return error; + } + + if (m_gdb_comm.IsConnected()) + { + // Finish the connection process by doing the handshake without connecting (send NULL URL) + ConnectToDebugserver (NULL); } else { - error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME); + StreamString connect_url; + connect_url.Printf("connect://%s:%u", hostname, port); + error = ConnectToDebugserver (connect_url.GetString().c_str()); } - if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) - StartAsyncThread (); } return error; } diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 35244074bab7..9331775bb896 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -21,7 +21,6 @@ #include "lldb/Core/Broadcaster.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Error.h" -#include "lldb/Core/InputReader.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/StringList.h" #include "lldb/Core/ThreadSafeValue.h" @@ -86,7 +85,7 @@ public: virtual lldb_private::Error DoLaunch (lldb_private::Module *exe_module, - const lldb_private::ProcessLaunchInfo &launch_info); + lldb_private::ProcessLaunchInfo &launch_info); virtual void DidLaunch (); @@ -111,7 +110,6 @@ public: virtual lldb_private::Error DoAttachToProcessWithName (const char *process_name, - bool wait_for_launch, const lldb_private::ProcessAttachInfo &attach_info); virtual void @@ -284,10 +282,7 @@ protected: lldb_private::ThreadList &new_thread_list); lldb_private::Error - StartDebugserverProcess (const char *debugserver_url); - - lldb_private::Error - StartDebugserverProcess (const char *debugserver_url, const lldb_private::ProcessInfo &process_info); + LaunchAndConnectToDebugserver (const lldb_private::ProcessInfo &process_info); void KillDebugserverProcess (); @@ -382,13 +377,6 @@ protected: GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr, std::string &dispatch_queue_name); - static size_t - AttachInputReaderCallback (void *baton, - lldb_private::InputReader *reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - lldb_private::DynamicLoader * GetDynamicLoader (); diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 4e475c80bdab..fb524deda813 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -19,6 +19,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" +#include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/Unwind.h" @@ -74,10 +75,10 @@ ThreadGDBRemote::GetQueueName () ProcessSP process_sp (GetProcess()); if (process_sp) { - PlatformSP platform_sp (process_sp->GetTarget().GetPlatform()); - if (platform_sp) + SystemRuntime *runtime = process_sp->GetSystemRuntime (); + if (runtime) { - m_dispatch_queue_name = platform_sp->GetQueueNameForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr); + m_dispatch_queue_name = runtime->GetQueueNameFromThreadQAddress (m_thread_dispatch_qaddr); } if (m_dispatch_queue_name.length() > 0) { @@ -96,10 +97,10 @@ ThreadGDBRemote::GetQueueID () ProcessSP process_sp (GetProcess()); if (process_sp) { - PlatformSP platform_sp (process_sp->GetTarget().GetPlatform()); - if (platform_sp) + SystemRuntime *runtime = process_sp->GetSystemRuntime (); + if (runtime) { - return platform_sp->GetQueueIDForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr); + return runtime->GetQueueIDFromThreadQAddress (m_thread_dispatch_qaddr); } } } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index fce995e4ff2e..d6c580c7ab1b 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -53,7 +53,7 @@ public: bool ExtractValue(const lldb_private::DWARFDataExtractor& data, lldb::offset_t* offset_ptr, const DWARFCompileUnit* cu); - bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (uint8_t*)m_value.value.cstr; } + bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (const uint8_t*)m_value.value.cstr; } const uint8_t* BlockData() const; uint64_t Reference(const DWARFCompileUnit* cu) const; uint64_t Reference (dw_offset_t offset) const; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 09b50531b8a9..ef03cac540c6 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1644,6 +1644,13 @@ struct BitfieldInfo { } + void + Clear() + { + bit_size = LLDB_INVALID_ADDRESS; + bit_offset = LLDB_INVALID_ADDRESS; + } + bool IsValid () { return (bit_size != LLDB_INVALID_ADDRESS) && @@ -1915,12 +1922,14 @@ SymbolFileDWARF::ParseChildMembers accessibility = default_accessibility; member_accessibilities.push_back(accessibility); - BitfieldInfo this_field_info; - - this_field_info.bit_size = bit_size; - - if (member_byte_offset != UINT32_MAX || bit_size != 0) + uint64_t field_bit_offset = (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); + if (bit_size > 0) { + + BitfieldInfo this_field_info; + this_field_info.bit_offset = field_bit_offset; + this_field_info.bit_size = bit_size; + ///////////////////////////////////////////////////////////// // How to locate a field given the DWARF debug information // @@ -1937,10 +1946,9 @@ SymbolFileDWARF::ParseChildMembers // AT_bit_size indicates the size of the field in bits. ///////////////////////////////////////////////////////////// - this_field_info.bit_offset = 0; - - this_field_info.bit_offset += (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); - + if (byte_size == 0) + byte_size = member_type->GetByteSize(); + if (GetObjectFile()->GetByteOrder() == eByteOrderLittle) { this_field_info.bit_offset += byte_size * 8; @@ -1950,30 +1958,30 @@ SymbolFileDWARF::ParseChildMembers { this_field_info.bit_offset += bit_offset; } - } + + // Update the field bit offset we will report for layout + field_bit_offset = this_field_info.bit_offset; - // If the member to be emitted did not start on a character boundary and there is - // empty space between the last field and this one, then we need to emit an - // anonymous member filling up the space up to its start. There are three cases - // here: - // - // 1 If the previous member ended on a character boundary, then we can emit an - // anonymous member starting at the most recent character boundary. - // - // 2 If the previous member did not end on a character boundary and the distance - // from the end of the previous member to the current member is less than a - // word width, then we can emit an anonymous member starting right after the - // previous member and right before this member. - // - // 3 If the previous member did not end on a character boundary and the distance - // from the end of the previous member to the current member is greater than - // or equal a word width, then we act as in Case 1. - - const uint64_t character_width = 8; - const uint64_t word_width = 32; - - if (this_field_info.IsValid()) - { + // If the member to be emitted did not start on a character boundary and there is + // empty space between the last field and this one, then we need to emit an + // anonymous member filling up the space up to its start. There are three cases + // here: + // + // 1 If the previous member ended on a character boundary, then we can emit an + // anonymous member starting at the most recent character boundary. + // + // 2 If the previous member did not end on a character boundary and the distance + // from the end of the previous member to the current member is less than a + // word width, then we can emit an anonymous member starting right after the + // previous member and right before this member. + // + // 3 If the previous member did not end on a character boundary and the distance + // from the end of the previous member to the current member is greater than + // or equal a word width, then we act as in Case 1. + + const uint64_t character_width = 8; + const uint64_t word_width = 32; + // Objective-C has invalid DW_AT_bit_offset values in older versions // of clang, so we have to be careful and only insert unnammed bitfields // if we have a new enough clang. @@ -2019,6 +2027,11 @@ SymbolFileDWARF::ParseChildMembers layout_info.field_offsets.insert(std::make_pair(unnamed_bitfield_decl, anon_field_info.bit_offset)); } } + last_field_info = this_field_info; + } + else + { + last_field_info.Clear(); } ClangASTType member_clang_type = member_type->GetClangLayoutType(); @@ -2062,11 +2075,8 @@ SymbolFileDWARF::ParseChildMembers GetClangASTContext().SetMetadataAsUserID (field_decl, MakeUserID(die->GetOffset())); - if (this_field_info.IsValid()) - { - layout_info.field_offsets.insert(std::make_pair(field_decl, this_field_info.bit_offset)); - last_field_info = this_field_info; - } + layout_info.field_offsets.insert(std::make_pair(field_decl, field_bit_offset)); + } else { @@ -2546,6 +2556,37 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) if (!base_classes.empty()) { + // Make sure all base classes refer to complete types and not + // forward declarations. If we don't do this, clang will crash + // with an assertion in the call to clang_type.SetBaseClassesForClassType() + bool base_class_error = false; + for (auto &base_class : base_classes) + { + clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo(); + if (type_source_info) + { + ClangASTType base_class_type (GetClangASTContext().getASTContext(), type_source_info->getType()); + if (base_class_type.GetCompleteType() == false) + { + if (!base_class_error) + { + GetObjectFile()->GetModule()->ReportError ("DWARF DIE at 0x%8.8x for class '%s' has a base class '%s' that is a forward declaration, not a complete definition.\nPlease file a bug against the compiler and include the preprocessed output for %s", + die->GetOffset(), + die->GetName(this, dwarf_cu), + base_class_type.GetTypeName().GetCString(), + sc.comp_unit ? sc.comp_unit->GetPath().c_str() : "the source file"); + } + // We have no choice other than to pretend that the base class + // is complete. If we don't do this, clang will crash when we + // call setBases() inside of "clang_type.SetBaseClassesForClassType()" + // below. Since we provide layout assistance, all ivars in this + // class and other classe will be fine, this is the best we can do + // short of crashing. + base_class_type.StartTagDeclarationDefinition (); + base_class_type.CompleteTagDeclarationDefinition (); + } + } + } clang_type.SetBaseClassesForClassType (&base_classes.front(), base_classes.size()); @@ -6222,6 +6263,11 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, case DW_TAG_subprogram: case DW_TAG_member: case DW_TAG_APPLE_property: + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_enumeration_type: + case DW_TAG_typedef: + case DW_TAG_union_type: child_die = NULL; is_forward_declaration = false; break; diff --git a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp index 6500aabdcea3..a9f8f36e610e 100644 --- a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -9,12 +9,8 @@ #include "SymbolVendorELF.h" -//#include <libxml/parser.h> -// #include <libxml/tree.h> #include <string.h> -// #include <AvailabilityMacros.h> - #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" |