diff options
56 files changed, 1022 insertions, 194 deletions
diff --git a/include/lldb/Core/Address.h b/include/lldb/Core/Address.h index a800570ec8b1..4c77458061d0 100644 --- a/include/lldb/Core/Address.h +++ b/include/lldb/Core/Address.h @@ -422,6 +422,10 @@ public: /// a section + offset. The Target's SectionLoadList object /// is used to resolve the address. /// + /// @param[in] allow_section_end + /// If true, treat an address pointing to the end of the module as + /// belonging to that module. + /// /// @return /// Returns \b true if the load address was resolved to be /// section/offset, \b false otherwise. It is often ok for an @@ -429,11 +433,13 @@ public: /// happens for JIT'ed code, or any load addresses on the stack /// or heap. //------------------------------------------------------------------ - bool SetLoadAddress(lldb::addr_t load_addr, Target *target); + bool SetLoadAddress(lldb::addr_t load_addr, Target *target, + bool allow_section_end = false); bool SetOpcodeLoadAddress( lldb::addr_t load_addr, Target *target, - lldb::AddressClass addr_class = lldb::eAddressClassInvalid); + lldb::AddressClass addr_class = lldb::eAddressClassInvalid, + bool allow_section_end = false); bool SetCallableLoadAddress(lldb::addr_t load_addr, Target *target); diff --git a/include/lldb/Core/Section.h b/include/lldb/Core/Section.h index a133298edaf3..0466693edbc4 100644 --- a/include/lldb/Core/Section.h +++ b/include/lldb/Core/Section.h @@ -143,7 +143,8 @@ public: lldb::addr_t GetLoadBaseAddress(Target *target) const; - bool ResolveContainedAddress(lldb::addr_t offset, Address &so_addr) const; + bool ResolveContainedAddress(lldb::addr_t offset, Address &so_addr, + bool allow_section_end = false) const; lldb::offset_t GetFileOffset() const { return m_file_offset; } diff --git a/include/lldb/Core/dwarf.h b/include/lldb/Core/dwarf.h index 4a935d5151e9..651a2bc29475 100644 --- a/include/lldb/Core/dwarf.h +++ b/include/lldb/Core/dwarf.h @@ -13,7 +13,7 @@ #include <stdint.h> // Get the DWARF constant definitions from llvm -#include "llvm/Support/Dwarf.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "lldb/Core/RangeMap.h" diff --git a/include/lldb/Target/SectionLoadList.h b/include/lldb/Target/SectionLoadList.h index c232dd91a8b3..beb345b71290 100644 --- a/include/lldb/Target/SectionLoadList.h +++ b/include/lldb/Target/SectionLoadList.h @@ -47,7 +47,8 @@ public: lldb::addr_t GetSectionLoadAddress(const lldb::SectionSP §ion_sp) const; - bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr) const; + bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, + bool allow_section_end = false) const; bool SetSectionLoadAddress(const lldb::SectionSP §ion_sp, lldb::addr_t load_addr, diff --git a/include/lldb/Utility/SafeMachO.h b/include/lldb/Utility/SafeMachO.h index 5da03c15da94..791410a38b34 100644 --- a/include/lldb/Utility/SafeMachO.h +++ b/include/lldb/Utility/SafeMachO.h @@ -114,6 +114,6 @@ #undef CPU_SUBTYPE_MC980000_ALL #undef CPU_SUBTYPE_MC98601 -#include "llvm/Support/MachO.h" +#include "llvm/BinaryFormat/MachO.h" #endif // liblldb_SafeMachO_h_ diff --git a/include/lldb/Utility/TaskPool.h b/include/lldb/Utility/TaskPool.h index 87b8824f9226..f2deaee506b8 100644 --- a/include/lldb/Utility/TaskPool.h +++ b/include/lldb/Utility/TaskPool.h @@ -10,6 +10,7 @@ #ifndef utility_TaskPool_h_ #define utility_TaskPool_h_ +#include "llvm/ADT/STLExtras.h" #include <functional> // for bind, function #include <future> #include <list> @@ -86,6 +87,6 @@ template <> struct TaskPool::RunTaskImpl<> { // 'batch_size' numbers at a time to work on, so for very fast functions, batch // should be large enough to avoid too much cache line contention. void TaskMapOverInt(size_t begin, size_t end, - std::function<void(size_t)> const &func); + const llvm::function_ref<void(size_t)> &func); #endif // #ifndef utility_TaskPool_h_ diff --git a/include/lldb/Utility/VMRange.h b/include/lldb/Utility/VMRange.h index 98362f4d7608..f03a1b0c1f97 100644 --- a/include/lldb/Utility/VMRange.h +++ b/include/lldb/Utility/VMRange.h @@ -111,11 +111,6 @@ public: static bool ContainsRange(const VMRange::collection &coll, const VMRange &range); - // Returns a valid index into coll when a match is found, else UINT32_MAX - // is returned - static size_t FindRangeIndexThatContainsValue(const VMRange::collection &coll, - lldb::addr_t value); - protected: lldb::addr_t m_base_addr; lldb::addr_t m_byte_size; diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py index eafe62a0e08f..d54e62887ce1 100644 --- a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py @@ -17,8 +17,8 @@ class NoreturnUnwind(TestBase): mydir = TestBase.compute_mydir(__file__) @skipIfWindows # clang-cl does not support gcc style attributes. - @expectedFailureAndroid(bugnumber="llvm.org/pr31192") - @expectedFailureAll(bugnumber="llvm.org/pr31192", oslist=['linux'], compiler="gcc", archs=['arm']) + # clang does not preserve LR in noreturn functions, making unwinding impossible + @skipIf(compiler="clang", archs=['arm'], oslist=['linux']) def test(self): """Test that we can backtrace correctly with 'noreturn' functions on the stack""" self.build() diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c index 7190e38f5d8c..4f6525fbf52f 100644 --- a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c @@ -29,8 +29,6 @@ func_a (void) int main (int argc, char *argv[]) { - sleep (2); - func_a (); return 0; diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/TestNoReturnModuleEnd.py b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/TestNoReturnModuleEnd.py new file mode 100644 index 000000000000..3aa6a230e8b6 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/TestNoReturnModuleEnd.py @@ -0,0 +1,53 @@ +""" +Test that we properly display the backtrace when a noreturn function happens to +be at the end of the stack. +""" + +from __future__ import print_function + +import shutil +import struct + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestNoreturnModuleEnd(TestBase): + NO_DEBUG_INFO_TESTCASE = True + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + super(TestNoreturnModuleEnd, self).setUp() + self._initial_platform = lldb.DBG.GetSelectedPlatform() + + def tearDown(self): + lldb.DBG.SetSelectedPlatform(self._initial_platform) + super(TestNoreturnModuleEnd, self).tearDown() + + def test(self): + target = self.dbg.CreateTarget("test.out") + process = target.LoadCore("test.core") + self.assertTrue(process.IsValid(), PROCESS_IS_VALID) + self.assertEqual(process.GetNumThreads(), 1) + + thread = process.GetSelectedThread() + self.assertTrue(thread.IsValid()) + + backtrace = [ + ["func2", 3], + ["func1", 8], + ["_start", 8], + ] + self.assertEqual(thread.GetNumFrames(), len(backtrace)) + for i in range(len(backtrace)): + frame = thread.GetFrameAtIndex(i) + self.assertTrue(frame.IsValid()) + symbol = frame.GetSymbol() + self.assertTrue(symbol.IsValid()) + self.assertEqual(symbol.GetName(), backtrace[i][0]) + function_start = symbol.GetStartAddress().GetLoadAddress(target) + self.assertEquals(function_start + backtrace[i][1], frame.GetPC()) + + self.dbg.DeleteTarget(target) diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/a.s b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/a.s new file mode 100644 index 000000000000..119465c132a9 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/a.s @@ -0,0 +1,35 @@ +# compile this with: +# as a.s -o a.o --32 && ld a.o -m elf_i386 +# generate core file with: +# ulimit -s 12 && ./a.out + +.text + +.globl func2 +.type func2, @function +func2: + pushl %ebp + movl %esp, %ebp + movl 0, %eax + popl %ebp + ret +.size func2, .-func2 + +.globl _start +.type _start, @function +_start: + pushl %ebp + movl %esp, %ebp + call func1 + popl %ebp + ret +.size _start, .-_start + +.globl func1 +.type func1, @function +func1: + pushl %ebp + movl %esp, %ebp + call func2 +.size func1, .-func1 + diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.core b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.core Binary files differnew file mode 100644 index 000000000000..6717d4ff6471 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.core diff --git a/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out Binary files differnew file mode 100755 index 000000000000..141c61ecbea3 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out diff --git a/source/Commands/CommandObjectRegister.cpp b/source/Commands/CommandObjectRegister.cpp index 6de8c667e7a7..d535742016ac 100644 --- a/source/Commands/CommandObjectRegister.cpp +++ b/source/Commands/CommandObjectRegister.cpp @@ -7,12 +7,6 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes -#include "llvm/ADT/STLExtras.h" - -// Project includes #include "CommandObjectRegister.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/RegisterValue.h" @@ -32,6 +26,7 @@ #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataExtractor.h" +#include "llvm/Support/Errno.h" using namespace lldb; using namespace lldb_private; @@ -178,8 +173,8 @@ protected: if (set_idx < reg_ctx->GetRegisterSetCount()) { if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) { if (errno) - result.AppendErrorWithFormat("register read failed: %s\n", - strerror(errno)); + result.AppendErrorWithFormatv("register read failed: {0}\n", + llvm::sys::StrError()); else result.AppendError("unknown error while reading registers.\n"); result.SetStatus(eReturnStatusFailed); diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp index 6328e433852a..0c929c22f75f 100644 --- a/source/Core/Address.cpp +++ b/source/Core/Address.cpp @@ -361,8 +361,9 @@ addr_t Address::GetOpcodeLoadAddress(Target *target, } bool Address::SetOpcodeLoadAddress(lldb::addr_t load_addr, Target *target, - AddressClass addr_class) { - if (SetLoadAddress(load_addr, target)) { + AddressClass addr_class, + bool allow_section_end) { + if (SetLoadAddress(load_addr, target, allow_section_end)) { if (target) { if (addr_class == eAddressClassInvalid) addr_class = GetAddressClass(); @@ -1001,9 +1002,10 @@ AddressClass Address::GetAddressClass() const { return eAddressClassUnknown; } -bool Address::SetLoadAddress(lldb::addr_t load_addr, Target *target) { - if (target && - target->GetSectionLoadList().ResolveLoadAddress(load_addr, *this)) +bool Address::SetLoadAddress(lldb::addr_t load_addr, Target *target, + bool allow_section_end) { + if (target && target->GetSectionLoadList().ResolveLoadAddress( + load_addr, *this, allow_section_end)) return true; m_section_wp.reset(); m_offset = load_addr; diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp index 91b73847ac1f..bfe9750f70f0 100644 --- a/source/Core/ArchSpec.cpp +++ b/source/Core/ArchSpec.cpp @@ -24,11 +24,11 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" // for Twine -#include "llvm/Support/COFF.h" -#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH -#include "llvm/Support/ELF.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" // for CPUType::CPU_T... +#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH #include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" // for CPUType::CPU_T... #include <memory> // for shared_ptr #include <string> diff --git a/source/Core/CMakeLists.txt b/source/Core/CMakeLists.txt index 7dcec050d866..806227793f24 100644 --- a/source/Core/CMakeLists.txt +++ b/source/Core/CMakeLists.txt @@ -67,6 +67,7 @@ add_lldb_library(lldbCore lldbPluginObjectFileJIT LINK_COMPONENTS + BinaryFormat Support Demangle ) diff --git a/source/Core/Section.cpp b/source/Core/Section.cpp index f6428ced0164..3b76dd361ff3 100644 --- a/source/Core/Section.cpp +++ b/source/Core/Section.cpp @@ -220,18 +220,18 @@ addr_t Section::GetLoadBaseAddress(Target *target) const { return load_base_addr; } -bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr) const { +bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, + bool allow_section_end) const { const size_t num_children = m_children.GetSize(); - if (num_children > 0) { - for (size_t i = 0; i < num_children; i++) { - Section *child_section = m_children.GetSectionAtIndex(i).get(); - - addr_t child_offset = child_section->GetOffset(); - if (child_offset <= offset && - offset - child_offset < child_section->GetByteSize()) - return child_section->ResolveContainedAddress(offset - child_offset, - so_addr); - } + for (size_t i = 0; i < num_children; i++) { + Section *child_section = m_children.GetSectionAtIndex(i).get(); + + addr_t child_offset = child_section->GetOffset(); + if (child_offset <= offset && + offset - child_offset < + child_section->GetByteSize() + (allow_section_end ? 1 : 0)) + return child_section->ResolveContainedAddress(offset - child_offset, + so_addr, allow_section_end); } so_addr.SetOffset(offset); so_addr.SetSection(const_cast<Section *>(this)->shared_from_this()); diff --git a/source/DataFormatters/TypeCategory.cpp b/source/DataFormatters/TypeCategory.cpp index db3372c52925..184a8c98de62 100644 --- a/source/DataFormatters/TypeCategory.cpp +++ b/source/DataFormatters/TypeCategory.cpp @@ -36,23 +36,8 @@ TypeCategoryImpl::TypeCategoryImpl( static bool IsApplicable(lldb::LanguageType category_lang, lldb::LanguageType valobj_lang) { switch (category_lang) { - // these are not languages that LLDB would ordinarily deal with - // only allow an exact equality here, since we really don't know - // any better - case eLanguageTypeAda83: - case eLanguageTypeCobol74: - case eLanguageTypeCobol85: - case eLanguageTypeFortran77: - case eLanguageTypeFortran90: - case eLanguageTypePascal83: - case eLanguageTypeModula2: - case eLanguageTypeJava: - case eLanguageTypeAda95: - case eLanguageTypeFortran95: - case eLanguageTypePLI: - case eLanguageTypeUPC: - case eLanguageTypeD: - case eLanguageTypePython: + // Unless we know better, allow only exact equality. + default: return category_lang == valobj_lang; // the C family, we consider it as one @@ -80,7 +65,7 @@ static bool IsApplicable(lldb::LanguageType category_lang, valobj_lang == eLanguageTypeC_plus_plus || valobj_lang == eLanguageTypeObjC; - default: + // Categories with unspecified language match everything. case eLanguageTypeUnknown: return true; } diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index da35022c813c..d78961e5bffc 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -68,6 +68,7 @@ #include "lldb/Utility/Status.h" #include "lldb/lldb-private-forward.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" #if defined(_WIN32) @@ -217,10 +218,9 @@ static thread_result_t MonitorChildProcessThreadFunction(void *arg) { if (errno == EINTR) continue; else { - if (log) - log->Printf( - "%s (arg = %p) thread exiting because waitpid failed (%s)...", - __FUNCTION__, arg, strerror(errno)); + LLDB_LOG(log, + "arg = {0}, thread exiting because waitpid failed ({1})...", + arg, llvm::sys::StrError()); break; } } else if (wait_pid > 0) { diff --git a/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 7a0c92b44918..c3b237a87302 100644 --- a/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -36,6 +36,7 @@ #include <sstream> // Other libraries and framework includes +#include "llvm/Support/Errno.h" #include "llvm/Support/ErrorHandling.h" #if defined(__APPLE__) #include "llvm/ADT/SmallVector.h" @@ -461,10 +462,8 @@ size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len, return 0; default: - if (log) - log->Printf( - "%p ConnectionFileDescriptor::Read (), unexpected error: %s", - static_cast<void *>(this), strerror(error_value)); + LLDB_LOG(log, "this = {0}, unexpected error: {1}", this, + llvm::sys::StrError(error_value)); status = eConnectionStatusError; break; // Break to close.... } diff --git a/source/Host/posix/ProcessLauncherPosixFork.cpp b/source/Host/posix/ProcessLauncherPosixFork.cpp index 378670cd2a9a..1eace5cd24cd 100644 --- a/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -14,6 +14,7 @@ #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "llvm/Support/Errno.h" #include <limits.h> #include <sys/ptrace.h> @@ -204,8 +205,8 @@ ProcessLauncherPosixFork::LaunchProcess(const ProcessLaunchInfo &launch_info, ::pid_t pid = ::fork(); if (pid == -1) { // Fork failed - error.SetErrorStringWithFormat("Fork failed with error message: %s", - strerror(errno)); + error.SetErrorStringWithFormatv("Fork failed with error message: {0}", + llvm::sys::StrError()); return HostProcess(LLDB_INVALID_PROCESS_ID); } if (pid == 0) { diff --git a/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/source/Plugins/Language/ObjC/ObjCLanguage.cpp index 193c5864d01f..4d9227598cef 100644 --- a/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -95,7 +95,7 @@ bool ObjCLanguage::MethodName::SetName(llvm::StringRef name, bool strict) { // or '-' can be omitted bool valid_prefix = false; - if (name[0] == '+' || name[0] == '-') { + if (name.size() > 1 && (name[0] == '+' || name[0] == '-')) { valid_prefix = name[1] == '['; if (name[0] == '+') m_type = eTypeClassMethod; diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 566fefaf7984..9cac499c0ff0 100644 --- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -171,6 +171,7 @@ UtilityFunction *AppleObjCRuntimeV1::CreateObjectChecker(const char *name) { " \n", name); assert(strformatsize < (int)sizeof(buf->contents)); + (void)strformatsize; Status error; return GetTargetRef().GetUtilityFunctionForLanguage( diff --git a/source/Plugins/ObjectFile/ELF/CMakeLists.txt b/source/Plugins/ObjectFile/ELF/CMakeLists.txt index a941b8d55848..e0680b07efc5 100644 --- a/source/Plugins/ObjectFile/ELF/CMakeLists.txt +++ b/source/Plugins/ObjectFile/ELF/CMakeLists.txt @@ -8,5 +8,6 @@ add_lldb_library(lldbPluginObjectFileELF PLUGIN lldbSymbol lldbTarget LINK_COMPONENTS + BinaryFormat Support ) diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.h b/source/Plugins/ObjectFile/ELF/ELFHeader.h index e6738a1ecb2b..4e2d3155ebb9 100644 --- a/source/Plugins/ObjectFile/ELF/ELFHeader.h +++ b/source/Plugins/ObjectFile/ELF/ELFHeader.h @@ -21,7 +21,7 @@ #ifndef liblldb_ELFHeader_h_ #define liblldb_ELFHeader_h_ -#include "llvm/Support/ELF.h" +#include "llvm/BinaryFormat/ELF.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-types.h" diff --git a/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt b/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt index 1e8fb85c72c9..04321f276551 100644 --- a/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt +++ b/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt @@ -8,5 +8,6 @@ add_lldb_library(lldbPluginObjectFilePECOFF PLUGIN lldbSymbol lldbTarget LINK_COMPONENTS + BinaryFormat Support ) diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index dcb9527f24c8..4739a4934aa6 100644 --- a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -10,7 +10,7 @@ #include "ObjectFilePECOFF.h" #include "WindowsMiniDump.h" -#include "llvm/Support/COFF.h" +#include "llvm/BinaryFormat/COFF.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/FileSpecList.h" diff --git a/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp b/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp index 6845a36730c9..c6daf6ccea6e 100644 --- a/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp +++ b/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp @@ -35,6 +35,7 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" +#include "llvm/Support/Errno.h" #include "CFBundle.h" #include "CFString.h" @@ -319,13 +320,12 @@ static Status PosixSpawnChildForPTraceDebugging(const char *path, ::posix_spawnattr_setsigdefault(&attr, &all_signals); if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) { - if (log) - log->Printf("::posix_spawnattr_setflags(&attr, " - "POSIX_SPAWN_START_SUSPENDED%s) failed: %s", - flags & _POSIX_SPAWN_DISABLE_ASLR - ? " | _POSIX_SPAWN_DISABLE_ASLR" - : "", - strerror(error_code)); + LLDB_LOG(log, + "::posix_spawnattr_setflags(&attr, " + "POSIX_SPAWN_START_SUSPENDED{0}) failed: {1}", + flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR" + : "", + llvm::sys::StrError(error_code)); error.SetError(error_code, eErrorTypePOSIX); return error; } @@ -341,10 +341,10 @@ static Status PosixSpawnChildForPTraceDebugging(const char *path, error_code = ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount); if (error_code != 0) { - if (log) - log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, " - "cpu_type = 0x%8.8x, count => %llu): %s", - desired_cpu_type, (uint64_t)ocount, strerror(error_code)); + LLDB_LOG(log, + "::posix_spawnattr_setbinpref_np(&attr, 1, " + "cpu_type = {0:x8}, count => {1}): {2}", + desired_cpu_type, ocount, llvm::sys::StrError(error_code)); error.SetError(error_code, eErrorTypePOSIX); return error; } @@ -361,10 +361,8 @@ static Status PosixSpawnChildForPTraceDebugging(const char *path, posix_spawn_file_actions_t file_actions; if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) { - if (log) - log->Printf("::posix_spawn_file_actions_init(&file_actions) " - "failed: %s", - strerror(error_code)); + LLDB_LOG(log, "::posix_spawn_file_actions_init(&file_actions) failed: {0}", + llvm::sys::StrError(error_code)); error.SetError(error_code, eErrorTypePOSIX); return error; } @@ -409,11 +407,11 @@ static Status PosixSpawnChildForPTraceDebugging(const char *path, error_code = ::posix_spawnp(pid, path, &file_actions, &attr, (char *const *)argv, (char *const *)envp); if (error_code != 0) { - if (log) - log->Printf("::posix_spawnp(pid => %p, path = '%s', file_actions " - "= %p, attr = %p, argv = %p, envp = %p) failed: %s", - pid, path, &file_actions, &attr, argv, envp, - strerror(error_code)); + LLDB_LOG(log, + "::posix_spawnp(pid => {0}, path = '{1}', file_actions " + "= {2}, attr = {3}, argv = {4}, envp = {5}) failed: {6}", + pid, path, &file_actions, &attr, argv, envp, + llvm::sys::StrError(error_code)); error.SetError(error_code, eErrorTypePOSIX); return error; } diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 34d99cd39de2..10dd14753914 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -30,6 +30,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Status.h" +#include "llvm/Support/Errno.h" #include "FreeBSDThread.h" #include "Plugins/Process/POSIX/CrashReason.h" @@ -529,10 +530,8 @@ void ResumeOperation::Execute(ProcessMonitor *monitor) { if (PTRACE(PT_CONTINUE, pid, (caddr_t)1, data)) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - if (log) - log->Printf("ResumeOperation (%" PRIu64 ") failed: %s", pid, - strerror(errno)); + LLDB_LOG(log, "ResumeOperation ({0}) failed: {1}", pid, + llvm::sys::StrError(errno)); m_result = false; } else m_result = true; diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 15e7c9b5f698..a130472c72d0 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -43,14 +43,14 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StringExtractor.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" #include "NativeThreadLinux.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #include "Procfs.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Threading.h" - #include <linux/unistd.h> #include <sys/socket.h> #include <sys/syscall.h> @@ -97,7 +97,7 @@ static bool ProcessVmReadvSupported() { LLDB_LOG(log, "syscall process_vm_readv failed (error: {0}). Fast memory " "reads disabled.", - strerror(errno)); + llvm::sys::StrError()); }); return is_supported; @@ -1988,7 +1988,7 @@ Status NativeProcessLinux::ReadMemory(lldb::addr_t addr, void *buf, size_t size, LLDB_LOG(log, "using process_vm_readv to read {0} bytes from inferior " "address {1:x}: {2}", - size, addr, success ? "Success" : strerror(errno)); + size, addr, success ? "Success" : llvm::sys::StrError(errno)); if (success) return Status(); diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 312c1887b581..bce77d7e0a32 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -329,7 +329,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { if (abi) pc = abi->FixCodeAddress(pc); - m_current_pc.SetLoadAddress(pc, &process->GetTarget()); + const bool allow_section_end = true; + m_current_pc.SetLoadAddress(pc, &process->GetTarget(), allow_section_end); // If we don't have a Module for some reason, we're not going to find // symbol/function information - just @@ -477,11 +478,12 @@ void RegisterContextLLDB::InitializeNonZerothFrame() { // 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 != eTrapHandlerFrame && + if (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().GetOffset() == m_current_pc.GetOffset()) { + (!m_sym_ctx_valid || + (addr_range.GetBaseAddress().IsValid() && + addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() && + addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()))) { decr_pc_and_recompute_addr_range = true; } diff --git a/source/Plugins/Process/elf-core/CMakeLists.txt b/source/Plugins/Process/elf-core/CMakeLists.txt index b358697d25af..c7ffae695320 100644 --- a/source/Plugins/Process/elf-core/CMakeLists.txt +++ b/source/Plugins/Process/elf-core/CMakeLists.txt @@ -17,5 +17,6 @@ add_lldb_library(lldbPluginProcessElfCore PLUGIN lldbPluginObjectFileELF lldbPluginProcessUtility LINK_COMPONENTS + BinaryFormat Support ) diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 5a459e80348b..71eb6437ceed 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -27,7 +27,7 @@ #include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/Log.h" -#include "llvm/Support/ELF.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Threading.h" #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index cb00e840673f..f5418763d67b 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -3732,8 +3732,8 @@ static DWARFDIE GetContainingFunctionWithAbstractOrigin(const DWARFDIE &die) { } } } - assert(!"Shouldn't call GetContainingFunctionWithAbstractOrigin on something " - "not in a function"); + assert(0 && "Shouldn't call GetContainingFunctionWithAbstractOrigin on " + "something not in a function"); return DWARFDIE(); } diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 279efe320a46..252a9807a3b5 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1958,7 +1958,7 @@ void SymbolFileDWARF::Index() { &function_fullname_index, &function_method_index, &function_selector_index, &objc_class_selectors_index, &global_index, &type_index, - &namespace_index](uint32_t cu_idx) { + &namespace_index](size_t cu_idx) { DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (dwarf_cu) { dwarf_cu->Index( @@ -1967,10 +1967,9 @@ void SymbolFileDWARF::Index() { objc_class_selectors_index[cu_idx], global_index[cu_idx], type_index[cu_idx], namespace_index[cu_idx]); } - return cu_idx; }; - auto extract_fn = [debug_info, &clear_cu_dies](uint32_t cu_idx) { + auto extract_fn = [debug_info, &clear_cu_dies](size_t cu_idx) { DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (dwarf_cu) { // dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the diff --git a/source/Target/SectionLoadList.cpp b/source/Target/SectionLoadList.cpp index 7f12c262f47e..31ccf17369db 100644 --- a/source/Target/SectionLoadList.cpp +++ b/source/Target/SectionLoadList.cpp @@ -207,8 +207,8 @@ bool SectionLoadList::SetSectionUnloaded(const lldb::SectionSP §ion_sp, return erased; } -bool SectionLoadList::ResolveLoadAddress(addr_t load_addr, - Address &so_addr) const { +bool SectionLoadList::ResolveLoadAddress(addr_t load_addr, Address &so_addr, + bool allow_section_end) const { // First find the top level section that this load address exists in std::lock_guard<std::recursive_mutex> guard(m_mutex); if (!m_addr_to_sect.empty()) { @@ -220,10 +220,11 @@ bool SectionLoadList::ResolveLoadAddress(addr_t load_addr, const addr_t pos_load_addr = pos->first; if (load_addr >= pos_load_addr) { addr_t offset = load_addr - pos_load_addr; - if (offset < pos->second->GetByteSize()) { + if (offset < pos->second->GetByteSize() + (allow_section_end ? 1 : 0)) { // We have found the top level section, now we need to find the // deepest child section. - return pos->second->ResolveContainedAddress(offset, so_addr); + return pos->second->ResolveContainedAddress(offset, so_addr, + allow_section_end); } } } else { @@ -233,10 +234,12 @@ bool SectionLoadList::ResolveLoadAddress(addr_t load_addr, m_addr_to_sect.rbegin(); if (load_addr >= rpos->first) { addr_t offset = load_addr - rpos->first; - if (offset < rpos->second->GetByteSize()) { + if (offset < + rpos->second->GetByteSize() + (allow_section_end ? 1 : 0)) { // We have found the top level section, now we need to find the // deepest child section. - return rpos->second->ResolveContainedAddress(offset, so_addr); + return rpos->second->ResolveContainedAddress(offset, so_addr, + allow_section_end); } } } diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp index 9deebcaf9250..4ef4a399290a 100644 --- a/source/Target/StackFrame.cpp +++ b/source/Target/StackFrame.cpp @@ -191,9 +191,10 @@ const Address &StackFrame::GetFrameCodeAddress() { if (thread_sp) { TargetSP target_sp(thread_sp->CalculateTarget()); if (target_sp) { + const bool allow_section_end = true; if (m_frame_code_addr.SetOpcodeLoadAddress( m_frame_code_addr.GetOffset(), target_sp.get(), - eAddressClassCode)) { + eAddressClassCode, allow_section_end)) { ModuleSP module_sp(m_frame_code_addr.GetModule()); if (module_sp) { m_sc.module_sp = module_sp; diff --git a/source/Utility/CMakeLists.txt b/source/Utility/CMakeLists.txt index a1675670f0b4..31b14acda962 100644 --- a/source/Utility/CMakeLists.txt +++ b/source/Utility/CMakeLists.txt @@ -38,5 +38,6 @@ add_lldb_library(lldbUtility # lldbUtility cannot have any dependencies LINK_COMPONENTS + BinaryFormat Support ) diff --git a/source/Utility/Status.cpp b/source/Utility/Status.cpp index ba87d3e5144f..6ecc7717620b 100644 --- a/source/Utility/Status.cpp +++ b/source/Utility/Status.cpp @@ -11,10 +11,11 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/VASPrintf.h" -#include "lldb/lldb-defines.h" // for LLDB_GENERIC_ERROR -#include "lldb/lldb-enumerations.h" // for ErrorType, ErrorType::eErr... -#include "llvm/ADT/SmallString.h" // for SmallString -#include "llvm/ADT/StringRef.h" // for StringRef +#include "lldb/lldb-defines.h" // for LLDB_GENERIC_ERROR +#include "lldb/lldb-enumerations.h" // for ErrorType, ErrorType::eErr... +#include "llvm/ADT/SmallString.h" // for SmallString +#include "llvm/ADT/StringRef.h" // for StringRef +#include "llvm/Support/Errno.h" #include "llvm/Support/FormatProviders.h" // for format_provider #include <cerrno> @@ -27,7 +28,6 @@ #endif #include <stdint.h> // for uint32_t -#include <string.h> // for strerror namespace llvm { class raw_ostream; @@ -121,23 +121,21 @@ const char *Status::AsCString(const char *default_error_str) const { return nullptr; if (m_string.empty()) { - const char *s = nullptr; switch (m_type) { case eErrorTypeMachKernel: #if defined(__APPLE__) - s = ::mach_error_string(m_code); + if (const char *s = ::mach_error_string(m_code)) + m_string.assign(s); #endif break; case eErrorTypePOSIX: - s = ::strerror(m_code); + m_string = llvm::sys::StrError(m_code); break; default: break; } - if (s != nullptr) - m_string.assign(s); } if (m_string.empty()) { if (default_error_str) diff --git a/source/Utility/TaskPool.cpp b/source/Utility/TaskPool.cpp index d8306dc7dc8f..d33f23cd861c 100644 --- a/source/Utility/TaskPool.cpp +++ b/source/Utility/TaskPool.cpp @@ -75,7 +75,7 @@ void TaskPoolImpl::Worker(TaskPoolImpl *pool) { } void TaskMapOverInt(size_t begin, size_t end, - std::function<void(size_t)> const &func) { + const llvm::function_ref<void(size_t)> &func) { std::atomic<size_t> idx{begin}; size_t num_workers = std::min<size_t>(end, std::thread::hardware_concurrency()); diff --git a/source/Utility/VMRange.cpp b/source/Utility/VMRange.cpp index 5eccd292a851..105b1a58c48c 100644 --- a/source/Utility/VMRange.cpp +++ b/source/Utility/VMRange.cpp @@ -25,34 +25,13 @@ using namespace lldb_private; bool VMRange::ContainsValue(const VMRange::collection &coll, lldb::addr_t value) { ValueInRangeUnaryPredicate in_range_predicate(value); - VMRange::const_iterator pos; - VMRange::const_iterator end = coll.end(); - pos = std::find_if(coll.begin(), end, in_range_predicate); - if (pos != end) - return true; - return false; + return llvm::find_if(coll, in_range_predicate) != coll.end(); } bool VMRange::ContainsRange(const VMRange::collection &coll, const VMRange &range) { RangeInRangeUnaryPredicate in_range_predicate(range); - VMRange::const_iterator pos; - VMRange::const_iterator end = coll.end(); - pos = std::find_if(coll.begin(), end, in_range_predicate); - if (pos != end) - return true; - return false; -} - -size_t VMRange::FindRangeIndexThatContainsValue(const VMRange::collection &coll, - lldb::addr_t value) { - ValueInRangeUnaryPredicate in_range_predicate(value); - VMRange::const_iterator begin = coll.begin(); - VMRange::const_iterator end = coll.end(); - VMRange::const_iterator pos = std::find_if(begin, end, in_range_predicate); - if (pos != end) - return std::distance(begin, pos); - return UINT32_MAX; + return llvm::find_if(coll, in_range_predicate) != coll.end(); } void VMRange::Dump(Stream *s, lldb::addr_t offset, uint32_t addr_width) const { @@ -66,8 +45,7 @@ bool lldb_private::operator==(const VMRange &lhs, const VMRange &rhs) { } bool lldb_private::operator!=(const VMRange &lhs, const VMRange &rhs) { - return lhs.GetBaseAddress() != rhs.GetBaseAddress() || - lhs.GetEndAddress() != rhs.GetEndAddress(); + return !(lhs == rhs); } bool lldb_private::operator<(const VMRange &lhs, const VMRange &rhs) { @@ -79,25 +57,13 @@ bool lldb_private::operator<(const VMRange &lhs, const VMRange &rhs) { } bool lldb_private::operator<=(const VMRange &lhs, const VMRange &rhs) { - if (lhs.GetBaseAddress() < rhs.GetBaseAddress()) - return true; - else if (lhs.GetBaseAddress() > rhs.GetBaseAddress()) - return false; - return lhs.GetEndAddress() <= rhs.GetEndAddress(); + return !(lhs > rhs); } bool lldb_private::operator>(const VMRange &lhs, const VMRange &rhs) { - if (lhs.GetBaseAddress() > rhs.GetBaseAddress()) - return true; - else if (lhs.GetBaseAddress() < rhs.GetBaseAddress()) - return false; - return lhs.GetEndAddress() > rhs.GetEndAddress(); + return rhs < lhs; } bool lldb_private::operator>=(const VMRange &lhs, const VMRange &rhs) { - if (lhs.GetBaseAddress() > rhs.GetBaseAddress()) - return true; - else if (lhs.GetBaseAddress() < rhs.GetBaseAddress()) - return false; - return lhs.GetEndAddress() >= rhs.GetEndAddress(); + return !(lhs < rhs); } diff --git a/tools/lldb-server/lldb-gdbserver.cpp b/tools/lldb-server/lldb-gdbserver.cpp index 6139bfabee3d..412d775e8394 100644 --- a/tools/lldb-server/lldb-gdbserver.cpp +++ b/tools/lldb-server/lldb-gdbserver.cpp @@ -21,8 +21,6 @@ // C++ Includes -// Other libraries and framework includes -#include "llvm/ADT/StringRef.h" #include "Acceptor.h" #include "LLDBServerUtilities.h" @@ -36,6 +34,8 @@ #include "lldb/Host/Socket.h" #include "lldb/Host/StringConvert.h" #include "lldb/Utility/Status.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Errno.h" #ifndef LLGS_PROGRAM_NAME #define LLGS_PROGRAM_NAME "lldb-server" @@ -398,10 +398,9 @@ int main_gdbserver(int argc, char *argv[]) { { const ::pid_t new_sid = setsid(); if (new_sid == -1) { - const char *errno_str = strerror(errno); - fprintf(stderr, "failed to set new session id for %s (%s)\n", - LLGS_PROGRAM_NAME, - errno_str ? errno_str : "<no error string>"); + llvm::errs() << llvm::formatv( + "failed to set new session id for {0} ({1})\n", LLGS_PROGRAM_NAME, + llvm::sys::StrError()); } } break; diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index f78879db09b4..c7c3140b121a 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -68,9 +68,10 @@ add_subdirectory(Signals) add_subdirectory(Symbol) add_subdirectory(SymbolFile) add_subdirectory(Target) +add_subdirectory(tools) add_subdirectory(UnwindAssembly) add_subdirectory(Utility) if(LLDB_CAN_USE_DEBUGSERVER) add_subdirectory(debugserver) -endif()
\ No newline at end of file +endif() diff --git a/unittests/Core/ArchSpecTest.cpp b/unittests/Core/ArchSpecTest.cpp index 8fed7adba07c..98b77e1826b1 100644 --- a/unittests/Core/ArchSpecTest.cpp +++ b/unittests/Core/ArchSpecTest.cpp @@ -11,7 +11,7 @@ #include "lldb/Core/ArchSpec.h" -#include "llvm/Support/MachO.h" +#include "llvm/BinaryFormat/MachO.h" using namespace lldb; using namespace lldb_private; diff --git a/unittests/Core/StructuredDataTest.cpp b/unittests/Core/StructuredDataTest.cpp index cac330304179..cdcf3236cd77 100644 --- a/unittests/Core/StructuredDataTest.cpp +++ b/unittests/Core/StructuredDataTest.cpp @@ -12,7 +12,7 @@ #include "lldb/Core/StructuredData.h" #include "lldb/Utility/StreamString.h" -#include "llvm/Support/MachO.h" +#include "llvm/BinaryFormat/MachO.h" using namespace lldb; using namespace lldb_private; diff --git a/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp index c9ab0b6050a0..8f6f9f0684a3 100644 --- a/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ b/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -318,8 +318,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) { if (HasFailure()) return; - const lldb::tid_t tid = 0x47; - const uint32_t reg_num = 4; std::future<Status> result = std::async(std::launch::async, [&] { return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11}); }); @@ -406,7 +404,7 @@ TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) { R"( {"psb" : 1,"tracetech" : "intel-pt"},"threadid" : 35,"type" : 1})"; HandlePacket(server, (expected_packet1 + expected_packet2), "1"); ASSERT_TRUE(error.Success()); - ASSERT_EQ(result.get(), 1); + ASSERT_EQ(result.get(), 1u); error.Clear(); result = std::async(std::launch::async, [&] { @@ -468,7 +466,7 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) { std::string expected_packet2 = R"("traceid" : 3})"; HandlePacket(server, expected_packet1+expected_packet2, "123456"); ASSERT_TRUE(result.get().Success()); - ASSERT_EQ(buffer.size(), 3); + ASSERT_EQ(buffer.size(), 3u); ASSERT_EQ(buf[0], 0x12); ASSERT_EQ(buf[1], 0x34); ASSERT_EQ(buf[2], 0x56); @@ -480,7 +478,7 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) { HandlePacket(server, expected_packet1+expected_packet2, "E23"); ASSERT_FALSE(result.get().Success()); - ASSERT_EQ(buffer2.size(), 0); + ASSERT_EQ(buffer2.size(), 0u); } TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) { @@ -506,7 +504,7 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) { std::string expected_packet2 = R"("traceid" : 3})"; HandlePacket(server, expected_packet1+expected_packet2, "123456"); ASSERT_TRUE(result.get().Success()); - ASSERT_EQ(buffer.size(), 3); + ASSERT_EQ(buffer.size(), 3u); ASSERT_EQ(buf[0], 0x12); ASSERT_EQ(buf[1], 0x34); ASSERT_EQ(buf[2], 0x56); @@ -518,7 +516,7 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) { HandlePacket(server, expected_packet1+expected_packet2, "E23"); ASSERT_FALSE(result.get().Success()); - ASSERT_EQ(buffer2.size(), 0); + ASSERT_EQ(buffer2.size(), 0u); } TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) { @@ -545,8 +543,8 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) { R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])"; HandlePacket(server, expected_packet, response1+response2); ASSERT_TRUE(result.get().Success()); - ASSERT_EQ(options.getTraceBufferSize(), 8192); - ASSERT_EQ(options.getMetaDataBufferSize(), 8192); + ASSERT_EQ(options.getTraceBufferSize(), 8192u); + ASSERT_EQ(options.getMetaDataBufferSize(), 8192u); ASSERT_EQ(options.getType(), 1); auto custom_params = options.getTraceParams(); @@ -556,9 +554,8 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) { ASSERT_TRUE(custom_params); ASSERT_EQ(custom_params->GetType(), eStructuredDataTypeDictionary); - ASSERT_TRUE( - custom_params->GetValueForKeyAsInteger<uint64_t>("psb", psb_value)); - ASSERT_EQ(psb_value, 1); + ASSERT_TRUE(custom_params->GetValueForKeyAsInteger("psb", psb_value)); + ASSERT_EQ(psb_value, 1u); ASSERT_TRUE( custom_params->GetValueForKeyAsString("tracetech", trace_tech_value)); ASSERT_STREQ(trace_tech_value.data(), "intel-pt"); diff --git a/unittests/tools/CMakeLists.txt b/unittests/tools/CMakeLists.txt new file mode 100644 index 000000000000..2d41864d98f4 --- /dev/null +++ b/unittests/tools/CMakeLists.txt @@ -0,0 +1,3 @@ +if(CMAKE_SYSTEM_NAME MATCHES "Android|Linux|NetBSD") + add_subdirectory(lldb-server) +endif() diff --git a/unittests/tools/lldb-server/CMakeLists.txt b/unittests/tools/lldb-server/CMakeLists.txt new file mode 100644 index 000000000000..b7113c3d260c --- /dev/null +++ b/unittests/tools/lldb-server/CMakeLists.txt @@ -0,0 +1,13 @@ +function(add_lldb_test_executable test_name) + set(EXCLUDE_FROM_ALL ON) + add_llvm_executable(${test_name} NO_INSTALL_RPATH ${ARGN}) + set(outdir ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}) + set_output_directory(${test_name} BINARY_DIR ${outdir} LIBRARY_DIR ${outdir}) +endfunction() + +add_lldb_test_executable(thread_inferior inferior/thread_inferior.cpp) + +add_definitions(-DLLDB_SERVER="$<TARGET_FILE:lldb-server>") +add_definitions(-DTHREAD_INFERIOR="${CMAKE_CURRENT_BINARY_DIR}/thread_inferior") +add_subdirectory(tests) +add_dependencies(LLDBServerTests thread_inferior) diff --git a/unittests/tools/lldb-server/inferior/thread_inferior.cpp b/unittests/tools/lldb-server/inferior/thread_inferior.cpp new file mode 100644 index 000000000000..d968e9ef71ea --- /dev/null +++ b/unittests/tools/lldb-server/inferior/thread_inferior.cpp @@ -0,0 +1,41 @@ +//===-- thread_inferior.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <atomic> +#include <chrono> +#include <string> +#include <thread> +#include <vector> + +int main(int argc, char* argv[]) { + int thread_count = 2; + if (argc > 1) { + thread_count = std::stoi(argv[1], nullptr, 10); + } + + std::atomic<bool> delay(true); + std::vector<std::thread> threads; + for (int i = 0; i < thread_count; i++) { + threads.push_back(std::thread([&delay] { + while (delay.load()) + std::this_thread::sleep_for(std::chrono::seconds(1)); + })); + } + + // Cause a break. + volatile char *p = NULL; + *p = 'a'; + + delay.store(false); + for (std::thread& t : threads) { + t.join(); + } + + return 0; +} diff --git a/unittests/tools/lldb-server/tests/CMakeLists.txt b/unittests/tools/lldb-server/tests/CMakeLists.txt new file mode 100644 index 000000000000..4ef4165b27fe --- /dev/null +++ b/unittests/tools/lldb-server/tests/CMakeLists.txt @@ -0,0 +1,15 @@ +add_lldb_unittest(LLDBServerTests + TestClient.cpp + MessageObjects.cpp + ThreadIdsInJstopinfoTest.cpp + + LINK_LIBS + lldbHost + lldbCore + lldbInterpreter + lldbTarget + lldbPluginPlatformLinux + lldbPluginProcessGDBRemote + LINK_COMPONENTS + Support + ) diff --git a/unittests/tools/lldb-server/tests/MessageObjects.cpp b/unittests/tools/lldb-server/tests/MessageObjects.cpp new file mode 100644 index 000000000000..fd44bf6b23a9 --- /dev/null +++ b/unittests/tools/lldb-server/tests/MessageObjects.cpp @@ -0,0 +1,207 @@ +//===-- MessageObjects.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MessageObjects.h" +#include "lldb/Core/StructuredData.h" +#include "llvm/ADT/StringExtras.h" +#include "gtest/gtest.h" + +using namespace lldb_private; +using namespace llvm; +using namespace llvm::support; +namespace llgs_tests { + +Expected<ProcessInfo> ProcessInfo::Create(StringRef response) { + ProcessInfo process_info; + auto elements_or_error = SplitPairList("ProcessInfo", response); + if (!elements_or_error) + return elements_or_error.takeError(); + + auto &elements = *elements_or_error; + if (elements["pid"].getAsInteger(16, process_info.m_pid)) + return make_parsing_error("ProcessInfo: pid"); + if (elements["parent-pid"].getAsInteger(16, process_info.m_parent_pid)) + return make_parsing_error("ProcessInfo: parent-pid"); + if (elements["real-uid"].getAsInteger(16, process_info.m_real_uid)) + return make_parsing_error("ProcessInfo: real-uid"); + if (elements["real-gid"].getAsInteger(16, process_info.m_real_gid)) + return make_parsing_error("ProcessInfo: real-uid"); + if (elements["effective-uid"].getAsInteger(16, process_info.m_effective_uid)) + return make_parsing_error("ProcessInfo: effective-uid"); + if (elements["effective-gid"].getAsInteger(16, process_info.m_effective_gid)) + return make_parsing_error("ProcessInfo: effective-gid"); + if (elements["ptrsize"].getAsInteger(10, process_info.m_ptrsize)) + return make_parsing_error("ProcessInfo: ptrsize"); + + process_info.m_triple = fromHex(elements["triple"]); + StringRef endian_str = elements["endian"]; + if (endian_str == "little") + process_info.m_endian = support::little; + else if (endian_str == "big") + process_info.m_endian = support::big; + else + return make_parsing_error("ProcessInfo: endian"); + + return process_info; +} + +lldb::pid_t ProcessInfo::GetPid() const { return m_pid; } + +endianness ProcessInfo::GetEndian() const { return m_endian; } + +//====== ThreadInfo ============================================================ +ThreadInfo::ThreadInfo(StringRef name, StringRef reason, + const RegisterMap ®isters, unsigned int signal) + : m_name(name.str()), m_reason(reason.str()), m_registers(registers), + m_signal(signal) {} + +StringRef ThreadInfo::ReadRegister(unsigned int register_id) const { + return m_registers.lookup(register_id); +} + +bool ThreadInfo::ReadRegisterAsUint64(unsigned int register_id, + uint64_t &value) const { + StringRef value_str(m_registers.lookup(register_id)); + if (value_str.getAsInteger(16, value)) { + GTEST_LOG_(ERROR) + << formatv("ThreadInfo: Unable to parse register value at {0}.", + register_id) + .str(); + return false; + } + + sys::swapByteOrder(value); + return true; +} + +//====== JThreadsInfo ========================================================== +Expected<JThreadsInfo> JThreadsInfo::Create(StringRef response, + endianness endian) { + JThreadsInfo jthreads_info; + + StructuredData::ObjectSP json = StructuredData::ParseJSON(response); + StructuredData::Array *array = json->GetAsArray(); + if (!array) + return make_parsing_error("JThreadsInfo: JSON array"); + + for (size_t i = 0; i < array->GetSize(); i++) { + StructuredData::Dictionary *thread_info; + array->GetItemAtIndexAsDictionary(i, thread_info); + if (!thread_info) + return make_parsing_error("JThreadsInfo: JSON obj at {0}", i); + + StringRef name, reason; + thread_info->GetValueForKeyAsString("name", name); + thread_info->GetValueForKeyAsString("reason", reason); + uint64_t signal; + thread_info->GetValueForKeyAsInteger("signal", signal); + uint64_t tid; + thread_info->GetValueForKeyAsInteger("tid", tid); + + StructuredData::Dictionary *register_dict; + thread_info->GetValueForKeyAsDictionary("registers", register_dict); + if (!register_dict) + return make_parsing_error("JThreadsInfo: registers JSON obj"); + + RegisterMap registers; + + auto keys_obj = register_dict->GetKeys(); + auto keys = keys_obj->GetAsArray(); + for (size_t i = 0; i < keys->GetSize(); i++) { + StringRef key_str, value_str; + keys->GetItemAtIndexAsString(i, key_str); + register_dict->GetValueForKeyAsString(key_str, value_str); + unsigned int register_id; + if (key_str.getAsInteger(10, register_id)) + return make_parsing_error("JThreadsInfo: register key[{0}]", i); + + registers[register_id] = value_str.str(); + } + + jthreads_info.m_thread_infos[tid] = + ThreadInfo(name, reason, registers, signal); + } + + return jthreads_info; +} + +const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const { + return m_thread_infos; +} + +//====== StopReply ============================================================= +const U64Map &StopReply::GetThreadPcs() const { return m_thread_pcs; } + +Expected<StopReply> StopReply::Create(StringRef response, + llvm::support::endianness endian) { + StopReply stop_reply; + + auto elements_or_error = SplitPairList("StopReply", response); + if (auto split_error = elements_or_error.takeError()) { + return std::move(split_error); + } + + auto elements = *elements_or_error; + stop_reply.m_name = elements["name"]; + stop_reply.m_reason = elements["reason"]; + + SmallVector<StringRef, 20> threads; + SmallVector<StringRef, 20> pcs; + elements["threads"].split(threads, ','); + elements["thread-pcs"].split(pcs, ','); + if (threads.size() != pcs.size()) + return make_parsing_error("StopReply: thread/PC count mismatch"); + + for (size_t i = 0; i < threads.size(); i++) { + lldb::tid_t thread_id; + uint64_t pc; + if (threads[i].getAsInteger(16, thread_id)) + return make_parsing_error("StopReply: thread ID at [{0}].", i); + if (pcs[i].getAsInteger(16, pc)) + return make_parsing_error("StopReply: thread PC at [{0}].", i); + + stop_reply.m_thread_pcs[thread_id] = pc; + } + + for (auto i = elements.begin(); i != elements.end(); i++) { + StringRef key = i->getKey(); + StringRef val = i->getValue(); + if (key.size() >= 9 && key[0] == 'T' && key.substr(3, 6) == "thread") { + if (val.getAsInteger(16, stop_reply.m_thread)) + return make_parsing_error("StopReply: thread id"); + if (key.substr(1, 2).getAsInteger(16, stop_reply.m_signal)) + return make_parsing_error("StopReply: stop signal"); + } else if (key.size() == 2) { + unsigned int reg; + if (!key.getAsInteger(16, reg)) { + stop_reply.m_registers[reg] = val.str(); + } + } + } + + return stop_reply; +} + +//====== Globals =============================================================== +Expected<StringMap<StringRef>> SplitPairList(StringRef caller, StringRef str) { + SmallVector<StringRef, 20> elements; + str.split(elements, ';'); + + StringMap<StringRef> pairs; + for (StringRef s : elements) { + std::pair<StringRef, StringRef> pair = s.split(':'); + if (pairs.count(pair.first)) + return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first); + + pairs.insert(s.split(':')); + } + + return pairs; +} +} // namespace llgs_tests diff --git a/unittests/tools/lldb-server/tests/MessageObjects.h b/unittests/tools/lldb-server/tests/MessageObjects.h new file mode 100644 index 000000000000..82551e2bb549 --- /dev/null +++ b/unittests/tools/lldb-server/tests/MessageObjects.h @@ -0,0 +1,102 @@ +//===-- MessageObjects.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-types.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FormatVariadic.h" +#include <string> + +namespace llgs_tests { +class ThreadInfo; +typedef llvm::DenseMap<uint64_t, ThreadInfo> ThreadInfoMap; +typedef llvm::DenseMap<uint64_t, uint64_t> U64Map; +typedef llvm::DenseMap<unsigned int, std::string> RegisterMap; + +class ProcessInfo { +public: + static llvm::Expected<ProcessInfo> Create(llvm::StringRef response); + lldb::pid_t GetPid() const; + llvm::support::endianness GetEndian() const; + +private: + ProcessInfo() = default; + lldb::pid_t m_pid; + lldb::pid_t m_parent_pid; + uint32_t m_real_uid; + uint32_t m_real_gid; + uint32_t m_effective_uid; + uint32_t m_effective_gid; + std::string m_triple; + llvm::SmallString<16> m_ostype; + llvm::support::endianness m_endian; + unsigned int m_ptrsize; +}; + +class ThreadInfo { +public: + ThreadInfo() = default; + ThreadInfo(llvm::StringRef name, llvm::StringRef reason, + const RegisterMap ®isters, unsigned int signal); + + llvm::StringRef ReadRegister(unsigned int register_id) const; + bool ReadRegisterAsUint64(unsigned int register_id, uint64_t &value) const; + +private: + std::string m_name; + std::string m_reason; + RegisterMap m_registers; + unsigned int m_signal; +}; + +class JThreadsInfo { +public: + static llvm::Expected<JThreadsInfo> Create(llvm::StringRef response, + llvm::support::endianness endian); + + const ThreadInfoMap &GetThreadInfos() const; + +private: + JThreadsInfo() = default; + ThreadInfoMap m_thread_infos; +}; + +class StopReply { +public: + static llvm::Expected<StopReply> Create(llvm::StringRef response, + llvm::support::endianness endian); + const U64Map &GetThreadPcs() const; + +private: + StopReply() = default; + void ParseResponse(llvm::StringRef response, + llvm::support::endianness endian); + unsigned int m_signal; + lldb::tid_t m_thread; + std::string m_name; + U64Map m_thread_pcs; + RegisterMap m_registers; + std::string m_reason; +}; + +// Common functions for parsing packet data. +llvm::Expected<llvm::StringMap<llvm::StringRef>> +SplitPairList(llvm::StringRef caller, llvm::StringRef s); + +template <typename... Args> +llvm::Error make_parsing_error(llvm::StringRef format, Args &&... args) { + std::string error = + "Unable to parse " + + llvm::formatv(format.data(), std::forward<Args>(args)...).str(); + return llvm::make_error<llvm::StringError>(error, + llvm::inconvertibleErrorCode()); +} +} // namespace llgs_tests diff --git a/unittests/tools/lldb-server/tests/TestClient.cpp b/unittests/tools/lldb-server/tests/TestClient.cpp new file mode 100644 index 000000000000..540d7979055c --- /dev/null +++ b/unittests/tools/lldb-server/tests/TestClient.cpp @@ -0,0 +1,287 @@ +//===-- TestClient.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TestClient.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" +#include "lldb/Host/posix/ProcessLauncherPosix.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Target/ProcessLaunchInfo.h" +#include "llvm/ADT/StringExtras.h" +#include "gtest/gtest.h" +#include <cstdlib> +#include <future> +#include <sstream> +#include <string> + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +namespace llgs_tests { +void TestClient::Initialize() { HostInfo::Initialize(); } + +TestClient::TestClient(const std::string &test_name, + const std::string &test_case_name) + : m_test_name(test_name), m_test_case_name(test_case_name), + m_pc_register(UINT_MAX) {} + +TestClient::~TestClient() {} + +bool TestClient::StartDebugger() { + const ArchSpec &arch_spec = HostInfo::GetArchitecture(); + Args args; + args.AppendArgument(LLDB_SERVER); + args.AppendArgument("gdbserver"); + args.AppendArgument("--log-channels=gdb-remote packets"); + args.AppendArgument("--reverse-connect"); + std::string log_file_name = GenerateLogFileName(arch_spec); + if (log_file_name.size()) { + args.AppendArgument("--log-file=" + log_file_name); + } + + Status error; + TCPSocket listen_socket(true, false); + error = listen_socket.Listen("127.0.0.1:0", 5); + if (error.Fail()) { + GTEST_LOG_(ERROR) << "Unable to open listen socket."; + return false; + } + + char connect_remote_address[64]; + snprintf(connect_remote_address, sizeof(connect_remote_address), + "localhost:%u", listen_socket.GetLocalPortNumber()); + + args.AppendArgument(connect_remote_address); + + m_server_process_info.SetArchitecture(arch_spec); + m_server_process_info.SetArguments(args, true); + Status status = Host::LaunchProcess(m_server_process_info); + if (status.Fail()) { + GTEST_LOG_(ERROR) + << formatv("Failure to launch lldb server: {0}.", status).str(); + return false; + } + + char connect_remote_uri[64]; + snprintf(connect_remote_uri, sizeof(connect_remote_uri), "connect://%s", + connect_remote_address); + Socket *accept_socket; + listen_socket.Accept(accept_socket); + SetConnection(new ConnectionFileDescriptor(accept_socket)); + + SendAck(); // Send this as a handshake. + return true; +} + +bool TestClient::StopDebugger() { + std::string response; + return SendMessage("k", response, PacketResult::ErrorDisconnected); +} + +bool TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) { + std::stringstream command; + command << "A"; + for (size_t i = 0; i < inferior_args.size(); i++) { + if (i > 0) + command << ','; + std::string hex_encoded = toHex(inferior_args[i]); + command << hex_encoded.size() << ',' << i << ',' << hex_encoded; + } + + if (!SendMessage(command.str())) + return false; + if (!SendMessage("qLaunchSuccess")) + return false; + std::string response; + if (!SendMessage("qProcessInfo", response)) + return false; + auto create_or_error = ProcessInfo::Create(response); + if (auto create_error = create_or_error.takeError()) { + GTEST_LOG_(ERROR) << toString(std::move(create_error)); + return false; + } + + m_process_info = *create_or_error; + return true; +} + +bool TestClient::ListThreadsInStopReply() { + return SendMessage("QListThreadsInStopReply"); +} + +bool TestClient::SetBreakpoint(unsigned long address) { + std::stringstream command; + command << "Z0," << std::hex << address << ",1"; + return SendMessage(command.str()); +} + +bool TestClient::ContinueAll() { return Continue("vCont;c"); } + +bool TestClient::ContinueThread(unsigned long thread_id) { + return Continue(formatv("vCont;c:{0:x-}", thread_id).str()); +} + +const ProcessInfo &TestClient::GetProcessInfo() { return *m_process_info; } + +Optional<JThreadsInfo> TestClient::GetJThreadsInfo() { + std::string response; + if (!SendMessage("jThreadsInfo", response)) + return llvm::None; + auto creation = JThreadsInfo::Create(response, m_process_info->GetEndian()); + if (auto create_error = creation.takeError()) { + GTEST_LOG_(ERROR) << toString(std::move(create_error)); + return llvm::None; + } + + return std::move(*creation); +} + +const StopReply &TestClient::GetLatestStopReply() { + return m_stop_reply.getValue(); +} + +bool TestClient::SendMessage(StringRef message) { + std::string dummy_string; + return SendMessage(message, dummy_string); +} + +bool TestClient::SendMessage(StringRef message, std::string &response_string) { + if (!SendMessage(message, response_string, PacketResult::Success)) + return false; + else if (response_string[0] == 'E') { + GTEST_LOG_(ERROR) << "Error " << response_string + << " while sending message: " << message.str(); + return false; + } + + return true; +} + +bool TestClient::SendMessage(StringRef message, std::string &response_string, + PacketResult expected_result) { + StringExtractorGDBRemote response; + GTEST_LOG_(INFO) << "Send Packet: " << message.str(); + PacketResult result = SendPacketAndWaitForResponse(message, response, false); + response.GetEscapedBinaryData(response_string); + GTEST_LOG_(INFO) << "Read Packet: " << response_string; + if (result != expected_result) { + GTEST_LOG_(ERROR) << FormatFailedResult(message, result); + return false; + } + + return true; +} + +unsigned int TestClient::GetPcRegisterId() { + if (m_pc_register != UINT_MAX) + return m_pc_register; + + for (unsigned int register_id = 0;; register_id++) { + std::string message = formatv("qRegisterInfo{0:x-}", register_id).str(); + std::string response; + if (!SendMessage(message, response)) { + GTEST_LOG_(ERROR) << "Unable to query register ID for PC register."; + return UINT_MAX; + } + + auto elements_or_error = SplitPairList("GetPcRegisterId", response); + if (auto split_error = elements_or_error.takeError()) { + GTEST_LOG_(ERROR) << "GetPcRegisterId: Error splitting response: " + << response; + return UINT_MAX; + } + + auto elements = *elements_or_error; + if (elements["alt-name"] == "pc" || elements["generic"] == "pc") { + m_pc_register = register_id; + break; + } + } + + return m_pc_register; +} + +bool TestClient::Continue(StringRef message) { + if (!m_process_info.hasValue()) { + GTEST_LOG_(ERROR) << "Continue() called before m_process_info initialized."; + return false; + } + + std::string response; + if (!SendMessage(message, response)) + return false; + auto creation = StopReply::Create(response, m_process_info->GetEndian()); + if (auto create_error = creation.takeError()) { + GTEST_LOG_(ERROR) << toString(std::move(create_error)); + return false; + } + + m_stop_reply = std::move(*creation); + return true; +} + +std::string TestClient::GenerateLogFileName(const ArchSpec &arch) const { + char *log_directory = getenv("LOG_FILE_DIRECTORY"); + if (!log_directory) + return ""; + + if (!llvm::sys::fs::is_directory(log_directory)) { + GTEST_LOG_(WARNING) << "Cannot access log directory: " << log_directory; + return ""; + } + + std::string log_file_name; + raw_string_ostream log_file(log_file_name); + log_file << log_directory << "/lldb-" << m_test_case_name << '-' + << m_test_name << '-' << arch.GetArchitectureName() << ".log"; + return log_file.str(); +} + +std::string TestClient::FormatFailedResult(const std::string &message, + PacketResult result) { + std::string formatted_error; + raw_string_ostream error_stream(formatted_error); + error_stream << "Failure sending message: " << message << " Result: "; + + switch (result) { + case PacketResult::ErrorSendFailed: + error_stream << "ErrorSendFailed"; + break; + case PacketResult::ErrorSendAck: + error_stream << "ErrorSendAck"; + break; + case PacketResult::ErrorReplyFailed: + error_stream << "ErrorReplyFailed"; + break; + case PacketResult::ErrorReplyTimeout: + error_stream << "ErrorReplyTimeout"; + break; + case PacketResult::ErrorReplyInvalid: + error_stream << "ErrorReplyInvalid"; + break; + case PacketResult::ErrorReplyAck: + error_stream << "ErrorReplyAck"; + break; + case PacketResult::ErrorDisconnected: + error_stream << "ErrorDisconnected"; + break; + case PacketResult::ErrorNoSequenceLock: + error_stream << "ErrorNoSequenceLock"; + break; + default: + error_stream << "Unknown Error"; + } + + error_stream.str(); + return formatted_error; +} +} // namespace llgs_tests diff --git a/unittests/tools/lldb-server/tests/TestClient.h b/unittests/tools/lldb-server/tests/TestClient.h new file mode 100644 index 000000000000..ae620cc97207 --- /dev/null +++ b/unittests/tools/lldb-server/tests/TestClient.h @@ -0,0 +1,61 @@ +//===-- TestClient.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MessageObjects.h" +#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Target/ProcessLaunchInfo.h" +#include "llvm/ADT/Optional.h" +#include <memory> +#include <string> + +namespace llgs_tests { +// TODO: Make the test client an abstract base class, with different children +// for different types of connections: llgs v. debugserver +class TestClient + : public lldb_private::process_gdb_remote::GDBRemoteCommunicationClient { +public: + static void Initialize(); + TestClient(const std::string &test_name, const std::string &test_case_name); + virtual ~TestClient(); + LLVM_NODISCARD bool StartDebugger(); + LLVM_NODISCARD bool StopDebugger(); + LLVM_NODISCARD bool SetInferior(llvm::ArrayRef<std::string> inferior_args); + LLVM_NODISCARD bool ListThreadsInStopReply(); + LLVM_NODISCARD bool SetBreakpoint(unsigned long address); + LLVM_NODISCARD bool ContinueAll(); + LLVM_NODISCARD bool ContinueThread(unsigned long thread_id); + const ProcessInfo &GetProcessInfo(); + llvm::Optional<JThreadsInfo> GetJThreadsInfo(); + const StopReply &GetLatestStopReply(); + LLVM_NODISCARD bool SendMessage(llvm::StringRef message); + LLVM_NODISCARD bool SendMessage(llvm::StringRef message, + std::string &response_string); + LLVM_NODISCARD bool SendMessage(llvm::StringRef message, + std::string &response_string, + PacketResult expected_result); + unsigned int GetPcRegisterId(); + +private: + LLVM_NODISCARD bool Continue(llvm::StringRef message); + LLVM_NODISCARD bool GenerateConnectionAddress(std::string &address); + std::string GenerateLogFileName(const lldb_private::ArchSpec &arch) const; + std::string FormatFailedResult( + const std::string &message, + lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult + result); + + llvm::Optional<ProcessInfo> m_process_info; + llvm::Optional<StopReply> m_stop_reply; + lldb_private::ProcessLaunchInfo m_server_process_info; + std::string m_test_name; + std::string m_test_case_name; + unsigned int m_pc_register; +}; +} // namespace llgs_tests diff --git a/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp b/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp new file mode 100644 index 000000000000..961b0a3b3167 --- /dev/null +++ b/unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp @@ -0,0 +1,58 @@ +//===-- ThreadsInJstopinfoTest.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TestClient.h" +#include "gtest/gtest.h" +#include <string> + +using namespace llgs_tests; + +class ThreadsInJstopinfoTest : public ::testing::Test { +protected: + virtual void SetUp() { TestClient::Initialize(); } +}; + +TEST_F(ThreadsInJstopinfoTest, TestStopReplyContainsThreadPcsLlgs) { + std::vector<std::string> inferior_args; + // This inferior spawns N threads, then forces a break. + inferior_args.push_back(THREAD_INFERIOR); + inferior_args.push_back("4"); + + auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); + + TestClient client(test_info->name(), test_info->test_case_name()); + ASSERT_TRUE(client.StartDebugger()); + ASSERT_TRUE(client.SetInferior(inferior_args)); + ASSERT_TRUE(client.ListThreadsInStopReply()); + ASSERT_TRUE(client.ContinueAll()); + unsigned int pc_reg = client.GetPcRegisterId(); + ASSERT_NE(pc_reg, UINT_MAX); + + auto jthreads_info = client.GetJThreadsInfo(); + ASSERT_TRUE(jthreads_info); + + auto stop_reply = client.GetLatestStopReply(); + auto stop_reply_pcs = stop_reply.GetThreadPcs(); + auto thread_infos = jthreads_info->GetThreadInfos(); + ASSERT_EQ(stop_reply_pcs.size(), thread_infos.size()) + << "Thread count mismatch."; + + for (auto stop_reply_pc : stop_reply_pcs) { + unsigned long tid = stop_reply_pc.first; + ASSERT_TRUE(thread_infos.find(tid) != thread_infos.end()) + << "Thread ID: " << tid << " not in JThreadsInfo."; + uint64_t pc_value; + ASSERT_TRUE(thread_infos[tid].ReadRegisterAsUint64(pc_reg, pc_value)) + << "Failure reading ThreadInfo register " << pc_reg; + ASSERT_EQ(stop_reply_pcs[tid], pc_value) + << "Mismatched PC for thread: " << tid; + } + + ASSERT_TRUE(client.StopDebugger()); +} |