aboutsummaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:26:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:26:05 +0000
commit14f1b3e8826ce43b978db93a62d1166055db5394 (patch)
tree0a00ad8d3498783fe0193f3b656bca17c4c8697d /unittests
parent4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff)
downloadsrc-14f1b3e8826ce43b978db93a62d1166055db5394.tar.gz
src-14f1b3e8826ce43b978db93a62d1166055db5394.zip
Vendor import of lldb trunk r290819:vendor/lldb/lldb-trunk-r290819
Notes
Notes: svn path=/vendor/lldb/dist/; revision=311128 svn path=/vendor/lldb/lldb-trunk-r290819/; revision=311129; tag=vendor/lldb/lldb-trunk-r290819
Diffstat (limited to 'unittests')
-rw-r--r--unittests/Breakpoint/BreakpointIDTest.cpp30
-rw-r--r--unittests/Breakpoint/CMakeLists.txt3
-rw-r--r--unittests/CMakeLists.txt13
-rw-r--r--unittests/Core/ArchSpecTest.cpp136
-rw-r--r--unittests/Core/BroadcasterTest.cpp74
-rw-r--r--unittests/Core/CMakeLists.txt5
-rw-r--r--unittests/Core/DataExtractorTest.cpp49
-rw-r--r--unittests/Core/ListenerTest.cpp114
-rw-r--r--unittests/Core/ScalarTest.cpp184
-rw-r--r--unittests/Core/StructuredDataTest.cpp32
-rw-r--r--unittests/Core/TimerTest.cpp72
-rw-r--r--unittests/Editline/EditlineTest.cpp493
-rw-r--r--unittests/Expression/GoParserTest.cpp434
-rw-r--r--unittests/Host/CMakeLists.txt1
-rw-r--r--unittests/Host/FileSpecTest.cpp353
-rw-r--r--unittests/Host/FileSystemTest.cpp32
-rw-r--r--unittests/Host/SocketAddressTest.cpp88
-rw-r--r--unittests/Host/SocketTest.cpp328
-rw-r--r--unittests/Host/SymbolsTest.cpp26
-rw-r--r--unittests/Interpreter/TestArgs.cpp381
-rw-r--r--unittests/Language/CMakeLists.txt1
-rw-r--r--unittests/Language/CPlusPlus/CMakeLists.txt3
-rw-r--r--unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp40
-rw-r--r--unittests/Platform/CMakeLists.txt3
-rw-r--r--unittests/Platform/PlatformDarwinTest.cpp56
-rw-r--r--unittests/Process/CMakeLists.txt2
-rw-r--r--unittests/Process/gdb-remote/CMakeLists.txt5
-rw-r--r--unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp378
-rw-r--r--unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp307
-rw-r--r--unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp69
-rw-r--r--unittests/Process/gdb-remote/GDBRemoteTestUtils.h51
-rw-r--r--unittests/Process/minidump/CMakeLists.txt12
-rw-r--r--unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmpbin0 -> 6297 bytes
-rw-r--r--unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmpbin0 -> 9280561 bytes
-rw-r--r--unittests/Process/minidump/Inputs/linux-i386.dmpbin0 -> 32976 bytes
-rw-r--r--unittests/Process/minidump/Inputs/linux-x86_64.cpp28
-rw-r--r--unittests/Process/minidump/Inputs/linux-x86_64.dmpbin0 -> 38320 bytes
-rw-r--r--unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmpbin0 -> 63744 bytes
-rw-r--r--unittests/Process/minidump/MinidumpParserTest.cpp453
-rw-r--r--unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp868
-rw-r--r--unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp239
-rw-r--r--unittests/ScriptInterpreter/Python/PythonTestSuite.cpp40
-rw-r--r--unittests/ScriptInterpreter/Python/PythonTestSuite.h12
-rw-r--r--unittests/Symbol/TestClangASTContext.cpp607
-rw-r--r--unittests/SymbolFile/CMakeLists.txt5
-rw-r--r--unittests/SymbolFile/DWARF/CMakeLists.txt8
-rw-r--r--unittests/SymbolFile/DWARF/Inputs/test-dwarf.cpp (renamed from unittests/SymbolFile/PDB/Inputs/test-dwarf.cpp)12
-rw-r--r--unittests/SymbolFile/DWARF/Inputs/test-dwarf.exe (renamed from unittests/SymbolFile/PDB/Inputs/test-dwarf.exe)bin6144 -> 6144 bytes
-rw-r--r--unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp83
-rw-r--r--unittests/SymbolFile/PDB/CMakeLists.txt3
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp8
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h5
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp64
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb.cpp14
-rw-r--r--unittests/SymbolFile/PDB/Inputs/test-pdb.h5
-rw-r--r--unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp964
-rw-r--r--unittests/UnwindAssembly/CMakeLists.txt5
-rw-r--r--unittests/UnwindAssembly/InstEmulation/CMakeLists.txt3
-rw-r--r--unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp672
-rw-r--r--unittests/UnwindAssembly/x86/CMakeLists.txt3
-rw-r--r--unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp2339
-rw-r--r--unittests/Utility/CMakeLists.txt1
-rw-r--r--unittests/Utility/Inputs/TestModule.c11
-rw-r--r--unittests/Utility/ModuleCacheTest.cpp224
-rw-r--r--unittests/Utility/StringExtractorTest.cpp1054
-rw-r--r--unittests/Utility/TaskPoolTest.cpp98
-rw-r--r--unittests/Utility/TimeoutTest.cpp22
-rw-r--r--unittests/Utility/UriParserTest.cpp226
-rw-r--r--unittests/gtest_common.h6
69 files changed, 8835 insertions, 3022 deletions
diff --git a/unittests/Breakpoint/BreakpointIDTest.cpp b/unittests/Breakpoint/BreakpointIDTest.cpp
new file mode 100644
index 000000000000..a449d40a335a
--- /dev/null
+++ b/unittests/Breakpoint/BreakpointIDTest.cpp
@@ -0,0 +1,30 @@
+//===-- BreakpointIDTest.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Core/Error.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(BreakpointIDTest, StringIsBreakpointName) {
+ Error E;
+ EXPECT_FALSE(BreakpointID::StringIsBreakpointName("1breakpoint", E));
+ EXPECT_FALSE(BreakpointID::StringIsBreakpointName("-", E));
+ EXPECT_FALSE(BreakpointID::StringIsBreakpointName("", E));
+ EXPECT_FALSE(BreakpointID::StringIsBreakpointName("3.4", E));
+
+ EXPECT_TRUE(BreakpointID::StringIsBreakpointName("_", E));
+ EXPECT_TRUE(BreakpointID::StringIsBreakpointName("a123", E));
+ EXPECT_TRUE(BreakpointID::StringIsBreakpointName("test", E));
+}
diff --git a/unittests/Breakpoint/CMakeLists.txt b/unittests/Breakpoint/CMakeLists.txt
new file mode 100644
index 000000000000..ca1c282aaa66
--- /dev/null
+++ b/unittests/Breakpoint/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_unittest(LLDBBreakpointTests
+ BreakpointIDTest.cpp
+ )
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index bdcb51675a0f..a865dbe244f8 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -12,6 +12,14 @@ endif ()
include(${LLDB_PROJECT_ROOT}/cmake/LLDBDependencies.cmake)
+if (LLDB_BUILT_STANDALONE)
+ # Build the gtest library needed for unittests, if we have LLVM sources
+ # handy.
+ if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/unittest AND NOT TARGET gtest)
+ add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/unittest utils/unittest)
+ endif()
+endif()
+
function(add_lldb_unittest test_name)
add_unittest(LLDBUnitTests
${test_name}
@@ -38,12 +46,17 @@ function(add_unittest_inputs test_name inputs)
endforeach()
endfunction()
+add_subdirectory(Breakpoint)
add_subdirectory(Core)
add_subdirectory(Editline)
add_subdirectory(Expression)
add_subdirectory(Host)
add_subdirectory(Interpreter)
+add_subdirectory(Language)
+add_subdirectory(Platform)
+add_subdirectory(Process)
add_subdirectory(ScriptInterpreter)
add_subdirectory(Symbol)
add_subdirectory(SymbolFile)
+add_subdirectory(UnwindAssembly)
add_subdirectory(Utility)
diff --git a/unittests/Core/ArchSpecTest.cpp b/unittests/Core/ArchSpecTest.cpp
new file mode 100644
index 000000000000..32b363652f75
--- /dev/null
+++ b/unittests/Core/ArchSpecTest.cpp
@@ -0,0 +1,136 @@
+//===-- ArchSpecTest.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/ArchSpec.h"
+
+#include "llvm/Support/MachO.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(ArchSpecTest, TestParseMachCPUDashSubtypeTripleSimple) {
+
+ // Success conditions. Valid cpu/subtype combinations using both - and .
+ ArchSpec AS;
+ EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-10", AS));
+ EXPECT_EQ(12u, AS.GetMachOCPUType());
+ EXPECT_EQ(10u, AS.GetMachOCPUSubType());
+
+ AS = ArchSpec();
+ EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-15", AS));
+ EXPECT_EQ(12u, AS.GetMachOCPUType());
+ EXPECT_EQ(15u, AS.GetMachOCPUSubType());
+
+ AS = ArchSpec();
+ EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12.15", AS));
+ EXPECT_EQ(12u, AS.GetMachOCPUType());
+ EXPECT_EQ(15u, AS.GetMachOCPUSubType());
+
+ // Failure conditions.
+
+ // Valid string, unknown cpu/subtype.
+ AS = ArchSpec();
+ EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("13.11", AS));
+ EXPECT_EQ(0u, AS.GetMachOCPUType());
+ EXPECT_EQ(0u, AS.GetMachOCPUSubType());
+
+ // Missing / invalid cpu or subtype
+ AS = ArchSpec();
+ EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("13", AS));
+
+ AS = ArchSpec();
+ EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("13.A", AS));
+
+ AS = ArchSpec();
+ EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("A.13", AS));
+
+ // Empty string.
+ AS = ArchSpec();
+ EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("", AS));
+}
+
+TEST(ArchSpecTest, TestParseMachCPUDashSubtypeTripleExtra) {
+ ArchSpec AS;
+ EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-15-vendor-os", AS));
+ EXPECT_EQ(12u, AS.GetMachOCPUType());
+ EXPECT_EQ(15u, AS.GetMachOCPUSubType());
+ EXPECT_EQ("vendor", AS.GetTriple().getVendorName());
+ EXPECT_EQ("os", AS.GetTriple().getOSName());
+
+ AS = ArchSpec();
+ EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-10-vendor-os-name", AS));
+ EXPECT_EQ(12u, AS.GetMachOCPUType());
+ EXPECT_EQ(10u, AS.GetMachOCPUSubType());
+ EXPECT_EQ("vendor", AS.GetTriple().getVendorName());
+ EXPECT_EQ("os", AS.GetTriple().getOSName());
+
+ AS = ArchSpec();
+ EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-15-vendor.os-name", AS));
+ EXPECT_EQ(12u, AS.GetMachOCPUType());
+ EXPECT_EQ(15u, AS.GetMachOCPUSubType());
+ EXPECT_EQ("vendor.os", AS.GetTriple().getVendorName());
+ EXPECT_EQ("name", AS.GetTriple().getOSName());
+
+ // These there should parse correctly, but the vendor / OS should be defaulted
+ // since they are unrecognized.
+ AS = ArchSpec();
+ EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-10-vendor", AS));
+ EXPECT_EQ(12u, AS.GetMachOCPUType());
+ EXPECT_EQ(10u, AS.GetMachOCPUSubType());
+ EXPECT_EQ("apple", AS.GetTriple().getVendorName());
+ EXPECT_EQ("", AS.GetTriple().getOSName());
+
+ AS = ArchSpec();
+ EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("12.10.10", AS));
+
+ AS = ArchSpec();
+ EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("12-10.10", AS));
+}
+
+TEST(ArchSpecTest, TestSetTriple) {
+ ArchSpec AS;
+
+ // Various flavors of valid triples.
+ EXPECT_TRUE(AS.SetTriple("12-10-apple-darwin"));
+ EXPECT_EQ(uint32_t(llvm::MachO::CPU_TYPE_ARM), AS.GetMachOCPUType());
+ EXPECT_EQ(10u, AS.GetMachOCPUSubType());
+ EXPECT_TRUE(llvm::StringRef(AS.GetTriple().str())
+ .consume_front("armv7f-apple-darwin"));
+ EXPECT_EQ(ArchSpec::eCore_arm_armv7f, AS.GetCore());
+
+ AS = ArchSpec();
+ EXPECT_TRUE(AS.SetTriple("18.100-apple-darwin"));
+ EXPECT_EQ(uint32_t(llvm::MachO::CPU_TYPE_POWERPC), AS.GetMachOCPUType());
+ EXPECT_EQ(100u, AS.GetMachOCPUSubType());
+ EXPECT_TRUE(llvm::StringRef(AS.GetTriple().str())
+ .consume_front("powerpc-apple-darwin"));
+ EXPECT_EQ(ArchSpec::eCore_ppc_ppc970, AS.GetCore());
+
+ AS = ArchSpec();
+ EXPECT_TRUE(AS.SetTriple("i686-pc-windows"));
+ EXPECT_EQ(llvm::Triple::x86, AS.GetTriple().getArch());
+ EXPECT_EQ(llvm::Triple::PC, AS.GetTriple().getVendor());
+ EXPECT_EQ(llvm::Triple::Win32, AS.GetTriple().getOS());
+ EXPECT_TRUE(
+ llvm::StringRef(AS.GetTriple().str()).consume_front("i686-pc-windows"));
+ EXPECT_STREQ("i686", AS.GetArchitectureName());
+ EXPECT_EQ(ArchSpec::eCore_x86_32_i686, AS.GetCore());
+
+ // Various flavors of invalid triples.
+ AS = ArchSpec();
+ EXPECT_FALSE(AS.SetTriple("unknown-unknown-unknown"));
+
+ AS = ArchSpec();
+ EXPECT_FALSE(AS.SetTriple("unknown"));
+
+ AS = ArchSpec();
+ EXPECT_FALSE(AS.SetTriple(""));
+}
diff --git a/unittests/Core/BroadcasterTest.cpp b/unittests/Core/BroadcasterTest.cpp
new file mode 100644
index 000000000000..e3795822f9ac
--- /dev/null
+++ b/unittests/Core/BroadcasterTest.cpp
@@ -0,0 +1,74 @@
+//===-- BroadcasterTest.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Host/Predicate.h"
+
+#include <thread>
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(BroadcasterTest, BroadcastEvent) {
+ EventSP event_sp;
+ Broadcaster broadcaster(nullptr, "test-broadcaster");
+ std::chrono::seconds timeout(0);
+
+ // Create a listener, sign it up, make sure it recieves an event.
+ ListenerSP listener1_sp = Listener::MakeListener("test-listener1");
+ const uint32_t event_mask1 = 1;
+ EXPECT_EQ(event_mask1,
+ listener1_sp->StartListeningForEvents(&broadcaster, event_mask1));
+ broadcaster.BroadcastEvent(event_mask1, nullptr);
+ EXPECT_TRUE(listener1_sp->GetEvent(event_sp, timeout));
+ EXPECT_EQ(event_mask1, event_sp->GetType());
+
+ {
+ // Add one more listener, make sure it works as well.
+ ListenerSP listener2_sp = Listener::MakeListener("test-listener2");
+ const uint32_t event_mask2 = 1;
+ EXPECT_EQ(event_mask2, listener2_sp->StartListeningForEvents(
+ &broadcaster, event_mask1 | event_mask2));
+ broadcaster.BroadcastEvent(event_mask2, nullptr);
+ EXPECT_TRUE(listener2_sp->GetEvent(event_sp, timeout));
+ EXPECT_EQ(event_mask2, event_sp->GetType());
+
+ // Both listeners should get this event.
+ broadcaster.BroadcastEvent(event_mask1, nullptr);
+ EXPECT_TRUE(listener1_sp->GetEvent(event_sp, timeout));
+ EXPECT_EQ(event_mask1, event_sp->GetType());
+ EXPECT_TRUE(listener2_sp->GetEvent(event_sp, timeout));
+ EXPECT_EQ(event_mask2, event_sp->GetType());
+ }
+
+ // Now again only one listener should be active.
+ broadcaster.BroadcastEvent(event_mask1, nullptr);
+ EXPECT_TRUE(listener1_sp->GetEvent(event_sp, timeout));
+ EXPECT_EQ(event_mask1, event_sp->GetType());
+}
+
+TEST(BroadcasterTest, EventTypeHasListeners) {
+ EventSP event_sp;
+ Broadcaster broadcaster(nullptr, "test-broadcaster");
+
+ const uint32_t event_mask = 1;
+ EXPECT_FALSE(broadcaster.EventTypeHasListeners(event_mask));
+
+ {
+ ListenerSP listener_sp = Listener::MakeListener("test-listener");
+ EXPECT_EQ(event_mask,
+ listener_sp->StartListeningForEvents(&broadcaster, event_mask));
+ EXPECT_TRUE(broadcaster.EventTypeHasListeners(event_mask));
+ }
+
+ EXPECT_FALSE(broadcaster.EventTypeHasListeners(event_mask));
+}
diff --git a/unittests/Core/CMakeLists.txt b/unittests/Core/CMakeLists.txt
index ad9def181de5..da880010e4be 100644
--- a/unittests/Core/CMakeLists.txt
+++ b/unittests/Core/CMakeLists.txt
@@ -1,4 +1,9 @@
add_lldb_unittest(LLDBCoreTests
+ ArchSpecTest.cpp
+ BroadcasterTest.cpp
DataExtractorTest.cpp
+ ListenerTest.cpp
ScalarTest.cpp
+ StructuredDataTest.cpp
+ TimerTest.cpp
)
diff --git a/unittests/Core/DataExtractorTest.cpp b/unittests/Core/DataExtractorTest.cpp
index f22883875055..d474e21dc0c3 100644
--- a/unittests/Core/DataExtractorTest.cpp
+++ b/unittests/Core/DataExtractorTest.cpp
@@ -8,7 +8,8 @@
//===----------------------------------------------------------------------===//
#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
-// Workaround for MSVC standard library bug, which fails to include <thread> when
+// Workaround for MSVC standard library bug, which fails to include <thread>
+// when
// exceptions are disabled.
#include <eh.h>
#endif
@@ -19,21 +20,39 @@
using namespace lldb_private;
-TEST(DataExtractorTest, GetBitfield)
-{
- char buffer[] = { 0x01, 0x23, 0x45, 0x67 };
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, sizeof(void *));
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
+TEST(DataExtractorTest, GetBitfield) {
+ uint8_t buffer[] = {0x01, 0x23, 0x45, 0x67};
+ DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
+ sizeof(void *));
+ DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
+
+ lldb::offset_t offset;
+
+ offset = 0;
+ ASSERT_EQ(buffer[1], LE.GetMaxU64Bitfield(&offset, sizeof(buffer), 8, 8));
+ offset = 0;
+ ASSERT_EQ(buffer[1], BE.GetMaxU64Bitfield(&offset, sizeof(buffer), 8, 8));
+
+ offset = 0;
+ ASSERT_EQ(int8_t(buffer[1]),
+ LE.GetMaxS64Bitfield(&offset, sizeof(buffer), 8, 8));
+ offset = 0;
+ ASSERT_EQ(int8_t(buffer[1]),
+ BE.GetMaxS64Bitfield(&offset, sizeof(buffer), 8, 8));
+}
+
+TEST(DataExtractorTest, PeekData) {
+ uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};
+ DataExtractor E(buffer, sizeof buffer, lldb::eByteOrderLittle, 4);
- lldb::offset_t offset;
+ EXPECT_EQ(buffer + 0, E.PeekData(0, 0));
+ EXPECT_EQ(buffer + 0, E.PeekData(0, 4));
+ EXPECT_EQ(nullptr, E.PeekData(0, 5));
- offset = 0;
- ASSERT_EQ(buffer[1], LE.GetMaxU64Bitfield(&offset, sizeof(buffer), 8, 8));
- offset = 0;
- ASSERT_EQ(buffer[1], BE.GetMaxU64Bitfield(&offset, sizeof(buffer), 8, 8));
+ EXPECT_EQ(buffer + 2, E.PeekData(2, 0));
+ EXPECT_EQ(buffer + 2, E.PeekData(2, 2));
+ EXPECT_EQ(nullptr, E.PeekData(2, 3));
- offset = 0;
- ASSERT_EQ(buffer[1], LE.GetMaxS64Bitfield(&offset, sizeof(buffer), 8, 8));
- offset = 0;
- ASSERT_EQ(buffer[1], BE.GetMaxS64Bitfield(&offset, sizeof(buffer), 8, 8));
+ EXPECT_EQ(buffer + 4, E.PeekData(4, 0));
+ EXPECT_EQ(nullptr, E.PeekData(4, 1));
}
diff --git a/unittests/Core/ListenerTest.cpp b/unittests/Core/ListenerTest.cpp
new file mode 100644
index 000000000000..7c5a52e3dc4b
--- /dev/null
+++ b/unittests/Core/ListenerTest.cpp
@@ -0,0 +1,114 @@
+//===-- ListenerTest.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Listener.h"
+#include <future>
+#include <thread>
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(ListenerTest, GetEventImmediate) {
+ EventSP event_sp;
+ Broadcaster broadcaster(nullptr, "test-broadcaster");
+
+ // Create a listener, sign it up, make sure it recieves an event.
+ ListenerSP listener_sp = Listener::MakeListener("test-listener");
+ const uint32_t event_mask = 1;
+ ASSERT_EQ(event_mask,
+ listener_sp->StartListeningForEvents(&broadcaster, event_mask));
+
+ const std::chrono::seconds timeout(0);
+ // Without any events sent, these should return false.
+ EXPECT_FALSE(listener_sp->GetEvent(event_sp, timeout));
+ EXPECT_FALSE(listener_sp->GetEventForBroadcaster(nullptr, event_sp, timeout));
+ EXPECT_FALSE(
+ listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, timeout));
+ EXPECT_FALSE(listener_sp->GetEventForBroadcasterWithType(
+ &broadcaster, event_mask, event_sp, timeout));
+
+ // Now send events and make sure they get it.
+ broadcaster.BroadcastEvent(event_mask, nullptr);
+ EXPECT_TRUE(listener_sp->GetEvent(event_sp, timeout));
+
+ broadcaster.BroadcastEvent(event_mask, nullptr);
+ EXPECT_TRUE(listener_sp->GetEventForBroadcaster(nullptr, event_sp, timeout));
+
+ broadcaster.BroadcastEvent(event_mask, nullptr);
+ EXPECT_TRUE(
+ listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, timeout));
+
+ broadcaster.BroadcastEvent(event_mask, nullptr);
+ EXPECT_FALSE(listener_sp->GetEventForBroadcasterWithType(
+ &broadcaster, event_mask * 2, event_sp, timeout));
+ EXPECT_TRUE(listener_sp->GetEventForBroadcasterWithType(
+ &broadcaster, event_mask, event_sp, timeout));
+}
+
+TEST(ListenerTest, GetEventWait) {
+ EventSP event_sp;
+ Broadcaster broadcaster(nullptr, "test-broadcaster");
+
+ // Create a listener, sign it up, make sure it recieves an event.
+ ListenerSP listener_sp = Listener::MakeListener("test-listener");
+ const uint32_t event_mask = 1;
+ ASSERT_EQ(event_mask,
+ listener_sp->StartListeningForEvents(&broadcaster, event_mask));
+
+ // Without any events sent, these should make a short wait and return false.
+ std::chrono::microseconds timeout(10);
+ EXPECT_FALSE(listener_sp->GetEvent(event_sp, timeout));
+ EXPECT_FALSE(listener_sp->GetEventForBroadcaster(nullptr, event_sp, timeout));
+ EXPECT_FALSE(
+ listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, timeout));
+ EXPECT_FALSE(listener_sp->GetEventForBroadcasterWithType(
+ &broadcaster, event_mask, event_sp, timeout));
+
+ // Now send events and make sure they get it.
+ broadcaster.BroadcastEvent(event_mask, nullptr);
+ EXPECT_TRUE(listener_sp->GetEvent(event_sp, timeout));
+
+ broadcaster.BroadcastEvent(event_mask, nullptr);
+ EXPECT_TRUE(listener_sp->GetEventForBroadcaster(nullptr, event_sp, timeout));
+
+ broadcaster.BroadcastEvent(event_mask, nullptr);
+ EXPECT_TRUE(
+ listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, timeout));
+
+ broadcaster.BroadcastEvent(event_mask, nullptr);
+ EXPECT_FALSE(listener_sp->GetEventForBroadcasterWithType(
+ &broadcaster, event_mask * 2, event_sp, timeout));
+ EXPECT_TRUE(listener_sp->GetEventForBroadcasterWithType(
+ &broadcaster, event_mask, event_sp, timeout));
+
+ auto delayed_broadcast = [&] {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ broadcaster.BroadcastEvent(event_mask, nullptr);
+ };
+
+ // These should do an infinite wait at return the event our asynchronous
+ // broadcast sends.
+ std::future<void> async_broadcast =
+ std::async(std::launch::async, delayed_broadcast);
+ EXPECT_TRUE(listener_sp->GetEvent(event_sp, llvm::None));
+ async_broadcast.get();
+
+ async_broadcast = std::async(std::launch::async, delayed_broadcast);
+ EXPECT_TRUE(
+ listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, llvm::None));
+ async_broadcast.get();
+
+ async_broadcast = std::async(std::launch::async, delayed_broadcast);
+ EXPECT_TRUE(listener_sp->GetEventForBroadcasterWithType(
+ &broadcaster, event_mask, event_sp, llvm::None));
+ async_broadcast.get();
+}
diff --git a/unittests/Core/ScalarTest.cpp b/unittests/Core/ScalarTest.cpp
index bf85f8e9623b..b79854f97ae3 100644
--- a/unittests/Core/ScalarTest.cpp
+++ b/unittests/Core/ScalarTest.cpp
@@ -8,98 +8,134 @@
//===----------------------------------------------------------------------===//
#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
-// Workaround for MSVC standard library bug, which fails to include <thread> when
+// Workaround for MSVC standard library bug, which fails to include <thread>
+// when
// exceptions are disabled.
#include <eh.h>
#endif
#include "gtest/gtest.h"
+#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamString.h"
#include "lldb/Host/Endian.h"
using namespace lldb_private;
-TEST(ScalarTest, RightShiftOperator)
-{
- int a = 0x00001000;
- int b = 0xFFFFFFFF;
- int c = 4;
- Scalar a_scalar(a);
- Scalar b_scalar(b);
- Scalar c_scalar(c);
- ASSERT_EQ(a >> c, a_scalar >> c_scalar);
- ASSERT_EQ(b >> c, b_scalar >> c_scalar);
+TEST(ScalarTest, RightShiftOperator) {
+ int a = 0x00001000;
+ int b = 0xFFFFFFFF;
+ int c = 4;
+ Scalar a_scalar(a);
+ Scalar b_scalar(b);
+ Scalar c_scalar(c);
+ ASSERT_EQ(a >> c, a_scalar >> c_scalar);
+ ASSERT_EQ(b >> c, b_scalar >> c_scalar);
}
-TEST(ScalarTest, GetBytes)
-{
- int a = 0x01020304;
- long long b = 0x0102030405060708LL;
- float c = 1234567.89e42;
- double d = 1234567.89e42;
- char e[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
- char f[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
- Scalar a_scalar(a);
- Scalar b_scalar(b);
- Scalar c_scalar(c);
- Scalar d_scalar(d);
- Scalar e_scalar;
- Scalar f_scalar;
- DataExtractor e_data(e, sizeof(e), endian::InlHostByteOrder(), sizeof(void *));
- Error e_error = e_scalar.SetValueFromData(e_data, lldb::eEncodingUint, sizeof(e));
- DataExtractor f_data(f, sizeof(f), endian::InlHostByteOrder(), sizeof(void *));
- Error f_error = f_scalar.SetValueFromData(f_data, lldb::eEncodingUint, sizeof(f));
- ASSERT_EQ(0, memcmp(&a, a_scalar.GetBytes(), sizeof(a)));
- ASSERT_EQ(0, memcmp(&b, b_scalar.GetBytes(), sizeof(b)));
- ASSERT_EQ(0, memcmp(&c, c_scalar.GetBytes(), sizeof(c)));
- ASSERT_EQ(0, memcmp(&d, d_scalar.GetBytes(), sizeof(d)));
- ASSERT_EQ(0, e_error.Fail());
- ASSERT_EQ(0, memcmp(e, e_scalar.GetBytes(), sizeof(e)));
- ASSERT_EQ(0, f_error.Fail());
- ASSERT_EQ(0, memcmp(f, f_scalar.GetBytes(), sizeof(f)));
+TEST(ScalarTest, GetBytes) {
+ int a = 0x01020304;
+ long long b = 0x0102030405060708LL;
+ float c = 1234567.89e42;
+ double d = 1234567.89e42;
+ char e[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ char f[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
+ Scalar a_scalar(a);
+ Scalar b_scalar(b);
+ Scalar c_scalar(c);
+ Scalar d_scalar(d);
+ Scalar e_scalar;
+ Scalar f_scalar;
+ DataExtractor e_data(e, sizeof(e), endian::InlHostByteOrder(),
+ sizeof(void *));
+ Error e_error =
+ e_scalar.SetValueFromData(e_data, lldb::eEncodingUint, sizeof(e));
+ DataExtractor f_data(f, sizeof(f), endian::InlHostByteOrder(),
+ sizeof(void *));
+ Error f_error =
+ f_scalar.SetValueFromData(f_data, lldb::eEncodingUint, sizeof(f));
+ ASSERT_EQ(0, memcmp(&a, a_scalar.GetBytes(), sizeof(a)));
+ ASSERT_EQ(0, memcmp(&b, b_scalar.GetBytes(), sizeof(b)));
+ ASSERT_EQ(0, memcmp(&c, c_scalar.GetBytes(), sizeof(c)));
+ ASSERT_EQ(0, memcmp(&d, d_scalar.GetBytes(), sizeof(d)));
+ ASSERT_EQ(0, e_error.Fail());
+ ASSERT_EQ(0, memcmp(e, e_scalar.GetBytes(), sizeof(e)));
+ ASSERT_EQ(0, f_error.Fail());
+ ASSERT_EQ(0, memcmp(f, f_scalar.GetBytes(), sizeof(f)));
}
-TEST(ScalarTest, CastOperations)
-{
- long long a = 0xf1f2f3f4f5f6f7f8LL;
- Scalar a_scalar(a);
- ASSERT_EQ((signed char)a, a_scalar.SChar());
- ASSERT_EQ((unsigned char)a, a_scalar.UChar());
- ASSERT_EQ((signed short)a, a_scalar.SShort());
- ASSERT_EQ((unsigned short)a, a_scalar.UShort());
- ASSERT_EQ((signed int)a, a_scalar.SInt());
- ASSERT_EQ((unsigned int)a, a_scalar.UInt());
- ASSERT_EQ((signed long)a, a_scalar.SLong());
- ASSERT_EQ((unsigned long)a, a_scalar.ULong());
- ASSERT_EQ((signed long long)a, a_scalar.SLongLong());
- ASSERT_EQ((unsigned long long)a, a_scalar.ULongLong());
+TEST(ScalarTest, CastOperations) {
+ long long a = 0xf1f2f3f4f5f6f7f8LL;
+ Scalar a_scalar(a);
+ ASSERT_EQ((signed char)a, a_scalar.SChar());
+ ASSERT_EQ((unsigned char)a, a_scalar.UChar());
+ ASSERT_EQ((signed short)a, a_scalar.SShort());
+ ASSERT_EQ((unsigned short)a, a_scalar.UShort());
+ ASSERT_EQ((signed int)a, a_scalar.SInt());
+ ASSERT_EQ((unsigned int)a, a_scalar.UInt());
+ ASSERT_EQ((signed long)a, a_scalar.SLong());
+ ASSERT_EQ((unsigned long)a, a_scalar.ULong());
+ ASSERT_EQ((signed long long)a, a_scalar.SLongLong());
+ ASSERT_EQ((unsigned long long)a, a_scalar.ULongLong());
}
-TEST(ScalarTest, ExtractBitfield)
-{
- uint32_t len = sizeof(long long) * 8;
+TEST(ScalarTest, ExtractBitfield) {
+ uint32_t len = sizeof(long long) * 8;
+
+ long long a1 = 0xf1f2f3f4f5f6f7f8LL;
+ long long b1 = 0xff1f2f3f4f5f6f7fLL;
+ Scalar s_scalar(a1);
+ ASSERT_TRUE(s_scalar.ExtractBitfield(0, 0));
+ ASSERT_EQ(0, memcmp(&a1, s_scalar.GetBytes(), sizeof(a1)));
+ ASSERT_TRUE(s_scalar.ExtractBitfield(len, 0));
+ ASSERT_EQ(0, memcmp(&a1, s_scalar.GetBytes(), sizeof(a1)));
+ ASSERT_TRUE(s_scalar.ExtractBitfield(len - 4, 4));
+ ASSERT_EQ(0, memcmp(&b1, s_scalar.GetBytes(), sizeof(b1)));
+
+ unsigned long long a2 = 0xf1f2f3f4f5f6f7f8ULL;
+ unsigned long long b2 = 0x0f1f2f3f4f5f6f7fULL;
+ Scalar u_scalar(a2);
+ ASSERT_TRUE(u_scalar.ExtractBitfield(0, 0));
+ ASSERT_EQ(0, memcmp(&a2, u_scalar.GetBytes(), sizeof(a2)));
+ ASSERT_TRUE(u_scalar.ExtractBitfield(len, 0));
+ ASSERT_EQ(0, memcmp(&a2, u_scalar.GetBytes(), sizeof(a2)));
+ ASSERT_TRUE(u_scalar.ExtractBitfield(len - 4, 4));
+ ASSERT_EQ(0, memcmp(&b2, u_scalar.GetBytes(), sizeof(b2)));
+}
+
+template <typename T> static std::string ScalarGetValue(T value) {
+ StreamString stream;
+ Scalar(value).GetValue(&stream, false);
+ return stream.GetString();
+}
+
+TEST(ScalarTest, GetValue) {
+ EXPECT_EQ("12345", ScalarGetValue<signed short>(12345));
+ EXPECT_EQ("-12345", ScalarGetValue<signed short>(-12345));
+ EXPECT_EQ("12345", ScalarGetValue<unsigned short>(12345));
+ EXPECT_EQ(std::to_string(std::numeric_limits<unsigned short>::max()),
+ ScalarGetValue(std::numeric_limits<unsigned short>::max()));
+
+ EXPECT_EQ("12345", ScalarGetValue<signed int>(12345));
+ EXPECT_EQ("-12345", ScalarGetValue<signed int>(-12345));
+ EXPECT_EQ("12345", ScalarGetValue<unsigned int>(12345));
+ EXPECT_EQ(std::to_string(std::numeric_limits<unsigned int>::max()),
+ ScalarGetValue(std::numeric_limits<unsigned int>::max()));
- long long a1 = 0xf1f2f3f4f5f6f7f8LL;
- long long b1 = 0xff1f2f3f4f5f6f7fLL;
- Scalar s_scalar(a1);
- ASSERT_TRUE(s_scalar.ExtractBitfield(0, 0));
- ASSERT_EQ(0, memcmp(&a1, s_scalar.GetBytes(), sizeof(a1)));
- ASSERT_TRUE(s_scalar.ExtractBitfield(len, 0));
- ASSERT_EQ(0, memcmp(&a1, s_scalar.GetBytes(), sizeof(a1)));
- ASSERT_TRUE(s_scalar.ExtractBitfield(len - 4, 4));
- ASSERT_EQ(0, memcmp(&b1, s_scalar.GetBytes(), sizeof(b1)));
+ EXPECT_EQ("12345678", ScalarGetValue<signed long>(12345678L));
+ EXPECT_EQ("-12345678", ScalarGetValue<signed long>(-12345678L));
+ EXPECT_EQ("12345678", ScalarGetValue<unsigned long>(12345678UL));
+ EXPECT_EQ(std::to_string(std::numeric_limits<unsigned long>::max()),
+ ScalarGetValue(std::numeric_limits<unsigned long>::max()));
- unsigned long long a2 = 0xf1f2f3f4f5f6f7f8ULL;
- unsigned long long b2 = 0x0f1f2f3f4f5f6f7fULL;
- Scalar u_scalar(a2);
- ASSERT_TRUE(u_scalar.ExtractBitfield(0, 0));
- ASSERT_EQ(0, memcmp(&a2, u_scalar.GetBytes(), sizeof(a2)));
- ASSERT_TRUE(u_scalar.ExtractBitfield(len, 0));
- ASSERT_EQ(0, memcmp(&a2, u_scalar.GetBytes(), sizeof(a2)));
- ASSERT_TRUE(u_scalar.ExtractBitfield(len - 4, 4));
- ASSERT_EQ(0, memcmp(&b2, u_scalar.GetBytes(), sizeof(b2)));
+ EXPECT_EQ("1234567890123", ScalarGetValue<signed long long>(1234567890123LL));
+ EXPECT_EQ("-1234567890123",
+ ScalarGetValue<signed long long>(-1234567890123LL));
+ EXPECT_EQ("1234567890123",
+ ScalarGetValue<unsigned long long>(1234567890123ULL));
+ EXPECT_EQ(std::to_string(std::numeric_limits<unsigned long long>::max()),
+ ScalarGetValue(std::numeric_limits<unsigned long long>::max()));
}
diff --git a/unittests/Core/StructuredDataTest.cpp b/unittests/Core/StructuredDataTest.cpp
new file mode 100644
index 000000000000..8e10d571fbfa
--- /dev/null
+++ b/unittests/Core/StructuredDataTest.cpp
@@ -0,0 +1,32 @@
+//===-- StructuredDataTest.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Core/StreamString.h"
+
+#include "llvm/Support/MachO.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(StructuredDataTest, StringDump) {
+ std::pair<llvm::StringRef, llvm::StringRef> TestCases[] = {
+ { R"(asdfg)", R"("asdfg")" },
+ { R"(as"df)", R"("as\"df")" },
+ { R"(as\df)", R"("as\\df")" },
+ };
+ for(auto P : TestCases) {
+ StreamString S;
+ const bool pretty_print = false;
+ StructuredData::String(P.first).Dump(S, pretty_print);
+ EXPECT_EQ(P.second, S.GetString());
+ }
+}
diff --git a/unittests/Core/TimerTest.cpp b/unittests/Core/TimerTest.cpp
new file mode 100644
index 000000000000..d37d281f61af
--- /dev/null
+++ b/unittests/Core/TimerTest.cpp
@@ -0,0 +1,72 @@
+//===-- TimerTest.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread>
+// when exceptions are disabled.
+#include <eh.h>
+#endif
+
+#include "lldb/Core/Timer.h"
+#include "gtest/gtest.h"
+
+#include "lldb/Core/StreamString.h"
+#include <thread>
+
+using namespace lldb_private;
+
+TEST(TimerTest, CategoryTimes) {
+ Timer::ResetCategoryTimes();
+ {
+ Timer t("CAT1", "");
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ StreamString ss;
+ Timer::DumpCategoryTimes(&ss);
+ double seconds;
+ ASSERT_EQ(1, sscanf(ss.GetData(), "%lf sec for CAT1", &seconds));
+ EXPECT_LT(0.001, seconds);
+ EXPECT_GT(0.1, seconds);
+}
+
+TEST(TimerTest, CategoryTimesNested) {
+ Timer::ResetCategoryTimes();
+ {
+ Timer t1("CAT1", "");
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ Timer t2("CAT1", "");
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ StreamString ss;
+ Timer::DumpCategoryTimes(&ss);
+ double seconds;
+ ASSERT_EQ(1, sscanf(ss.GetData(), "%lf sec for CAT1", &seconds));
+ EXPECT_LT(0.002, seconds);
+ EXPECT_GT(0.2, seconds);
+}
+
+TEST(TimerTest, CategoryTimes2) {
+ Timer::ResetCategoryTimes();
+ {
+ Timer t1("CAT1", "");
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ Timer t2("CAT2", "");
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ StreamString ss;
+ Timer::DumpCategoryTimes(&ss);
+ double seconds1, seconds2;
+ ASSERT_EQ(2, sscanf(ss.GetData(), "%lf sec for CAT1%*[\n ]%lf sec for CAT2",
+ &seconds1, &seconds2))
+ << "String: " << ss.GetData();
+ EXPECT_LT(0.01, seconds1);
+ EXPECT_GT(1, seconds1);
+ EXPECT_LT(0.001, seconds2);
+ EXPECT_GT(0.1, seconds2);
+}
diff --git a/unittests/Editline/EditlineTest.cpp b/unittests/Editline/EditlineTest.cpp
index e2552ffdd3b8..55dae525ddc3 100644
--- a/unittests/Editline/EditlineTest.cpp
+++ b/unittests/Editline/EditlineTest.cpp
@@ -25,348 +25,289 @@
#include "lldb/Host/Pipe.h"
#include "lldb/Utility/PseudoTerminal.h"
-namespace
-{
- const size_t TIMEOUT_MILLIS = 5000;
+namespace {
+const size_t TIMEOUT_MILLIS = 5000;
}
-class FilePointer
-{
+class FilePointer {
public:
+ FilePointer() = delete;
- FilePointer () = delete;
+ FilePointer(const FilePointer &) = delete;
- FilePointer (const FilePointer&) = delete;
+ FilePointer(FILE *file_p) : _file_p(file_p) {}
- FilePointer (FILE *file_p)
- : _file_p (file_p)
- {
+ ~FilePointer() {
+ if (_file_p != nullptr) {
+ const int close_result = fclose(_file_p);
+ EXPECT_EQ(0, close_result);
}
+ }
- ~FilePointer ()
- {
- if (_file_p != nullptr)
- {
- const int close_result = fclose (_file_p);
- EXPECT_EQ(0, close_result);
- }
- }
-
- operator FILE* ()
- {
- return _file_p;
- }
+ operator FILE *() { return _file_p; }
private:
-
- FILE *_file_p;
-
+ FILE *_file_p;
};
/**
Wraps an Editline class, providing a simple way to feed
input (as if from the keyboard) and receive output from Editline.
*/
-class EditlineAdapter
-{
+class EditlineAdapter {
public:
+ EditlineAdapter();
- EditlineAdapter ();
+ void CloseInput();
- void
- CloseInput ();
+ bool IsValid() const { return _editline_sp.get() != nullptr; }
- bool
- IsValid () const
- {
- return _editline_sp.get () != nullptr;
- }
+ lldb_private::Editline &GetEditline() { return *_editline_sp; }
- lldb_private::Editline&
- GetEditline ()
- {
- return *_editline_sp;
- }
+ bool SendLine(const std::string &line);
- bool
- SendLine (const std::string &line);
+ bool SendLines(const std::vector<std::string> &lines);
- bool
- SendLines (const std::vector<std::string> &lines);
+ bool GetLine(std::string &line, bool &interrupted, size_t timeout_millis);
- bool
- GetLine (std::string &line, bool &interrupted, size_t timeout_millis);
+ bool GetLines(lldb_private::StringList &lines, bool &interrupted,
+ size_t timeout_millis);
- bool
- GetLines (lldb_private::StringList &lines, bool &interrupted, size_t timeout_millis);
-
- void
- ConsumeAllOutput ();
+ void ConsumeAllOutput();
private:
+ static bool IsInputComplete(lldb_private::Editline *editline,
+ lldb_private::StringList &lines, void *baton);
- static bool
- IsInputComplete (
- lldb_private::Editline * editline,
- lldb_private::StringList & lines,
- void * baton);
-
- std::unique_ptr<lldb_private::Editline> _editline_sp;
+ std::unique_ptr<lldb_private::Editline> _editline_sp;
- lldb_utility::PseudoTerminal _pty;
- int _pty_master_fd;
- int _pty_slave_fd;
+ lldb_utility::PseudoTerminal _pty;
+ int _pty_master_fd;
+ int _pty_slave_fd;
- std::unique_ptr<FilePointer> _el_slave_file;
+ std::unique_ptr<FilePointer> _el_slave_file;
};
-EditlineAdapter::EditlineAdapter () :
- _editline_sp (),
- _pty (),
- _pty_master_fd (-1),
- _pty_slave_fd (-1),
- _el_slave_file ()
-{
- lldb_private::Error error;
-
- // Open the first master pty available.
- char error_string[256];
- error_string[0] = '\0';
- if (!_pty.OpenFirstAvailableMaster (O_RDWR, error_string, sizeof (error_string)))
- {
- fprintf(stderr, "failed to open first available master pty: '%s'\n", error_string);
- return;
- }
-
- // Grab the master fd. This is a file descriptor we will:
- // (1) write to when we want to send input to editline.
- // (2) read from when we want to see what editline sends back.
- _pty_master_fd = _pty.GetMasterFileDescriptor();
-
- // Open the corresponding slave pty.
- if (!_pty.OpenSlave (O_RDWR, error_string, sizeof (error_string)))
- {
- fprintf(stderr, "failed to open slave pty: '%s'\n", error_string);
- return;
- }
- _pty_slave_fd = _pty.GetSlaveFileDescriptor();
+EditlineAdapter::EditlineAdapter()
+ : _editline_sp(), _pty(), _pty_master_fd(-1), _pty_slave_fd(-1),
+ _el_slave_file() {
+ lldb_private::Error error;
+
+ // Open the first master pty available.
+ char error_string[256];
+ error_string[0] = '\0';
+ if (!_pty.OpenFirstAvailableMaster(O_RDWR, error_string,
+ sizeof(error_string))) {
+ fprintf(stderr, "failed to open first available master pty: '%s'\n",
+ error_string);
+ return;
+ }
+
+ // Grab the master fd. This is a file descriptor we will:
+ // (1) write to when we want to send input to editline.
+ // (2) read from when we want to see what editline sends back.
+ _pty_master_fd = _pty.GetMasterFileDescriptor();
+
+ // Open the corresponding slave pty.
+ if (!_pty.OpenSlave(O_RDWR, error_string, sizeof(error_string))) {
+ fprintf(stderr, "failed to open slave pty: '%s'\n", error_string);
+ return;
+ }
+ _pty_slave_fd = _pty.GetSlaveFileDescriptor();
+
+ _el_slave_file.reset(new FilePointer(fdopen(_pty_slave_fd, "rw")));
+ EXPECT_FALSE(nullptr == *_el_slave_file);
+ if (*_el_slave_file == nullptr)
+ return;
+
+ // Create an Editline instance.
+ _editline_sp.reset(new lldb_private::Editline("gtest editor", *_el_slave_file,
+ *_el_slave_file,
+ *_el_slave_file, false));
+ _editline_sp->SetPrompt("> ");
+
+ // Hookup our input complete callback.
+ _editline_sp->SetIsInputCompleteCallback(IsInputComplete, this);
+}
- _el_slave_file.reset (new FilePointer (fdopen (_pty_slave_fd, "rw")));
- EXPECT_FALSE (nullptr == *_el_slave_file);
- if (*_el_slave_file == nullptr)
- return;
+void EditlineAdapter::CloseInput() {
+ if (_el_slave_file != nullptr)
+ _el_slave_file.reset(nullptr);
+}
- // Create an Editline instance.
- _editline_sp.reset (new lldb_private::Editline("gtest editor", *_el_slave_file, *_el_slave_file, *_el_slave_file, false));
- _editline_sp->SetPrompt ("> ");
+bool EditlineAdapter::SendLine(const std::string &line) {
+ // Ensure we're valid before proceeding.
+ if (!IsValid())
+ return false;
- // Hookup our input complete callback.
- _editline_sp->SetIsInputCompleteCallback(IsInputComplete, this);
-}
+ // Write the line out to the pipe connected to editline's input.
+ ssize_t input_bytes_written =
+ ::write(_pty_master_fd, line.c_str(),
+ line.length() * sizeof(std::string::value_type));
-void
-EditlineAdapter::CloseInput ()
-{
- if (_el_slave_file != nullptr)
- _el_slave_file.reset (nullptr);
-}
+ const char *eoln = "\n";
+ const size_t eoln_length = strlen(eoln);
+ input_bytes_written =
+ ::write(_pty_master_fd, eoln, eoln_length * sizeof(char));
-bool
-EditlineAdapter::SendLine (const std::string &line)
-{
- // Ensure we're valid before proceeding.
- if (!IsValid ())
- return false;
-
- // Write the line out to the pipe connected to editline's input.
- ssize_t input_bytes_written =
- ::write (_pty_master_fd,
- line.c_str(),
- line.length() * sizeof (std::string::value_type));
-
- const char *eoln = "\n";
- const size_t eoln_length = strlen(eoln);
- input_bytes_written =
- ::write (_pty_master_fd,
- eoln,
- eoln_length * sizeof (char));
-
- EXPECT_NE(-1, input_bytes_written) << strerror(errno);
- EXPECT_EQ (eoln_length * sizeof (char), size_t(input_bytes_written));
- return eoln_length * sizeof (char) == size_t(input_bytes_written);
+ EXPECT_NE(-1, input_bytes_written) << strerror(errno);
+ EXPECT_EQ(eoln_length * sizeof(char), size_t(input_bytes_written));
+ return eoln_length * sizeof(char) == size_t(input_bytes_written);
}
-bool
-EditlineAdapter::SendLines (const std::vector<std::string> &lines)
-{
- for (auto &line : lines)
- {
+bool EditlineAdapter::SendLines(const std::vector<std::string> &lines) {
+ for (auto &line : lines) {
#if EDITLINE_TEST_DUMP_OUTPUT
- printf ("<stdin> sending line \"%s\"\n", line.c_str());
+ printf("<stdin> sending line \"%s\"\n", line.c_str());
#endif
- if (!SendLine (line))
- return false;
- }
- return true;
+ if (!SendLine(line))
+ return false;
+ }
+ return true;
}
// We ignore the timeout for now.
-bool
-EditlineAdapter::GetLine (std::string &line, bool &interrupted, size_t /* timeout_millis */)
-{
- // Ensure we're valid before proceeding.
- if (!IsValid ())
- return false;
-
- _editline_sp->GetLine (line, interrupted);
- return true;
+bool EditlineAdapter::GetLine(std::string &line, bool &interrupted,
+ size_t /* timeout_millis */) {
+ // Ensure we're valid before proceeding.
+ if (!IsValid())
+ return false;
+
+ _editline_sp->GetLine(line, interrupted);
+ return true;
}
-bool
-EditlineAdapter::GetLines (lldb_private::StringList &lines, bool &interrupted, size_t /* timeout_millis */)
-{
- // Ensure we're valid before proceeding.
- if (!IsValid ())
- return false;
-
- _editline_sp->GetLines (1, lines, interrupted);
- return true;
+bool EditlineAdapter::GetLines(lldb_private::StringList &lines,
+ bool &interrupted, size_t /* timeout_millis */) {
+ // Ensure we're valid before proceeding.
+ if (!IsValid())
+ return false;
+
+ _editline_sp->GetLines(1, lines, interrupted);
+ return true;
}
-bool
-EditlineAdapter::IsInputComplete (
- lldb_private::Editline * editline,
- lldb_private::StringList & lines,
- void * baton)
-{
- // We'll call ourselves complete if we've received a balanced set of braces.
- int start_block_count = 0;
- int brace_balance = 0;
-
- for (size_t i = 0; i < lines.GetSize (); ++i)
- {
- for (auto ch : lines[i])
- {
- if (ch == '{')
- {
- ++start_block_count;
- ++brace_balance;
- }
- else if (ch == '}')
- --brace_balance;
- }
+bool EditlineAdapter::IsInputComplete(lldb_private::Editline *editline,
+ lldb_private::StringList &lines,
+ void *baton) {
+ // We'll call ourselves complete if we've received a balanced set of braces.
+ int start_block_count = 0;
+ int brace_balance = 0;
+
+ for (size_t i = 0; i < lines.GetSize(); ++i) {
+ for (auto ch : lines[i]) {
+ if (ch == '{') {
+ ++start_block_count;
+ ++brace_balance;
+ } else if (ch == '}')
+ --brace_balance;
}
+ }
- return (start_block_count > 0) && (brace_balance == 0);
+ return (start_block_count > 0) && (brace_balance == 0);
}
-void
-EditlineAdapter::ConsumeAllOutput ()
-{
- FilePointer output_file (fdopen (_pty_master_fd, "r"));
+void EditlineAdapter::ConsumeAllOutput() {
+ FilePointer output_file(fdopen(_pty_master_fd, "r"));
- int ch;
- while ((ch = fgetc(output_file)) != EOF)
- {
+ int ch;
+ while ((ch = fgetc(output_file)) != EOF) {
#if EDITLINE_TEST_DUMP_OUTPUT
- char display_str[] = { 0, 0, 0 };
- switch (ch)
- {
- case '\t':
- display_str[0] = '\\';
- display_str[1] = 't';
- break;
- case '\n':
- display_str[0] = '\\';
- display_str[1] = 'n';
- break;
- case '\r':
- display_str[0] = '\\';
- display_str[1] = 'r';
- break;
- default:
- display_str[0] = ch;
- break;
- }
- printf ("<stdout> 0x%02x (%03d) (%s)\n", ch, ch, display_str);
- // putc(ch, stdout);
-#endif
+ char display_str[] = {0, 0, 0};
+ switch (ch) {
+ case '\t':
+ display_str[0] = '\\';
+ display_str[1] = 't';
+ break;
+ case '\n':
+ display_str[0] = '\\';
+ display_str[1] = 'n';
+ break;
+ case '\r':
+ display_str[0] = '\\';
+ display_str[1] = 'r';
+ break;
+ default:
+ display_str[0] = ch;
+ break;
}
+ printf("<stdout> 0x%02x (%03d) (%s)\n", ch, ch, display_str);
+// putc(ch, stdout);
+#endif
+ }
}
-class EditlineTestFixture : public ::testing::Test
-{
+class EditlineTestFixture : public ::testing::Test {
private:
- EditlineAdapter _el_adapter;
- std::shared_ptr<std::thread> _sp_output_thread;
+ EditlineAdapter _el_adapter;
+ std::shared_ptr<std::thread> _sp_output_thread;
public:
- void SetUp()
- {
- // We need a TERM set properly for editline to work as expected.
- setenv("TERM", "vt100", 1);
-
- // Validate the editline adapter.
- EXPECT_TRUE(_el_adapter.IsValid());
- if (!_el_adapter.IsValid())
- return;
-
- // Dump output.
- _sp_output_thread.reset(new std::thread([&] { _el_adapter.ConsumeAllOutput(); }));
- }
-
- void TearDown()
- {
- _el_adapter.CloseInput();
- if (_sp_output_thread)
- _sp_output_thread->join();
- }
-
- EditlineAdapter &GetEditlineAdapter() { return _el_adapter; }
+ void SetUp() {
+ // We need a TERM set properly for editline to work as expected.
+ setenv("TERM", "vt100", 1);
+
+ // Validate the editline adapter.
+ EXPECT_TRUE(_el_adapter.IsValid());
+ if (!_el_adapter.IsValid())
+ return;
+
+ // Dump output.
+ _sp_output_thread.reset(
+ new std::thread([&] { _el_adapter.ConsumeAllOutput(); }));
+ }
+
+ void TearDown() {
+ _el_adapter.CloseInput();
+ if (_sp_output_thread)
+ _sp_output_thread->join();
+ }
+
+ EditlineAdapter &GetEditlineAdapter() { return _el_adapter; }
};
-TEST_F(EditlineTestFixture, EditlineReceivesSingleLineText)
-{
- // Send it some text via our virtual keyboard.
- const std::string input_text ("Hello, world");
- EXPECT_TRUE(GetEditlineAdapter().SendLine(input_text));
+TEST_F(EditlineTestFixture, EditlineReceivesSingleLineText) {
+ // Send it some text via our virtual keyboard.
+ const std::string input_text("Hello, world");
+ EXPECT_TRUE(GetEditlineAdapter().SendLine(input_text));
- // Verify editline sees what we put in.
- std::string el_reported_line;
- bool input_interrupted = false;
- const bool received_line = GetEditlineAdapter().GetLine(el_reported_line, input_interrupted, TIMEOUT_MILLIS);
+ // Verify editline sees what we put in.
+ std::string el_reported_line;
+ bool input_interrupted = false;
+ const bool received_line = GetEditlineAdapter().GetLine(
+ el_reported_line, input_interrupted, TIMEOUT_MILLIS);
- EXPECT_TRUE (received_line);
- EXPECT_FALSE (input_interrupted);
- EXPECT_EQ (input_text, el_reported_line);
+ EXPECT_TRUE(received_line);
+ EXPECT_FALSE(input_interrupted);
+ EXPECT_EQ(input_text, el_reported_line);
}
-TEST_F(EditlineTestFixture, EditlineReceivesMultiLineText)
-{
- // Send it some text via our virtual keyboard.
- std::vector<std::string> input_lines;
- input_lines.push_back ("int foo()");
- input_lines.push_back ("{");
- input_lines.push_back ("printf(\"Hello, world\");");
- input_lines.push_back ("}");
- input_lines.push_back ("");
-
- EXPECT_TRUE(GetEditlineAdapter().SendLines(input_lines));
-
- // Verify editline sees what we put in.
- lldb_private::StringList el_reported_lines;
- bool input_interrupted = false;
-
- EXPECT_TRUE(GetEditlineAdapter().GetLines(el_reported_lines, input_interrupted, TIMEOUT_MILLIS));
- EXPECT_FALSE (input_interrupted);
-
- // Without any auto indentation support, our output should directly match our input.
- EXPECT_EQ (input_lines.size (), el_reported_lines.GetSize ());
- if (input_lines.size () == el_reported_lines.GetSize ())
- {
- for (size_t i = 0; i < input_lines.size(); ++i)
- EXPECT_EQ (input_lines[i], el_reported_lines[i]);
- }
+TEST_F(EditlineTestFixture, EditlineReceivesMultiLineText) {
+ // Send it some text via our virtual keyboard.
+ std::vector<std::string> input_lines;
+ input_lines.push_back("int foo()");
+ input_lines.push_back("{");
+ input_lines.push_back("printf(\"Hello, world\");");
+ input_lines.push_back("}");
+ input_lines.push_back("");
+
+ EXPECT_TRUE(GetEditlineAdapter().SendLines(input_lines));
+
+ // Verify editline sees what we put in.
+ lldb_private::StringList el_reported_lines;
+ bool input_interrupted = false;
+
+ EXPECT_TRUE(GetEditlineAdapter().GetLines(el_reported_lines,
+ input_interrupted, TIMEOUT_MILLIS));
+ EXPECT_FALSE(input_interrupted);
+
+ // Without any auto indentation support, our output should directly match our
+ // input.
+ EXPECT_EQ(input_lines.size(), el_reported_lines.GetSize());
+ if (input_lines.size() == el_reported_lines.GetSize()) {
+ for (size_t i = 0; i < input_lines.size(); ++i)
+ EXPECT_EQ(input_lines[i], el_reported_lines[i]);
+ }
}
#endif
diff --git a/unittests/Expression/GoParserTest.cpp b/unittests/Expression/GoParserTest.cpp
index 76483979f353..de489e43ef22 100644
--- a/unittests/Expression/GoParserTest.cpp
+++ b/unittests/Expression/GoParserTest.cpp
@@ -1,4 +1,5 @@
-//===-- GoParserTest.cpp ------------------------------------------*- C++ -*-===//
+//===-- GoParserTest.cpp ------------------------------------------*- C++
+//-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,7 +9,8 @@
//===----------------------------------------------------------------------===//
#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
-// Workaround for MSVC standard library bug, which fails to include <thread> when
+// Workaround for MSVC standard library bug, which fails to include <thread>
+// when
// exceptions are disabled.
#include <eh.h>
#endif
@@ -17,234 +19,262 @@
#include "gtest/gtest.h"
-#include "lldb/Core/Error.h"
#include "Plugins/ExpressionParser/Go/GoParser.h"
+#include "lldb/Core/Error.h"
using namespace lldb_private;
-namespace
-{
-struct ASTPrinter
-{
- ASTPrinter(GoASTNode *n) { (*this)(n); }
-
- void
- operator()(GoASTNode *n)
- {
- if (n == nullptr)
- {
- m_stream << "nil ";
- return;
- }
- m_stream << "(" << n->GetKindName() << " ";
- n->WalkChildren(*this);
- if (auto *nn = llvm::dyn_cast<GoASTAssignStmt>(n))
- m_stream << nn->GetDefine() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTBasicLit>(n))
- m_stream << nn->GetValue().m_value.str() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTBinaryExpr>(n))
- m_stream << GoLexer::LookupToken(nn->GetOp()).str() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTIdent>(n))
- m_stream << nn->GetName().m_value.str() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTBranchStmt>(n))
- m_stream << GoLexer::LookupToken(nn->GetTok()).str() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTCallExpr>(n))
- m_stream << (nn->GetEllipsis() ? "..." : "") << " ";
- if (auto *nn = llvm::dyn_cast<GoASTChanType>(n))
- m_stream << nn->GetDir() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTGenDecl>(n))
- m_stream << GoLexer::LookupToken(nn->GetTok()).str() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTIncDecStmt>(n))
- m_stream << GoLexer::LookupToken(nn->GetTok()).str() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTRangeStmt>(n))
- m_stream << nn->GetDefine() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTSliceExpr>(n))
- m_stream << nn->GetSlice3() << " ";
- if (auto *nn = llvm::dyn_cast<GoASTUnaryExpr>(n))
- m_stream << GoLexer::LookupToken(nn->GetOp()).str() << " ";
- m_stream << ") ";
- }
+namespace {
+struct ASTPrinter {
+ ASTPrinter(GoASTNode *n) { (*this)(n); }
- const std::string
- str() const
- {
- return m_stream.str();
+ void operator()(GoASTNode *n) {
+ if (n == nullptr) {
+ m_stream << "nil ";
+ return;
}
- std::stringstream m_stream;
+ m_stream << "(" << n->GetKindName() << " ";
+ n->WalkChildren(*this);
+ if (auto *nn = llvm::dyn_cast<GoASTAssignStmt>(n))
+ m_stream << nn->GetDefine() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTBasicLit>(n))
+ m_stream << nn->GetValue().m_value.str() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTBinaryExpr>(n))
+ m_stream << GoLexer::LookupToken(nn->GetOp()).str() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTIdent>(n))
+ m_stream << nn->GetName().m_value.str() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTBranchStmt>(n))
+ m_stream << GoLexer::LookupToken(nn->GetTok()).str() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTCallExpr>(n))
+ m_stream << (nn->GetEllipsis() ? "..." : "") << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTChanType>(n))
+ m_stream << nn->GetDir() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTGenDecl>(n))
+ m_stream << GoLexer::LookupToken(nn->GetTok()).str() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTIncDecStmt>(n))
+ m_stream << GoLexer::LookupToken(nn->GetTok()).str() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTRangeStmt>(n))
+ m_stream << nn->GetDefine() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTSliceExpr>(n))
+ m_stream << nn->GetSlice3() << " ";
+ if (auto *nn = llvm::dyn_cast<GoASTUnaryExpr>(n))
+ m_stream << GoLexer::LookupToken(nn->GetOp()).str() << " ";
+ m_stream << ") ";
+ }
+
+ const std::string str() const { return m_stream.str(); }
+ std::stringstream m_stream;
};
-testing::AssertionResult
-CheckStatement(const char *_s, const char *c_expr, const char *sexpr, const char *code)
-{
- GoParser parser(code);
- std::unique_ptr<GoASTStmt> stmt(parser.Statement());
- if (parser.Failed() || !stmt)
- {
- Error err;
- parser.GetError(err);
- return testing::AssertionFailure() << "Error parsing " << c_expr << "\n\t" << err.AsCString();
- }
- std::string actual_sexpr = ASTPrinter(stmt.get()).str();
- if (actual_sexpr == sexpr)
- return testing::AssertionSuccess();
- return testing::AssertionFailure() << "Parsing: " << c_expr << "\nExpected: " << sexpr
- << "\nGot: " << actual_sexpr;
+testing::AssertionResult CheckStatement(const char *_s, const char *c_expr,
+ const char *sexpr, const char *code) {
+ GoParser parser(code);
+ std::unique_ptr<GoASTStmt> stmt(parser.Statement());
+ if (parser.Failed() || !stmt) {
+ Error err;
+ parser.GetError(err);
+ return testing::AssertionFailure() << "Error parsing " << c_expr << "\n\t"
+ << err.AsCString();
+ }
+ std::string actual_sexpr = ASTPrinter(stmt.get()).str();
+ if (actual_sexpr == sexpr)
+ return testing::AssertionSuccess();
+ return testing::AssertionFailure() << "Parsing: " << c_expr
+ << "\nExpected: " << sexpr
+ << "\nGot: " << actual_sexpr;
}
} // namespace
#define EXPECT_PARSE(s, c) EXPECT_PRED_FORMAT2(CheckStatement, s, c)
-TEST(GoParserTest, ParseBasicLiterals)
-{
- EXPECT_PARSE("(ExprStmt (BasicLit 0 ) ) ", "0");
- EXPECT_PARSE("(ExprStmt (BasicLit 42 ) ) ", "42");
- EXPECT_PARSE("(ExprStmt (BasicLit 0600 ) ) ", "0600");
- EXPECT_PARSE("(ExprStmt (BasicLit 0xBadFace ) ) ", "0xBadFace");
- EXPECT_PARSE("(ExprStmt (BasicLit 170141183460469231731687303715884105727 ) ) ",
- "170141183460469231731687303715884105727");
-
- EXPECT_PARSE("(ExprStmt (BasicLit 0. ) ) ", "0.");
- EXPECT_PARSE("(ExprStmt (BasicLit 72.40 ) ) ", "72.40");
- EXPECT_PARSE("(ExprStmt (BasicLit 072.40 ) ) ", "072.40");
- EXPECT_PARSE("(ExprStmt (BasicLit 2.71828 ) ) ", "2.71828");
- EXPECT_PARSE("(ExprStmt (BasicLit 1.e+0 ) ) ", "1.e+0");
- EXPECT_PARSE("(ExprStmt (BasicLit 6.67428e-11 ) ) ", "6.67428e-11");
- EXPECT_PARSE("(ExprStmt (BasicLit 1E6 ) ) ", "1E6");
- EXPECT_PARSE("(ExprStmt (BasicLit .12345E+6 ) ) ", ".12345E+6");
-
- EXPECT_PARSE("(ExprStmt (BasicLit 0i ) ) ", "0i");
- EXPECT_PARSE("(ExprStmt (BasicLit 011i ) ) ", "011i");
- EXPECT_PARSE("(ExprStmt (BasicLit 0.i ) ) ", "0.i");
- EXPECT_PARSE("(ExprStmt (BasicLit 2.71828i ) ) ", "2.71828i");
- EXPECT_PARSE("(ExprStmt (BasicLit 6.67428e-11i ) ) ", "6.67428e-11i");
- EXPECT_PARSE("(ExprStmt (BasicLit 1E6i ) ) ", "1E6i");
- EXPECT_PARSE("(ExprStmt (BasicLit .12345E+6i ) ) ", ".12345E+6i");
-
- EXPECT_PARSE("(ExprStmt (BasicLit 'a' ) ) ", "'a'");
- EXPECT_PARSE("(ExprStmt (BasicLit '本' ) ) ", "'本'");
- EXPECT_PARSE("(ExprStmt (BasicLit \"abc\" ) ) ", "\"abc\"");
- EXPECT_PARSE("(ExprStmt (BasicLit `abc` ) ) ", "`abc`");
- EXPECT_PARSE("(ExprStmt (BasicLit `ab\nc` ) ) ", "`ab\nc`");
+TEST(GoParserTest, ParseBasicLiterals) {
+ EXPECT_PARSE("(ExprStmt (BasicLit 0 ) ) ", "0");
+ EXPECT_PARSE("(ExprStmt (BasicLit 42 ) ) ", "42");
+ EXPECT_PARSE("(ExprStmt (BasicLit 0600 ) ) ", "0600");
+ EXPECT_PARSE("(ExprStmt (BasicLit 0xBadFace ) ) ", "0xBadFace");
+ EXPECT_PARSE(
+ "(ExprStmt (BasicLit 170141183460469231731687303715884105727 ) ) ",
+ "170141183460469231731687303715884105727");
+
+ EXPECT_PARSE("(ExprStmt (BasicLit 0. ) ) ", "0.");
+ EXPECT_PARSE("(ExprStmt (BasicLit 72.40 ) ) ", "72.40");
+ EXPECT_PARSE("(ExprStmt (BasicLit 072.40 ) ) ", "072.40");
+ EXPECT_PARSE("(ExprStmt (BasicLit 2.71828 ) ) ", "2.71828");
+ EXPECT_PARSE("(ExprStmt (BasicLit 1.e+0 ) ) ", "1.e+0");
+ EXPECT_PARSE("(ExprStmt (BasicLit 6.67428e-11 ) ) ", "6.67428e-11");
+ EXPECT_PARSE("(ExprStmt (BasicLit 1E6 ) ) ", "1E6");
+ EXPECT_PARSE("(ExprStmt (BasicLit .12345E+6 ) ) ", ".12345E+6");
+
+ EXPECT_PARSE("(ExprStmt (BasicLit 0i ) ) ", "0i");
+ EXPECT_PARSE("(ExprStmt (BasicLit 011i ) ) ", "011i");
+ EXPECT_PARSE("(ExprStmt (BasicLit 0.i ) ) ", "0.i");
+ EXPECT_PARSE("(ExprStmt (BasicLit 2.71828i ) ) ", "2.71828i");
+ EXPECT_PARSE("(ExprStmt (BasicLit 6.67428e-11i ) ) ", "6.67428e-11i");
+ EXPECT_PARSE("(ExprStmt (BasicLit 1E6i ) ) ", "1E6i");
+ EXPECT_PARSE("(ExprStmt (BasicLit .12345E+6i ) ) ", ".12345E+6i");
+
+ EXPECT_PARSE("(ExprStmt (BasicLit 'a' ) ) ", "'a'");
+ EXPECT_PARSE("(ExprStmt (BasicLit '本' ) ) ", "'本'");
+ EXPECT_PARSE("(ExprStmt (BasicLit \"abc\" ) ) ", "\"abc\"");
+ EXPECT_PARSE("(ExprStmt (BasicLit `abc` ) ) ", "`abc`");
+ EXPECT_PARSE("(ExprStmt (BasicLit `ab\nc` ) ) ", "`ab\nc`");
}
-TEST(GoParserTest, ParseOperand)
-{
- EXPECT_PARSE("(ExprStmt (Ident a ) ) ", "a");
- EXPECT_PARSE("(ExprStmt (Ident _x9 ) ) ", "_x9");
- EXPECT_PARSE("(ExprStmt (Ident ThisVariableIsExported ) ) ", "ThisVariableIsExported");
- EXPECT_PARSE("(ExprStmt (Ident αβ ) ) ", "αβ");
+TEST(GoParserTest, ParseOperand) {
+ EXPECT_PARSE("(ExprStmt (Ident a ) ) ", "a");
+ EXPECT_PARSE("(ExprStmt (Ident _x9 ) ) ", "_x9");
+ EXPECT_PARSE("(ExprStmt (Ident ThisVariableIsExported ) ) ",
+ "ThisVariableIsExported");
+ EXPECT_PARSE("(ExprStmt (Ident αβ ) ) ", "αβ");
- EXPECT_PARSE("(ExprStmt (SelectorExpr (Ident math ) (Ident Sin ) ) ) ", "math.Sin");
+ EXPECT_PARSE("(ExprStmt (SelectorExpr (Ident math ) (Ident Sin ) ) ) ",
+ "math.Sin");
}
-TEST(GoParserTest, ParseCompositeLiterals)
-{
- EXPECT_PARSE("(ExprStmt (CompositeLit (Ident Point3D ) ) ) ", "Point3D{}");
- EXPECT_PARSE("(ExprStmt (CompositeLit (Ident Line ) (Ident origin ) (CompositeLit (Ident Point3D ) (KeyValueExpr "
- "(Ident y ) (UnaryExpr (BasicLit 4 ) - ) ) (KeyValueExpr (Ident z ) (BasicLit 12.3 ) ) ) ) ) ",
- "Line{origin, Point3D{y: -4, z: 12.3}}");
- EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 10 ) (Ident string ) ) ) ) ", "[10]string{}");
- EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 6 ) (Ident int ) ) (BasicLit 1 ) (BasicLit 2 ) "
- "(BasicLit 3 ) (BasicLit 5 ) ) ) ",
- "[6]int {1, 2, 3, 5}");
- EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType nil (Ident int ) ) (BasicLit 2 ) (BasicLit 3 ) (BasicLit 5 ) "
- "(BasicLit 7 ) (BasicLit 9 ) (BasicLit 2147483647 ) ) ) ",
- "[]int{2, 3, 5, 7, 9, 2147483647}");
- EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 128 ) (Ident bool ) ) (KeyValueExpr (BasicLit 'a' ) "
- "(Ident true ) ) (KeyValueExpr (BasicLit 'e' ) (Ident true ) ) (KeyValueExpr (BasicLit 'i' ) (Ident "
- "true ) ) (KeyValueExpr (BasicLit 'o' ) (Ident true ) ) (KeyValueExpr (BasicLit 'u' ) (Ident true ) ) "
- "(KeyValueExpr (BasicLit 'y' ) (Ident true ) ) ) ) ",
- "[128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true}");
- EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 10 ) (Ident float32 ) ) (UnaryExpr (BasicLit 1 ) - ) "
- "(KeyValueExpr (BasicLit 4 ) (UnaryExpr (BasicLit 0.1 ) - ) ) (UnaryExpr (BasicLit 0.1 ) - ) "
- "(KeyValueExpr (BasicLit 9 ) (UnaryExpr (BasicLit 1 ) - ) ) ) ) ",
- "[10]float32{-1, 4: -0.1, -0.1, 9: -1}");
+TEST(GoParserTest, ParseCompositeLiterals) {
+ EXPECT_PARSE("(ExprStmt (CompositeLit (Ident Point3D ) ) ) ", "Point3D{}");
+ EXPECT_PARSE("(ExprStmt (CompositeLit (Ident Line ) (Ident origin ) "
+ "(CompositeLit (Ident Point3D ) (KeyValueExpr "
+ "(Ident y ) (UnaryExpr (BasicLit 4 ) - ) ) (KeyValueExpr (Ident "
+ "z ) (BasicLit 12.3 ) ) ) ) ) ",
+ "Line{origin, Point3D{y: -4, z: 12.3}}");
+ EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 10 ) (Ident "
+ "string ) ) ) ) ",
+ "[10]string{}");
+ EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 6 ) (Ident int ) "
+ ") (BasicLit 1 ) (BasicLit 2 ) "
+ "(BasicLit 3 ) (BasicLit 5 ) ) ) ",
+ "[6]int {1, 2, 3, 5}");
+ EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType nil (Ident int ) ) "
+ "(BasicLit 2 ) (BasicLit 3 ) (BasicLit 5 ) "
+ "(BasicLit 7 ) (BasicLit 9 ) (BasicLit 2147483647 ) ) ) ",
+ "[]int{2, 3, 5, 7, 9, 2147483647}");
+ EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 128 ) (Ident bool "
+ ") ) (KeyValueExpr (BasicLit 'a' ) "
+ "(Ident true ) ) (KeyValueExpr (BasicLit 'e' ) (Ident true ) ) "
+ "(KeyValueExpr (BasicLit 'i' ) (Ident "
+ "true ) ) (KeyValueExpr (BasicLit 'o' ) (Ident true ) ) "
+ "(KeyValueExpr (BasicLit 'u' ) (Ident true ) ) "
+ "(KeyValueExpr (BasicLit 'y' ) (Ident true ) ) ) ) ",
+ "[128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': "
+ "true, 'y': true}");
+ EXPECT_PARSE(
+ "(ExprStmt (CompositeLit (ArrayType (BasicLit 10 ) (Ident float32 ) ) "
+ "(UnaryExpr (BasicLit 1 ) - ) "
+ "(KeyValueExpr (BasicLit 4 ) (UnaryExpr (BasicLit 0.1 ) - ) ) (UnaryExpr "
+ "(BasicLit 0.1 ) - ) "
+ "(KeyValueExpr (BasicLit 9 ) (UnaryExpr (BasicLit 1 ) - ) ) ) ) ",
+ "[10]float32{-1, 4: -0.1, -0.1, 9: -1}");
}
-TEST(GoParserTest, ParseEllipsisArray)
-{
- EXPECT_PARSE(
- "(ExprStmt (CompositeLit (ArrayType (Ellipsis nil ) (Ident string ) ) (BasicLit `Sat` ) (BasicLit `Sun` ) ) ) ",
- "[...]string {`Sat`, `Sun`}");
- EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (Ellipsis nil ) (Ident Point ) ) (CompositeLit nil (BasicLit 1.5 "
- ") (UnaryExpr (BasicLit 3.5 ) - ) ) (CompositeLit nil (BasicLit 0 ) (BasicLit 0 ) ) ) ) ",
- "[...]Point{{1.5, -3.5}, {0, 0}}");
+TEST(GoParserTest, ParseEllipsisArray) {
+ EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (Ellipsis nil ) (Ident "
+ "string ) ) (BasicLit `Sat` ) (BasicLit `Sun` ) ) ) ",
+ "[...]string {`Sat`, `Sun`}");
+ EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (Ellipsis nil ) (Ident "
+ "Point ) ) (CompositeLit nil (BasicLit 1.5 "
+ ") (UnaryExpr (BasicLit 3.5 ) - ) ) (CompositeLit nil (BasicLit "
+ "0 ) (BasicLit 0 ) ) ) ) ",
+ "[...]Point{{1.5, -3.5}, {0, 0}}");
}
-TEST(GoParserTest, ParseMap)
-{
- EXPECT_PARSE("(ExprStmt (CompositeLit (MapType (Ident string ) (Ident float32 ) ) (KeyValueExpr (BasicLit `C0` ) "
- "(BasicLit 16.35 ) ) (KeyValueExpr (BasicLit `D0` ) (BasicLit 18.35 ) ) ) ) ",
- "map[string]float32{`C0`: 16.35, `D0`: 18.35, }");
+TEST(GoParserTest, ParseMap) {
+ EXPECT_PARSE("(ExprStmt (CompositeLit (MapType (Ident string ) (Ident "
+ "float32 ) ) (KeyValueExpr (BasicLit `C0` ) "
+ "(BasicLit 16.35 ) ) (KeyValueExpr (BasicLit `D0` ) (BasicLit "
+ "18.35 ) ) ) ) ",
+ "map[string]float32{`C0`: 16.35, `D0`: 18.35, }");
}
-TEST(GoParserTest, UnaryExpr)
-{
- EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) + ) ) ", "+x");
- EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) - ) ) ", "-x");
- EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) ! ) ) ", "!x");
- EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) ^ ) ) ", "^x");
- EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) & ) ) ", "&x");
- EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) <- ) ) ", "<-x");
- EXPECT_PARSE("(ExprStmt (StarExpr (Ident x ) ) ) ", "*x");
+TEST(GoParserTest, UnaryExpr) {
+ EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) + ) ) ", "+x");
+ EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) - ) ) ", "-x");
+ EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) ! ) ) ", "!x");
+ EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) ^ ) ) ", "^x");
+ EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) & ) ) ", "&x");
+ EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) <- ) ) ", "<-x");
+ EXPECT_PARSE("(ExprStmt (StarExpr (Ident x ) ) ) ", "*x");
}
-TEST(GoParserTest, BinaryExpr)
-{
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) || ) ) ", "a || b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) && ) ) ", "a && b");
-
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) == ) ) ", "a == b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) != ) ) ", "a != b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) < ) ) ", "a < b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) <= ) ) ", "a <= b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) > ) ) ", "a > b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) >= ) ) ", "a >= b");
-
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) + ) ) ", "a + b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) - ) ) ", "a - b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) | ) ) ", "a | b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) ^ ) ) ", "a ^ b");
-
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) * ) ) ", "a * b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) / ) ) ", "a / b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) % ) ) ", "a % b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) << ) ) ", "a << b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) >> ) ) ", "a >> b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) & ) ) ", "a & b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) &^ ) ) ", "a &^ b");
-
- EXPECT_PARSE(
- "(ExprStmt (BinaryExpr (BasicLit 23 ) (BinaryExpr (BasicLit 3 ) (IndexExpr (Ident x ) (Ident i ) ) * ) + ) ) ",
- "23 + 3*x[i]");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (UnaryExpr (UnaryExpr (Ident a ) + ) + ) + ) ) ", "a + + + a");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (UnaryExpr (Ident a ) ^ ) (Ident b ) >> ) ) ", "^a >> b");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (CallExpr (Ident f ) ) (CallExpr (Ident g ) ) || ) ) ", "f() || g()");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (BinaryExpr (Ident x ) (BinaryExpr (Ident y ) (BasicLit 1 ) + ) == ) "
- "(BinaryExpr (UnaryExpr (Ident chanPtr ) <- ) (BasicLit 0 ) > ) && ) ) ",
- "x == y+1 && <-chanPtr > 0");
+TEST(GoParserTest, BinaryExpr) {
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) || ) ) ", "a || b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) && ) ) ", "a && b");
+
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) == ) ) ", "a == b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) != ) ) ", "a != b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) < ) ) ", "a < b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) <= ) ) ", "a <= b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) > ) ) ", "a > b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) >= ) ) ", "a >= b");
+
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) + ) ) ", "a + b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) - ) ) ", "a - b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) | ) ) ", "a | b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) ^ ) ) ", "a ^ b");
+
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) * ) ) ", "a * b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) / ) ) ", "a / b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) % ) ) ", "a % b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) << ) ) ", "a << b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) >> ) ) ", "a >> b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) & ) ) ", "a & b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) &^ ) ) ", "a &^ b");
+
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (BasicLit 23 ) (BinaryExpr (BasicLit 3 ) "
+ "(IndexExpr (Ident x ) (Ident i ) ) * ) + ) ) ",
+ "23 + 3*x[i]");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (UnaryExpr (UnaryExpr (Ident "
+ "a ) + ) + ) + ) ) ",
+ "a + + + a");
+ EXPECT_PARSE(
+ "(ExprStmt (BinaryExpr (UnaryExpr (Ident a ) ^ ) (Ident b ) >> ) ) ",
+ "^a >> b");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (CallExpr (Ident f ) ) (CallExpr (Ident "
+ "g ) ) || ) ) ",
+ "f() || g()");
+ EXPECT_PARSE(
+ "(ExprStmt (BinaryExpr (BinaryExpr (Ident x ) (BinaryExpr (Ident y ) "
+ "(BasicLit 1 ) + ) == ) "
+ "(BinaryExpr (UnaryExpr (Ident chanPtr ) <- ) (BasicLit 0 ) > ) && ) ) ",
+ "x == y+1 && <-chanPtr > 0");
}
-TEST(GoParserTest, PrimaryExpr)
-{
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident x ) (CallExpr (Ident f ) ) <= ) ) ", "x <= f()");
- EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident s ) (BasicLit `.txt` ) + ) ) ", "(s + `.txt`)");
- EXPECT_PARSE("(ExprStmt (CallExpr (Ident f ) (BasicLit 3.1415 ) (Ident true ) ) ) ", "f(3.1415, true)");
- EXPECT_PARSE("(ExprStmt (CallExpr (Ident f ) (BasicLit 3.1415 ) (Ident a ) ... ) ) ", "f(3.1415, a...)");
- EXPECT_PARSE("(ExprStmt (IndexExpr (Ident m ) (BasicLit '1' ) ) ) ", "m['1']");
- EXPECT_PARSE("(ExprStmt (SliceExpr (Ident s ) (Ident i ) (BinaryExpr (Ident j ) (BasicLit 1 ) + ) nil 0 ) ) ",
- "s[i : j + 1]");
- EXPECT_PARSE("(ExprStmt (SelectorExpr (Ident obj ) (Ident color ) ) ) ", "obj.color");
- EXPECT_PARSE("(ExprStmt (CallExpr (SelectorExpr (IndexExpr (SelectorExpr (Ident f ) (Ident p ) ) (Ident i ) ) "
- "(Ident x ) ) ) ) ",
- "f.p[i].x()");
+TEST(GoParserTest, PrimaryExpr) {
+ EXPECT_PARSE(
+ "(ExprStmt (BinaryExpr (Ident x ) (CallExpr (Ident f ) ) <= ) ) ",
+ "x <= f()");
+ EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident s ) (BasicLit `.txt` ) + ) ) ",
+ "(s + `.txt`)");
+ EXPECT_PARSE(
+ "(ExprStmt (CallExpr (Ident f ) (BasicLit 3.1415 ) (Ident true ) ) ) ",
+ "f(3.1415, true)");
+ EXPECT_PARSE(
+ "(ExprStmt (CallExpr (Ident f ) (BasicLit 3.1415 ) (Ident a ) ... ) ) ",
+ "f(3.1415, a...)");
+ EXPECT_PARSE("(ExprStmt (IndexExpr (Ident m ) (BasicLit '1' ) ) ) ",
+ "m['1']");
+ EXPECT_PARSE("(ExprStmt (SliceExpr (Ident s ) (Ident i ) (BinaryExpr (Ident "
+ "j ) (BasicLit 1 ) + ) nil 0 ) ) ",
+ "s[i : j + 1]");
+ EXPECT_PARSE("(ExprStmt (SelectorExpr (Ident obj ) (Ident color ) ) ) ",
+ "obj.color");
+ EXPECT_PARSE("(ExprStmt (CallExpr (SelectorExpr (IndexExpr (SelectorExpr "
+ "(Ident f ) (Ident p ) ) (Ident i ) ) "
+ "(Ident x ) ) ) ) ",
+ "f.p[i].x()");
}
-TEST(GoParserTest, Conversions)
-{
- EXPECT_PARSE("(ExprStmt (StarExpr (CallExpr (Ident Point ) (Ident p ) ) ) ) ", "*Point(p)");
- EXPECT_PARSE("(ExprStmt (CallExpr (StarExpr (Ident Point ) ) (Ident p ) ) ) ", "(*Point)(p)");
- EXPECT_PARSE("(ExprStmt (UnaryExpr (CallExpr (ChanType (Ident int ) 0 ) (Ident c ) ) <- ) ) ", "<-chan int(c)");
- EXPECT_PARSE("(ExprStmt (TypeAssertExpr (Ident y ) (SelectorExpr (Ident io ) (Ident Reader ) ) ) ) ",
- "y.(io.Reader)");
+TEST(GoParserTest, Conversions) {
+ EXPECT_PARSE(
+ "(ExprStmt (StarExpr (CallExpr (Ident Point ) (Ident p ) ) ) ) ",
+ "*Point(p)");
+ EXPECT_PARSE(
+ "(ExprStmt (CallExpr (StarExpr (Ident Point ) ) (Ident p ) ) ) ",
+ "(*Point)(p)");
+ EXPECT_PARSE("(ExprStmt (UnaryExpr (CallExpr (ChanType (Ident int ) 0 ) "
+ "(Ident c ) ) <- ) ) ",
+ "<-chan int(c)");
+ EXPECT_PARSE("(ExprStmt (TypeAssertExpr (Ident y ) (SelectorExpr (Ident io ) "
+ "(Ident Reader ) ) ) ) ",
+ "y.(io.Reader)");
}
diff --git a/unittests/Host/CMakeLists.txt b/unittests/Host/CMakeLists.txt
index be0450874203..4c20f820e3c8 100644
--- a/unittests/Host/CMakeLists.txt
+++ b/unittests/Host/CMakeLists.txt
@@ -1,5 +1,6 @@
add_lldb_unittest(HostTests
FileSpecTest.cpp
+ FileSystemTest.cpp
SocketAddressTest.cpp
SocketTest.cpp
SymbolsTest.cpp
diff --git a/unittests/Host/FileSpecTest.cpp b/unittests/Host/FileSpecTest.cpp
index 4e619529773f..55a66b3b37eb 100644
--- a/unittests/Host/FileSpecTest.cpp
+++ b/unittests/Host/FileSpecTest.cpp
@@ -13,99 +13,274 @@
using namespace lldb_private;
-TEST(FileSpecTest, FileAndDirectoryComponents)
-{
- FileSpec fs_posix("/foo/bar", false, FileSpec::ePathSyntaxPosix);
- EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
- EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
-
- FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
- EXPECT_STREQ("F:\\bar", fs_windows.GetCString());
- // EXPECT_STREQ("F:\\", fs_windows.GetDirectory().GetCString()); // It returns "F:/"
- EXPECT_STREQ("bar", fs_windows.GetFilename().GetCString());
-
- FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
- EXPECT_STREQ("/", fs_posix_root.GetCString());
- EXPECT_EQ(nullptr, fs_posix_root.GetDirectory().GetCString());
- EXPECT_STREQ("/", fs_posix_root.GetFilename().GetCString());
-
- FileSpec fs_windows_drive("F:", false, FileSpec::ePathSyntaxWindows);
- EXPECT_STREQ("F:", fs_windows_drive.GetCString());
- EXPECT_EQ(nullptr, fs_windows_drive.GetDirectory().GetCString());
- EXPECT_STREQ("F:", fs_windows_drive.GetFilename().GetCString());
-
- FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
- EXPECT_STREQ("F:\\", fs_windows_root.GetCString());
- EXPECT_STREQ("F:", fs_windows_root.GetDirectory().GetCString());
- // EXPECT_STREQ("\\", fs_windows_root.GetFilename().GetCString()); // It returns "/"
-
- FileSpec fs_posix_long("/foo/bar/baz", false, FileSpec::ePathSyntaxPosix);
- EXPECT_STREQ("/foo/bar/baz", fs_posix_long.GetCString());
- EXPECT_STREQ("/foo/bar", fs_posix_long.GetDirectory().GetCString());
- EXPECT_STREQ("baz", fs_posix_long.GetFilename().GetCString());
-
- FileSpec fs_windows_long("F:\\bar\\baz", false, FileSpec::ePathSyntaxWindows);
- EXPECT_STREQ("F:\\bar\\baz", fs_windows_long.GetCString());
- // EXPECT_STREQ("F:\\bar", fs_windows_long.GetDirectory().GetCString()); // It returns "F:/bar"
- EXPECT_STREQ("baz", fs_windows_long.GetFilename().GetCString());
-
- FileSpec fs_posix_trailing_slash("/foo/bar/", false, FileSpec::ePathSyntaxPosix);
- EXPECT_STREQ("/foo/bar/.", fs_posix_trailing_slash.GetCString());
- EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetDirectory().GetCString());
- EXPECT_STREQ(".", fs_posix_trailing_slash.GetFilename().GetCString());
-
- FileSpec fs_windows_trailing_slash("F:\\bar\\", false, FileSpec::ePathSyntaxWindows);
- EXPECT_STREQ("F:\\bar\\.", fs_windows_trailing_slash.GetCString());
- // EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetDirectory().GetCString()); // It returns "F:/bar"
- EXPECT_STREQ(".", fs_windows_trailing_slash.GetFilename().GetCString());
+TEST(FileSpecTest, FileAndDirectoryComponents) {
+ FileSpec fs_posix("/foo/bar", false, FileSpec::ePathSyntaxPosix);
+ EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
+ EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
+ EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
+
+ FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:\\bar", fs_windows.GetCString());
+ // EXPECT_STREQ("F:\\", fs_windows.GetDirectory().GetCString()); // It returns
+ // "F:/"
+ EXPECT_STREQ("bar", fs_windows.GetFilename().GetCString());
+
+ FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
+ EXPECT_STREQ("/", fs_posix_root.GetCString());
+ EXPECT_EQ(nullptr, fs_posix_root.GetDirectory().GetCString());
+ EXPECT_STREQ("/", fs_posix_root.GetFilename().GetCString());
+
+ FileSpec fs_windows_drive("F:", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:", fs_windows_drive.GetCString());
+ EXPECT_EQ(nullptr, fs_windows_drive.GetDirectory().GetCString());
+ EXPECT_STREQ("F:", fs_windows_drive.GetFilename().GetCString());
+
+ FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:\\", fs_windows_root.GetCString());
+ EXPECT_STREQ("F:", fs_windows_root.GetDirectory().GetCString());
+ // EXPECT_STREQ("\\", fs_windows_root.GetFilename().GetCString()); // It
+ // returns "/"
+
+ FileSpec fs_posix_long("/foo/bar/baz", false, FileSpec::ePathSyntaxPosix);
+ EXPECT_STREQ("/foo/bar/baz", fs_posix_long.GetCString());
+ EXPECT_STREQ("/foo/bar", fs_posix_long.GetDirectory().GetCString());
+ EXPECT_STREQ("baz", fs_posix_long.GetFilename().GetCString());
+
+ FileSpec fs_windows_long("F:\\bar\\baz", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:\\bar\\baz", fs_windows_long.GetCString());
+ // EXPECT_STREQ("F:\\bar", fs_windows_long.GetDirectory().GetCString()); // It
+ // returns "F:/bar"
+ EXPECT_STREQ("baz", fs_windows_long.GetFilename().GetCString());
+
+ FileSpec fs_posix_trailing_slash("/foo/bar/", false,
+ FileSpec::ePathSyntaxPosix);
+ EXPECT_STREQ("/foo/bar/.", fs_posix_trailing_slash.GetCString());
+ EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetDirectory().GetCString());
+ EXPECT_STREQ(".", fs_posix_trailing_slash.GetFilename().GetCString());
+
+ FileSpec fs_windows_trailing_slash("F:\\bar\\", false,
+ FileSpec::ePathSyntaxWindows);
+ EXPECT_STREQ("F:\\bar\\.", fs_windows_trailing_slash.GetCString());
+ // EXPECT_STREQ("F:\\bar",
+ // fs_windows_trailing_slash.GetDirectory().GetCString()); // It returns
+ // "F:/bar"
+ EXPECT_STREQ(".", fs_windows_trailing_slash.GetFilename().GetCString());
+}
+
+TEST(FileSpecTest, AppendPathComponent) {
+ FileSpec fs_posix("/foo", false, FileSpec::ePathSyntaxPosix);
+ fs_posix.AppendPathComponent("bar");
+ EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
+ EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
+ EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
+
+ FileSpec fs_posix_2("/foo", false, FileSpec::ePathSyntaxPosix);
+ fs_posix_2.AppendPathComponent("//bar/baz");
+ EXPECT_STREQ("/foo/bar/baz", fs_posix_2.GetCString());
+ EXPECT_STREQ("/foo/bar", fs_posix_2.GetDirectory().GetCString());
+ EXPECT_STREQ("baz", fs_posix_2.GetFilename().GetCString());
+
+ FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
+ fs_windows.AppendPathComponent("baz");
+ EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
+ // EXPECT_STREQ("F:\\bar", fs_windows.GetDirectory().GetCString()); // It
+ // returns "F:/bar"
+ EXPECT_STREQ("baz", fs_windows.GetFilename().GetCString());
+
+ FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
+ fs_posix_root.AppendPathComponent("bar");
+ EXPECT_STREQ("/bar", fs_posix_root.GetCString());
+ EXPECT_STREQ("/", fs_posix_root.GetDirectory().GetCString());
+ EXPECT_STREQ("bar", fs_posix_root.GetFilename().GetCString());
+
+ FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
+ fs_windows_root.AppendPathComponent("bar");
+ EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
+ // EXPECT_STREQ("F:\\", fs_windows_root.GetDirectory().GetCString()); // It
+ // returns "F:/"
+ EXPECT_STREQ("bar", fs_windows_root.GetFilename().GetCString());
+}
+
+TEST(FileSpecTest, CopyByAppendingPathComponent) {
+ FileSpec fs = FileSpec("/foo", false, FileSpec::ePathSyntaxPosix)
+ .CopyByAppendingPathComponent("bar");
+ EXPECT_STREQ("/foo/bar", fs.GetCString());
+ EXPECT_STREQ("/foo", fs.GetDirectory().GetCString());
+ EXPECT_STREQ("bar", fs.GetFilename().GetCString());
+}
+
+static void Compare(const FileSpec &one, const FileSpec &two, bool full_match,
+ bool remove_backup_dots, bool result) {
+ EXPECT_EQ(result, FileSpec::Equal(one, two, full_match, remove_backup_dots))
+ << "File one: " << one.GetCString() << "\nFile two: " << two.GetCString()
+ << "\nFull match: " << full_match
+ << "\nRemove backup dots: " << remove_backup_dots;
}
-TEST(FileSpecTest, AppendPathComponent)
-{
- FileSpec fs_posix("/foo", false, FileSpec::ePathSyntaxPosix);
- fs_posix.AppendPathComponent("bar");
- EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
- EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
-
- FileSpec fs_windows("F:\\bar", false, FileSpec::ePathSyntaxWindows);
- fs_windows.AppendPathComponent("baz");
- EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
- // EXPECT_STREQ("F:\\bar", fs_windows.GetDirectory().GetCString()); // It returns "F:/bar"
- EXPECT_STREQ("baz", fs_windows.GetFilename().GetCString());
-
- FileSpec fs_posix_root("/", false, FileSpec::ePathSyntaxPosix);
- fs_posix_root.AppendPathComponent("bar");
- EXPECT_STREQ("/bar", fs_posix_root.GetCString());
- EXPECT_STREQ("/", fs_posix_root.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs_posix_root.GetFilename().GetCString());
-
- FileSpec fs_windows_root("F:\\", false, FileSpec::ePathSyntaxWindows);
- fs_windows_root.AppendPathComponent("bar");
- EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
- // EXPECT_STREQ("F:\\", fs_windows_root.GetDirectory().GetCString()); // It returns "F:/"
- EXPECT_STREQ("bar", fs_windows_root.GetFilename().GetCString());
+TEST(FileSpecTest, EqualSeparator) {
+ FileSpec backward("C:\\foo\\bar", false, FileSpec::ePathSyntaxWindows);
+ FileSpec forward("C:/foo/bar", false, FileSpec::ePathSyntaxWindows);
+ EXPECT_EQ(forward, backward);
+
+ const bool full_match = true;
+ const bool remove_backup_dots = true;
+ const bool match = true;
+ Compare(forward, backward, full_match, remove_backup_dots, match);
+ Compare(forward, backward, full_match, !remove_backup_dots, match);
+ Compare(forward, backward, !full_match, remove_backup_dots, match);
+ Compare(forward, backward, !full_match, !remove_backup_dots, match);
}
-TEST(FileSpecTest, CopyByAppendingPathComponent)
-{
- FileSpec fs = FileSpec("/foo", false, FileSpec::ePathSyntaxPosix).CopyByAppendingPathComponent("bar");
- EXPECT_STREQ("/foo/bar", fs.GetCString());
- EXPECT_STREQ("/foo", fs.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs.GetFilename().GetCString());
+TEST(FileSpecTest, EqualDotsWindows) {
+ const bool full_match = true;
+ const bool remove_backup_dots = true;
+ const bool match = true;
+ std::pair<const char *, const char *> tests[] = {
+ {R"(C:\foo\bar\baz)", R"(C:\foo\foo\..\bar\baz)"},
+ {R"(C:\bar\baz)", R"(C:\foo\..\bar\baz)"},
+ {R"(C:\bar\baz)", R"(C:/foo/../bar/baz)"},
+ {R"(C:/bar/baz)", R"(C:\foo\..\bar\baz)"},
+ {R"(C:\bar)", R"(C:\foo\..\bar)"},
+ {R"(C:\foo\bar)", R"(C:\foo\.\bar)"},
+ };
+
+ for(const auto &test: tests) {
+ FileSpec one(test.first, false, FileSpec::ePathSyntaxWindows);
+ FileSpec two(test.second, false, FileSpec::ePathSyntaxWindows);
+ EXPECT_NE(one, two);
+ Compare(one, two, full_match, remove_backup_dots, match);
+ Compare(one, two, full_match, !remove_backup_dots, !match);
+ Compare(one, two, !full_match, remove_backup_dots, match);
+ Compare(one, two, !full_match, !remove_backup_dots, !match);
+ }
+
}
-TEST(FileSpecTest, Equal)
-{
- FileSpec backward("C:\\foo\\bar", false, FileSpec::ePathSyntaxWindows);
- FileSpec forward("C:/foo/bar", false, FileSpec::ePathSyntaxWindows);
- EXPECT_EQ(forward, backward);
-
- const bool full_match = true;
- const bool remove_backup_dots = true;
- EXPECT_TRUE(FileSpec::Equal(forward, backward, full_match, remove_backup_dots));
- EXPECT_TRUE(FileSpec::Equal(forward, backward, full_match, !remove_backup_dots));
- EXPECT_TRUE(FileSpec::Equal(forward, backward, !full_match, remove_backup_dots));
- EXPECT_TRUE(FileSpec::Equal(forward, backward, !full_match, !remove_backup_dots));
+TEST(FileSpecTest, EqualDotsPosix) {
+ const bool full_match = true;
+ const bool remove_backup_dots = true;
+ const bool match = true;
+ std::pair<const char *, const char *> tests[] = {
+ {R"(/foo/bar/baz)", R"(/foo/foo/../bar/baz)"},
+ {R"(/bar/baz)", R"(/foo/../bar/baz)"},
+ {R"(/bar)", R"(/foo/../bar)"},
+ {R"(/foo/bar)", R"(/foo/./bar)"},
+ };
+
+ for(const auto &test: tests) {
+ FileSpec one(test.first, false, FileSpec::ePathSyntaxPosix);
+ FileSpec two(test.second, false, FileSpec::ePathSyntaxPosix);
+ EXPECT_NE(one, two);
+ Compare(one, two, full_match, remove_backup_dots, match);
+ Compare(one, two, full_match, !remove_backup_dots, !match);
+ Compare(one, two, !full_match, remove_backup_dots, match);
+ Compare(one, two, !full_match, !remove_backup_dots, !match);
+ }
+
+}
+
+TEST(FileSpecTest, EqualDotsPosixRoot) {
+ const bool full_match = true;
+ const bool remove_backup_dots = true;
+ const bool match = true;
+ std::pair<const char *, const char *> tests[] = {
+ {R"(/)", R"(/..)"}, {R"(/)", R"(/.)"}, {R"(/)", R"(/foo/..)"},
+ };
+
+ for(const auto &test: tests) {
+ FileSpec one(test.first, false, FileSpec::ePathSyntaxPosix);
+ FileSpec two(test.second, false, FileSpec::ePathSyntaxPosix);
+ EXPECT_NE(one, two);
+ Compare(one, two, full_match, remove_backup_dots, match);
+ Compare(one, two, full_match, !remove_backup_dots, !match);
+ Compare(one, two, !full_match, remove_backup_dots, !match);
+ Compare(one, two, !full_match, !remove_backup_dots, !match);
+ }
}
+
+TEST(FileSpecTest, GetNormalizedPath) {
+ std::pair<const char *, const char *> posix_tests[] = {
+ {"/foo/.././bar", "/bar"},
+ {"/foo/./../bar", "/bar"},
+ {"/foo/../bar", "/bar"},
+ {"/foo/./bar", "/foo/bar"},
+ {"/foo/..", "/"},
+ {"/foo/.", "/foo"},
+ {"/foo//bar", "/foo/bar"},
+ {"/foo//bar/baz", "/foo/bar/baz"},
+ {"/foo//bar/./baz", "/foo/bar/baz"},
+ {"/./foo", "/foo"},
+ {"/", "/"},
+ {"//", "//"},
+ {"//net", "//net"},
+ {"/..", "/"},
+ {"/.", "/"},
+ {"..", ".."},
+ {".", "."},
+ {"../..", "../.."},
+ {"foo/..", "."},
+ {"foo/../bar", "bar"},
+ {"../foo/..", ".."},
+ {"./foo", "foo"},
+ };
+ for (auto test : posix_tests) {
+ EXPECT_EQ(test.second,
+ FileSpec(test.first, false, FileSpec::ePathSyntaxPosix)
+ .GetNormalizedPath()
+ .GetPath());
+ }
+
+ std::pair<const char *, const char *> windows_tests[] = {
+ {R"(c:\bar\..\bar)", R"(c:\bar)"},
+ {R"(c:\bar\.\bar)", R"(c:\bar\bar)"},
+ {R"(c:\bar\..)", R"(c:\)"},
+ {R"(c:\bar\.)", R"(c:\bar)"},
+ {R"(c:\.\bar)", R"(c:\bar)"},
+ {R"(\)", R"(\)"},
+ // {R"(\\)", R"(\\)"},
+ // {R"(\\net)", R"(\\net)"},
+ {R"(c:\..)", R"(c:\)"},
+ {R"(c:\.)", R"(c:\)"},
+ {R"(\..)", R"(\)"},
+ // {R"(c:..)", R"(c:..)"},
+ {R"(..)", R"(..)"},
+ {R"(.)", R"(.)"},
+ {R"(c:..\..)", R"(c:..\..)"},
+ {R"(..\..)", R"(..\..)"},
+ {R"(foo\..)", R"(.)"},
+ {R"(foo\..\bar)", R"(bar)"},
+ {R"(..\foo\..)", R"(..)"},
+ {R"(.\foo)", R"(foo)"},
+ };
+ for (auto test : windows_tests) {
+ EXPECT_EQ(test.second,
+ FileSpec(test.first, false, FileSpec::ePathSyntaxWindows)
+ .GetNormalizedPath()
+ .GetPath())
+ << "Original path: " << test.first;
+ }
+}
+
+TEST(FileSpecTest, FormatFileSpec) {
+ auto win = FileSpec::ePathSyntaxWindows;
+
+ FileSpec F;
+ EXPECT_EQ("(empty)", llvm::formatv("{0}", F).str());
+ EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
+ EXPECT_EQ("(empty)", llvm::formatv("{0:F}", F).str());
+
+ F = FileSpec("C:\\foo\\bar.txt", false, win);
+ EXPECT_EQ("C:\\foo\\bar.txt", llvm::formatv("{0}", F).str());
+ EXPECT_EQ("C:\\foo\\", llvm::formatv("{0:D}", F).str());
+ EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
+
+ F = FileSpec("foo\\bar.txt", false, win);
+ EXPECT_EQ("foo\\bar.txt", llvm::formatv("{0}", F).str());
+ EXPECT_EQ("foo\\", llvm::formatv("{0:D}", F).str());
+ EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
+
+ F = FileSpec("foo", false, win);
+ EXPECT_EQ("foo", llvm::formatv("{0}", F).str());
+ EXPECT_EQ("foo", llvm::formatv("{0:F}", F).str());
+ EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
+} \ No newline at end of file
diff --git a/unittests/Host/FileSystemTest.cpp b/unittests/Host/FileSystemTest.cpp
new file mode 100644
index 000000000000..d5160b1a0da1
--- /dev/null
+++ b/unittests/Host/FileSystemTest.cpp
@@ -0,0 +1,32 @@
+//===-- FileSystemTest.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Host/FileSystem.h"
+
+extern const char *TestMainArgv0;
+
+using namespace lldb_private;
+
+TEST(FileSystemTest, FileAndDirectoryComponents) {
+ using namespace std::chrono;
+
+ const bool resolve = true;
+#ifdef _WIN32
+ FileSpec fs1("C:\\FILE\\THAT\\DOES\\NOT\\EXIST.TXT", !resolve);
+#else
+ FileSpec fs1("/file/that/does/not/exist.txt", !resolve);
+#endif
+ FileSpec fs2(TestMainArgv0, resolve);
+
+ EXPECT_EQ(system_clock::time_point(), FileSystem::GetModificationTime(fs1));
+ EXPECT_LT(system_clock::time_point() + hours(24 * 365 * 20),
+ FileSystem::GetModificationTime(fs2));
+}
diff --git a/unittests/Host/SocketAddressTest.cpp b/unittests/Host/SocketAddressTest.cpp
index 6b27e04ce702..3c18137ac063 100644
--- a/unittests/Host/SocketAddressTest.cpp
+++ b/unittests/Host/SocketAddressTest.cpp
@@ -7,68 +7,64 @@
//
//===----------------------------------------------------------------------===//
-
#include "gtest/gtest.h"
#include "lldb/Host/SocketAddress.h"
-namespace
-{
- class SocketAddressTest: public ::testing::Test
- {
- };
+namespace {
+class SocketAddressTest : public ::testing::Test {};
}
using namespace lldb_private;
-TEST_F (SocketAddressTest, Set)
-{
- SocketAddress sa;
- ASSERT_TRUE (sa.SetToLocalhost (AF_INET, 1138));
- ASSERT_STREQ ("127.0.0.1", sa.GetIPAddress ().c_str ());
- ASSERT_EQ (1138, sa.GetPort ());
+TEST_F(SocketAddressTest, Set) {
+ SocketAddress sa;
+ ASSERT_TRUE(sa.SetToLocalhost(AF_INET, 1138));
+ ASSERT_STREQ("127.0.0.1", sa.GetIPAddress().c_str());
+ ASSERT_EQ(1138, sa.GetPort());
- ASSERT_TRUE (sa.SetToAnyAddress (AF_INET, 0));
- ASSERT_STREQ ("0.0.0.0", sa.GetIPAddress ().c_str ());
- ASSERT_EQ (0, sa.GetPort ());
+ ASSERT_TRUE(sa.SetToAnyAddress(AF_INET, 0));
+ ASSERT_STREQ("0.0.0.0", sa.GetIPAddress().c_str());
+ ASSERT_EQ(0, sa.GetPort());
- ASSERT_TRUE (sa.SetToLocalhost (AF_INET6, 1139));
- ASSERT_TRUE(sa.GetIPAddress() == "::1" || sa.GetIPAddress() == "0:0:0:0:0:0:0:1") << "Address was: "
- << sa.GetIPAddress();
- ASSERT_EQ (1139, sa.GetPort ());
+ ASSERT_TRUE(sa.SetToLocalhost(AF_INET6, 1139));
+ ASSERT_TRUE(sa.GetIPAddress() == "::1" ||
+ sa.GetIPAddress() == "0:0:0:0:0:0:0:1")
+ << "Address was: " << sa.GetIPAddress();
+ ASSERT_EQ(1139, sa.GetPort());
}
#ifdef _WIN32
// we need to test our inet_ntop implementation for Windows XP
-const char* inet_ntop (int af, const void * src,
- char * dst, socklen_t size);
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
-TEST_F (SocketAddressTest, inet_ntop)
-{
- const uint8_t address4[4] = {255, 0, 1, 100};
- const uint8_t address6[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 255, 0};
-
- char buffer[INET6_ADDRSTRLEN];
- memset (buffer, 'x', sizeof (buffer));
- EXPECT_STREQ ("1:203:405:607:809:a0b:c0d:ff00", inet_ntop (AF_INET6, address6, buffer, sizeof (buffer)));
- memset (buffer, 'x', sizeof (buffer));
- EXPECT_STREQ ("1:203:405:607:809:a0b:c0d:ff00", inet_ntop (AF_INET6, address6, buffer, 31));
- memset (buffer, 'x', sizeof (buffer));
- EXPECT_STREQ (nullptr, inet_ntop (AF_INET6, address6, buffer, 0));
- memset (buffer, 'x', sizeof (buffer));
- EXPECT_STREQ (nullptr, inet_ntop (AF_INET6, address6, buffer, 30));
-
- memset (buffer, 'x', sizeof (buffer));
- EXPECT_STREQ ("255.0.1.100", inet_ntop (AF_INET, address4, buffer, sizeof (buffer)));
- memset (buffer, 'x', sizeof (buffer));
- EXPECT_STREQ ("255.0.1.100", inet_ntop (AF_INET, address4, buffer, 12));
- memset (buffer, 'x', sizeof (buffer));
- EXPECT_STREQ (nullptr, inet_ntop (AF_INET, address4, buffer, 0));
- memset (buffer, 'x', sizeof (buffer));
- EXPECT_STREQ (nullptr, inet_ntop (AF_INET, address4, buffer, 11));
-}
+TEST_F(SocketAddressTest, inet_ntop) {
+ const uint8_t address4[4] = {255, 0, 1, 100};
+ const uint8_t address6[16] = {0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 255, 0};
-#endif
+ char buffer[INET6_ADDRSTRLEN];
+ memset(buffer, 'x', sizeof(buffer));
+ EXPECT_STREQ("1:203:405:607:809:a0b:c0d:ff00",
+ inet_ntop(AF_INET6, address6, buffer, sizeof(buffer)));
+ memset(buffer, 'x', sizeof(buffer));
+ EXPECT_STREQ("1:203:405:607:809:a0b:c0d:ff00",
+ inet_ntop(AF_INET6, address6, buffer, 31));
+ memset(buffer, 'x', sizeof(buffer));
+ EXPECT_STREQ(nullptr, inet_ntop(AF_INET6, address6, buffer, 0));
+ memset(buffer, 'x', sizeof(buffer));
+ EXPECT_STREQ(nullptr, inet_ntop(AF_INET6, address6, buffer, 30));
+ memset(buffer, 'x', sizeof(buffer));
+ EXPECT_STREQ("255.0.1.100",
+ inet_ntop(AF_INET, address4, buffer, sizeof(buffer)));
+ memset(buffer, 'x', sizeof(buffer));
+ EXPECT_STREQ("255.0.1.100", inet_ntop(AF_INET, address4, buffer, 12));
+ memset(buffer, 'x', sizeof(buffer));
+ EXPECT_STREQ(nullptr, inet_ntop(AF_INET, address4, buffer, 0));
+ memset(buffer, 'x', sizeof(buffer));
+ EXPECT_STREQ(nullptr, inet_ntop(AF_INET, address4, buffer, 11));
+}
+#endif
diff --git a/unittests/Host/SocketTest.cpp b/unittests/Host/SocketTest.cpp
index e3e522744760..569a4404131e 100644
--- a/unittests/Host/SocketTest.cpp
+++ b/unittests/Host/SocketTest.cpp
@@ -8,7 +8,8 @@
//===----------------------------------------------------------------------===//
#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
-// Workaround for MSVC standard library bug, which fails to include <thread> when
+// Workaround for MSVC standard library bug, which fails to include <thread>
+// when
// exceptions are disabled.
#include <eh.h>
#endif
@@ -30,182 +31,189 @@
using namespace lldb_private;
-class SocketTest : public testing::Test
-{
- public:
- void
- SetUp() override
- {
+class SocketTest : public testing::Test {
+public:
+ void SetUp() override {
#if defined(_MSC_VER)
- WSADATA data;
- ::WSAStartup(MAKEWORD(2, 2), &data);
+ WSADATA data;
+ ::WSAStartup(MAKEWORD(2, 2), &data);
#endif
- }
+ }
- void
- TearDown() override
- {
+ void TearDown() override {
#if defined(_MSC_VER)
- ::WSACleanup();
+ ::WSACleanup();
#endif
- }
-
- protected:
- static void
- AcceptThread(Socket *listen_socket, const char *listen_remote_address, bool child_processes_inherit,
- Socket **accept_socket, Error *error)
- {
- *error = listen_socket->Accept(listen_remote_address, child_processes_inherit, *accept_socket);
- }
-
- template<typename SocketType>
- void
- CreateConnectedSockets(const char *listen_remote_address, const std::function<std::string(const SocketType&)> &get_connect_addr, std::unique_ptr<SocketType> *a_up, std::unique_ptr<SocketType> *b_up)
- {
- bool child_processes_inherit = false;
- Error error;
- std::unique_ptr<SocketType> listen_socket_up(new SocketType(child_processes_inherit, error));
- EXPECT_FALSE(error.Fail());
- error = listen_socket_up->Listen(listen_remote_address, 5);
- EXPECT_FALSE(error.Fail());
- EXPECT_TRUE(listen_socket_up->IsValid());
-
- Error accept_error;
- Socket *accept_socket;
- std::thread accept_thread(AcceptThread, listen_socket_up.get(), listen_remote_address, child_processes_inherit,
- &accept_socket, &accept_error);
-
- std::string connect_remote_address = get_connect_addr(*listen_socket_up);
- std::unique_ptr<SocketType> connect_socket_up(new SocketType(child_processes_inherit, error));
- EXPECT_FALSE(error.Fail());
- error = connect_socket_up->Connect(connect_remote_address.c_str());
- EXPECT_FALSE(error.Fail());
- EXPECT_TRUE(connect_socket_up->IsValid());
-
- a_up->swap(connect_socket_up);
- EXPECT_TRUE(error.Success());
- EXPECT_NE(nullptr, a_up->get());
- EXPECT_TRUE((*a_up)->IsValid());
-
- accept_thread.join();
- b_up->reset(static_cast<SocketType*>(accept_socket));
- EXPECT_TRUE(accept_error.Success());
- EXPECT_NE(nullptr, b_up->get());
- EXPECT_TRUE((*b_up)->IsValid());
-
- listen_socket_up.reset();
- }
-};
-
-TEST_F (SocketTest, DecodeHostAndPort)
-{
- std::string host_str;
- std::string port_str;
- int32_t port;
+ }
+
+protected:
+ static void AcceptThread(Socket *listen_socket,
+ const char *listen_remote_address,
+ bool child_processes_inherit, Socket **accept_socket,
+ Error *error) {
+ *error = listen_socket->Accept(listen_remote_address,
+ child_processes_inherit, *accept_socket);
+ }
+
+ template <typename SocketType>
+ void CreateConnectedSockets(
+ const char *listen_remote_address,
+ const std::function<std::string(const SocketType &)> &get_connect_addr,
+ std::unique_ptr<SocketType> *a_up, std::unique_ptr<SocketType> *b_up) {
+ bool child_processes_inherit = false;
Error error;
- EXPECT_TRUE (Socket::DecodeHostAndPort ("localhost:1138", host_str, port_str, port, &error));
- EXPECT_STREQ ("localhost", host_str.c_str ());
- EXPECT_STREQ ("1138", port_str.c_str ());
- EXPECT_EQ (1138, port);
- EXPECT_TRUE (error.Success ());
-
- EXPECT_FALSE (Socket::DecodeHostAndPort ("google.com:65536", host_str, port_str, port, &error));
- EXPECT_TRUE (error.Fail ());
- EXPECT_STREQ ("invalid host:port specification: 'google.com:65536'", error.AsCString ());
-
- EXPECT_FALSE (Socket::DecodeHostAndPort ("google.com:-1138", host_str, port_str, port, &error));
- EXPECT_TRUE (error.Fail ());
- EXPECT_STREQ ("invalid host:port specification: 'google.com:-1138'", error.AsCString ());
-
- EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:65536", host_str, port_str, port, &error));
- EXPECT_TRUE(error.Fail());
- EXPECT_STREQ("invalid host:port specification: 'google.com:65536'", error.AsCString());
-
- EXPECT_TRUE (Socket::DecodeHostAndPort ("12345", host_str, port_str, port, &error));
- EXPECT_STREQ ("", host_str.c_str ());
- EXPECT_STREQ ("12345", port_str.c_str ());
- EXPECT_EQ (12345, port);
- EXPECT_TRUE (error.Success ());
-
- EXPECT_TRUE (Socket::DecodeHostAndPort ("*:0", host_str, port_str, port, &error));
- EXPECT_STREQ ("*", host_str.c_str ());
- EXPECT_STREQ ("0", port_str.c_str ());
- EXPECT_EQ (0, port);
- EXPECT_TRUE (error.Success ());
-
- EXPECT_TRUE(Socket::DecodeHostAndPort("*:65535", host_str, port_str, port, &error));
- EXPECT_STREQ("*", host_str.c_str());
- EXPECT_STREQ("65535", port_str.c_str());
- EXPECT_EQ(65535, port);
+ std::unique_ptr<SocketType> listen_socket_up(
+ new SocketType(child_processes_inherit, error));
+ EXPECT_FALSE(error.Fail());
+ error = listen_socket_up->Listen(listen_remote_address, 5);
+ EXPECT_FALSE(error.Fail());
+ EXPECT_TRUE(listen_socket_up->IsValid());
+
+ Error accept_error;
+ Socket *accept_socket;
+ std::thread accept_thread(AcceptThread, listen_socket_up.get(),
+ listen_remote_address, child_processes_inherit,
+ &accept_socket, &accept_error);
+
+ std::string connect_remote_address = get_connect_addr(*listen_socket_up);
+ std::unique_ptr<SocketType> connect_socket_up(
+ new SocketType(child_processes_inherit, error));
+ EXPECT_FALSE(error.Fail());
+ error = connect_socket_up->Connect(connect_remote_address);
+ EXPECT_FALSE(error.Fail());
+ EXPECT_TRUE(connect_socket_up->IsValid());
+
+ a_up->swap(connect_socket_up);
EXPECT_TRUE(error.Success());
+ EXPECT_NE(nullptr, a_up->get());
+ EXPECT_TRUE((*a_up)->IsValid());
+
+ accept_thread.join();
+ b_up->reset(static_cast<SocketType *>(accept_socket));
+ EXPECT_TRUE(accept_error.Success());
+ EXPECT_NE(nullptr, b_up->get());
+ EXPECT_TRUE((*b_up)->IsValid());
+
+ listen_socket_up.reset();
+ }
+};
+
+TEST_F(SocketTest, DecodeHostAndPort) {
+ std::string host_str;
+ std::string port_str;
+ int32_t port;
+ Error error;
+ EXPECT_TRUE(Socket::DecodeHostAndPort("localhost:1138", host_str, port_str,
+ port, &error));
+ EXPECT_STREQ("localhost", host_str.c_str());
+ EXPECT_STREQ("1138", port_str.c_str());
+ EXPECT_EQ(1138, port);
+ EXPECT_TRUE(error.Success());
+
+ EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:65536", host_str, port_str,
+ port, &error));
+ EXPECT_TRUE(error.Fail());
+ EXPECT_STREQ("invalid host:port specification: 'google.com:65536'",
+ error.AsCString());
+
+ EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:-1138", host_str, port_str,
+ port, &error));
+ EXPECT_TRUE(error.Fail());
+ EXPECT_STREQ("invalid host:port specification: 'google.com:-1138'",
+ error.AsCString());
+
+ EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:65536", host_str, port_str,
+ port, &error));
+ EXPECT_TRUE(error.Fail());
+ EXPECT_STREQ("invalid host:port specification: 'google.com:65536'",
+ error.AsCString());
+
+ EXPECT_TRUE(
+ Socket::DecodeHostAndPort("12345", host_str, port_str, port, &error));
+ EXPECT_STREQ("", host_str.c_str());
+ EXPECT_STREQ("12345", port_str.c_str());
+ EXPECT_EQ(12345, port);
+ EXPECT_TRUE(error.Success());
+
+ EXPECT_TRUE(
+ Socket::DecodeHostAndPort("*:0", host_str, port_str, port, &error));
+ EXPECT_STREQ("*", host_str.c_str());
+ EXPECT_STREQ("0", port_str.c_str());
+ EXPECT_EQ(0, port);
+ EXPECT_TRUE(error.Success());
+
+ EXPECT_TRUE(
+ Socket::DecodeHostAndPort("*:65535", host_str, port_str, port, &error));
+ EXPECT_STREQ("*", host_str.c_str());
+ EXPECT_STREQ("65535", port_str.c_str());
+ EXPECT_EQ(65535, port);
+ EXPECT_TRUE(error.Success());
}
#ifndef LLDB_DISABLE_POSIX
-TEST_F (SocketTest, DomainListenConnectAccept)
-{
- char* file_name_str = tempnam(nullptr, nullptr);
- EXPECT_NE (nullptr, file_name_str);
- const std::string file_name(file_name_str);
- free(file_name_str);
-
- std::unique_ptr<DomainSocket> socket_a_up;
- std::unique_ptr<DomainSocket> socket_b_up;
- CreateConnectedSockets<DomainSocket>(file_name.c_str(),
- [=](const DomainSocket &)
- {
- return file_name;
- },
- &socket_a_up, &socket_b_up);
+TEST_F(SocketTest, DomainListenConnectAccept) {
+ char *file_name_str = tempnam(nullptr, nullptr);
+ EXPECT_NE(nullptr, file_name_str);
+ const std::string file_name(file_name_str);
+ free(file_name_str);
+
+ std::unique_ptr<DomainSocket> socket_a_up;
+ std::unique_ptr<DomainSocket> socket_b_up;
+ CreateConnectedSockets<DomainSocket>(
+ file_name.c_str(), [=](const DomainSocket &) { return file_name; },
+ &socket_a_up, &socket_b_up);
}
#endif
-TEST_F (SocketTest, TCPListen0ConnectAccept)
-{
- std::unique_ptr<TCPSocket> socket_a_up;
- std::unique_ptr<TCPSocket> socket_b_up;
- CreateConnectedSockets<TCPSocket>("127.0.0.1:0",
- [=](const TCPSocket &s)
- {
- char connect_remote_address[64];
- snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber());
- return std::string(connect_remote_address);
- },
- &socket_a_up, &socket_b_up);
+TEST_F(SocketTest, TCPListen0ConnectAccept) {
+ std::unique_ptr<TCPSocket> socket_a_up;
+ std::unique_ptr<TCPSocket> socket_b_up;
+ CreateConnectedSockets<TCPSocket>(
+ "127.0.0.1:0",
+ [=](const TCPSocket &s) {
+ char connect_remote_address[64];
+ snprintf(connect_remote_address, sizeof(connect_remote_address),
+ "localhost:%u", s.GetLocalPortNumber());
+ return std::string(connect_remote_address);
+ },
+ &socket_a_up, &socket_b_up);
}
-TEST_F (SocketTest, TCPGetAddress)
-{
- std::unique_ptr<TCPSocket> socket_a_up;
- std::unique_ptr<TCPSocket> socket_b_up;
- CreateConnectedSockets<TCPSocket>("127.0.0.1:0",
- [=](const TCPSocket &s)
- {
- char connect_remote_address[64];
- snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber());
- return std::string(connect_remote_address);
- },
- &socket_a_up,
- &socket_b_up);
-
- EXPECT_EQ (socket_a_up->GetLocalPortNumber (), socket_b_up->GetRemotePortNumber ());
- EXPECT_EQ (socket_b_up->GetLocalPortNumber (), socket_a_up->GetRemotePortNumber ());
- EXPECT_NE (socket_a_up->GetLocalPortNumber (), socket_b_up->GetLocalPortNumber ());
- EXPECT_STREQ ("127.0.0.1", socket_a_up->GetRemoteIPAddress ().c_str ());
- EXPECT_STREQ ("127.0.0.1", socket_b_up->GetRemoteIPAddress ().c_str ());
+TEST_F(SocketTest, TCPGetAddress) {
+ std::unique_ptr<TCPSocket> socket_a_up;
+ std::unique_ptr<TCPSocket> socket_b_up;
+ CreateConnectedSockets<TCPSocket>(
+ "127.0.0.1:0",
+ [=](const TCPSocket &s) {
+ char connect_remote_address[64];
+ snprintf(connect_remote_address, sizeof(connect_remote_address),
+ "localhost:%u", s.GetLocalPortNumber());
+ return std::string(connect_remote_address);
+ },
+ &socket_a_up, &socket_b_up);
+
+ EXPECT_EQ(socket_a_up->GetLocalPortNumber(),
+ socket_b_up->GetRemotePortNumber());
+ EXPECT_EQ(socket_b_up->GetLocalPortNumber(),
+ socket_a_up->GetRemotePortNumber());
+ EXPECT_NE(socket_a_up->GetLocalPortNumber(),
+ socket_b_up->GetLocalPortNumber());
+ EXPECT_STREQ("127.0.0.1", socket_a_up->GetRemoteIPAddress().c_str());
+ EXPECT_STREQ("127.0.0.1", socket_b_up->GetRemoteIPAddress().c_str());
}
-TEST_F (SocketTest, UDPConnect)
-{
- Socket* socket_a;
- Socket* socket_b;
+TEST_F(SocketTest, UDPConnect) {
+ Socket *socket_a;
+ Socket *socket_b;
+
+ bool child_processes_inherit = false;
+ auto error = UDPSocket::Connect("127.0.0.1:0", child_processes_inherit,
+ socket_a, socket_b);
- bool child_processes_inherit = false;
- auto error = UDPSocket::Connect("127.0.0.1:0", child_processes_inherit, socket_a, socket_b);
-
- std::unique_ptr<Socket> a_up(socket_a);
- std::unique_ptr<Socket> b_up(socket_b);
+ std::unique_ptr<Socket> a_up(socket_a);
+ std::unique_ptr<Socket> b_up(socket_b);
- EXPECT_TRUE(error.Success ());
- EXPECT_TRUE(a_up->IsValid());
- EXPECT_TRUE(b_up->IsValid());
+ EXPECT_TRUE(error.Success());
+ EXPECT_TRUE(a_up->IsValid());
+ EXPECT_TRUE(b_up->IsValid());
}
diff --git a/unittests/Host/SymbolsTest.cpp b/unittests/Host/SymbolsTest.cpp
index cb59b2c56539..d3073310e3e7 100644
--- a/unittests/Host/SymbolsTest.cpp
+++ b/unittests/Host/SymbolsTest.cpp
@@ -8,23 +8,25 @@
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
+
#include "lldb/Host/Symbols.h"
#include "lldb/Core/ModuleSpec.h"
using namespace lldb_private;
-TEST(SymbolsTest, LocateExecutableSymbolFileForUnknownExecutableAndUnknownSymbolFile)
-{
- ModuleSpec module_spec;
- FileSpec symbol_file_spec = Symbols::LocateExecutableSymbolFile(module_spec);
- EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty());
+TEST(SymbolsTest,
+ LocateExecutableSymbolFileForUnknownExecutableAndUnknownSymbolFile) {
+ ModuleSpec module_spec;
+ FileSpec symbol_file_spec = Symbols::LocateExecutableSymbolFile(module_spec);
+ EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty());
}
-TEST(SymbolsTest, LocateExecutableSymbolFileForUnknownExecutableAndMissingSymbolFile)
-{
- ModuleSpec module_spec;
- // using a GUID here because the symbol file shouldn't actually exist on disk
- module_spec.GetSymbolFileSpec().SetFile("4A524676-B24B-4F4E-968A-551D465EBAF1.so", false);
- FileSpec symbol_file_spec = Symbols::LocateExecutableSymbolFile(module_spec);
- EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty());
+TEST(SymbolsTest,
+ LocateExecutableSymbolFileForUnknownExecutableAndMissingSymbolFile) {
+ ModuleSpec module_spec;
+ // using a GUID here because the symbol file shouldn't actually exist on disk
+ module_spec.GetSymbolFileSpec().SetFile(
+ "4A524676-B24B-4F4E-968A-551D465EBAF1.so", false);
+ FileSpec symbol_file_spec = Symbols::LocateExecutableSymbolFile(module_spec);
+ EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty());
}
diff --git a/unittests/Interpreter/TestArgs.cpp b/unittests/Interpreter/TestArgs.cpp
index e2cf1c4d4a0a..9dcf09d54aea 100644
--- a/unittests/Interpreter/TestArgs.cpp
+++ b/unittests/Interpreter/TestArgs.cpp
@@ -11,60 +11,333 @@
#include "lldb/Interpreter/Args.h"
+#include <limits>
+#include <sstream>
+
using namespace lldb_private;
-TEST(ArgsTest, TestSingleArg)
-{
- Args args;
- args.SetCommandString("arg");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg");
-}
-
-TEST(ArgsTest, TestSingleQuotedArgWithSpace)
-{
- Args args;
- args.SetCommandString("\"arg with space\"");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg with space");
-}
-
-TEST(ArgsTest, TestSingleArgWithQuotedSpace)
-{
- Args args;
- args.SetCommandString("arg\\ with\\ space");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg with space");
-}
-
-TEST(ArgsTest, TestMultipleArgs)
-{
- Args args;
- args.SetCommandString("this has multiple args");
- EXPECT_EQ(4u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "this");
- EXPECT_STREQ(args.GetArgumentAtIndex(1), "has");
- EXPECT_STREQ(args.GetArgumentAtIndex(2), "multiple");
- EXPECT_STREQ(args.GetArgumentAtIndex(3), "args");
-}
-
-TEST(ArgsTest, TestOverwriteArgs)
-{
- Args args;
- args.SetCommandString("this has multiple args");
- EXPECT_EQ(4u, args.GetArgumentCount());
- args.SetCommandString("arg");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg");
-}
-
-TEST(ArgsTest, TestAppendArg)
-{
- Args args;
- args.SetCommandString("first_arg");
- EXPECT_EQ(1u, args.GetArgumentCount());
- args.AppendArgument("second_arg");
- EXPECT_EQ(2u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "first_arg");
- EXPECT_STREQ(args.GetArgumentAtIndex(1), "second_arg");
+TEST(ArgsTest, TestSingleArg) {
+ Args args;
+ args.SetCommandString("arg");
+ EXPECT_EQ(1u, args.GetArgumentCount());
+ EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg");
+}
+
+TEST(ArgsTest, TestSingleQuotedArgWithSpace) {
+ Args args;
+ args.SetCommandString("\"arg with space\"");
+ EXPECT_EQ(1u, args.GetArgumentCount());
+ EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg with space");
+}
+
+TEST(ArgsTest, TestSingleArgWithQuotedSpace) {
+ Args args;
+ args.SetCommandString("arg\\ with\\ space");
+ EXPECT_EQ(1u, args.GetArgumentCount());
+ EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg with space");
+}
+
+TEST(ArgsTest, TestMultipleArgs) {
+ Args args;
+ args.SetCommandString("this has multiple args");
+ EXPECT_EQ(4u, args.GetArgumentCount());
+ EXPECT_STREQ(args.GetArgumentAtIndex(0), "this");
+ EXPECT_STREQ(args.GetArgumentAtIndex(1), "has");
+ EXPECT_STREQ(args.GetArgumentAtIndex(2), "multiple");
+ EXPECT_STREQ(args.GetArgumentAtIndex(3), "args");
+}
+
+TEST(ArgsTest, TestOverwriteArgs) {
+ Args args;
+ args.SetCommandString("this has multiple args");
+ EXPECT_EQ(4u, args.GetArgumentCount());
+ args.SetCommandString("arg");
+ EXPECT_EQ(1u, args.GetArgumentCount());
+ EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg");
+}
+
+TEST(ArgsTest, TestAppendArg) {
+ Args args;
+ args.SetCommandString("first_arg");
+ EXPECT_EQ(1u, args.GetArgumentCount());
+ args.AppendArgument(llvm::StringRef("second_arg"));
+ EXPECT_EQ(2u, args.GetArgumentCount());
+ EXPECT_STREQ(args.GetArgumentAtIndex(0), "first_arg");
+ EXPECT_STREQ(args.GetArgumentAtIndex(1), "second_arg");
+}
+
+TEST(ArgsTest, TestInsertArg) {
+ Args args;
+ args.AppendArgument("1");
+ args.AppendArgument("2");
+ args.AppendArgument("3");
+ args.InsertArgumentAtIndex(1, "1.5");
+ args.InsertArgumentAtIndex(4, "3.5");
+
+ ASSERT_EQ(5u, args.GetArgumentCount());
+ EXPECT_STREQ("1", args.GetArgumentAtIndex(0));
+ EXPECT_STREQ("1.5", args.GetArgumentAtIndex(1));
+ EXPECT_STREQ("2", args.GetArgumentAtIndex(2));
+ EXPECT_STREQ("3", args.GetArgumentAtIndex(3));
+ EXPECT_STREQ("3.5", args.GetArgumentAtIndex(4));
+}
+
+TEST(ArgsTest, TestArgv) {
+ Args args;
+ EXPECT_EQ(nullptr, args.GetArgumentVector());
+
+ args.AppendArgument("1");
+ EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
+ EXPECT_EQ(nullptr, args.GetArgumentVector()[1]);
+
+ args.AppendArgument("2");
+ EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[1]);
+ EXPECT_EQ(nullptr, args.GetArgumentVector()[2]);
+
+ args.AppendArgument("3");
+ EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[1]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[2]);
+ EXPECT_EQ(nullptr, args.GetArgumentVector()[3]);
+
+ args.InsertArgumentAtIndex(1, "1.5");
+ EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[1]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[2]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[3]);
+ EXPECT_EQ(nullptr, args.GetArgumentVector()[4]);
+
+ args.InsertArgumentAtIndex(4, "3.5");
+ EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[1]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[2]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[3]);
+ EXPECT_NE(nullptr, args.GetArgumentVector()[4]);
+ EXPECT_EQ(nullptr, args.GetArgumentVector()[5]);
+}
+
+TEST(ArgsTest, GetQuotedCommandString) {
+ Args args;
+ const char *str = "process launch -o stdout.txt -- \"a b c\"";
+ args.SetCommandString(str);
+
+ std::string stdstr;
+ ASSERT_TRUE(args.GetQuotedCommandString(stdstr));
+ EXPECT_EQ(str, stdstr);
+}
+
+TEST(ArgsTest, BareSingleQuote) {
+ Args args;
+ args.SetCommandString("a\\'b");
+ EXPECT_EQ(1u, args.GetArgumentCount());
+
+ EXPECT_STREQ("a'b", args.GetArgumentAtIndex(0));
+}
+
+TEST(ArgsTest, DoubleQuotedItem) {
+ Args args;
+ args.SetCommandString("\"a b c\"");
+ EXPECT_EQ(1u, args.GetArgumentCount());
+
+ EXPECT_STREQ("a b c", args.GetArgumentAtIndex(0));
+}
+
+TEST(ArgsTest, AppendArguments) {
+ Args args;
+ const char *argv[] = {"1", "2", nullptr};
+ const char *argv2[] = {"3", "4", nullptr};
+
+ args.AppendArguments(argv);
+ ASSERT_EQ(2u, args.GetArgumentCount());
+ EXPECT_STREQ("1", args.GetArgumentVector()[0]);
+ EXPECT_STREQ("2", args.GetArgumentVector()[1]);
+ EXPECT_EQ(nullptr, args.GetArgumentVector()[2]);
+ EXPECT_STREQ("1", args.GetArgumentAtIndex(0));
+ EXPECT_STREQ("2", args.GetArgumentAtIndex(1));
+
+ args.AppendArguments(argv2);
+ ASSERT_EQ(4u, args.GetArgumentCount());
+ EXPECT_STREQ("1", args.GetArgumentVector()[0]);
+ EXPECT_STREQ("2", args.GetArgumentVector()[1]);
+ EXPECT_STREQ("3", args.GetArgumentVector()[2]);
+ EXPECT_STREQ("4", args.GetArgumentVector()[3]);
+ EXPECT_EQ(nullptr, args.GetArgumentVector()[4]);
+ EXPECT_STREQ("1", args.GetArgumentAtIndex(0));
+ EXPECT_STREQ("2", args.GetArgumentAtIndex(1));
+ EXPECT_STREQ("3", args.GetArgumentAtIndex(2));
+ EXPECT_STREQ("4", args.GetArgumentAtIndex(3));
+}
+
+TEST(ArgsTest, StringToBoolean) {
+ bool success = false;
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("true"), false, nullptr));
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("on"), false, nullptr));
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("yes"), false, nullptr));
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("1"), false, nullptr));
+
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("true"), false, &success));
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("on"), false, &success));
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("yes"), false, &success));
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("1"), false, &success));
+ EXPECT_TRUE(success);
+
+ EXPECT_FALSE(Args::StringToBoolean(llvm::StringRef("false"), true, nullptr));
+ EXPECT_FALSE(Args::StringToBoolean(llvm::StringRef("off"), true, nullptr));
+ EXPECT_FALSE(Args::StringToBoolean(llvm::StringRef("no"), true, nullptr));
+ EXPECT_FALSE(Args::StringToBoolean(llvm::StringRef("0"), true, nullptr));
+
+ EXPECT_FALSE(Args::StringToBoolean(llvm::StringRef("false"), true, &success));
+ EXPECT_TRUE(success);
+ EXPECT_FALSE(Args::StringToBoolean(llvm::StringRef("off"), true, &success));
+ EXPECT_TRUE(success);
+ EXPECT_FALSE(Args::StringToBoolean(llvm::StringRef("no"), true, &success));
+ EXPECT_TRUE(success);
+ EXPECT_FALSE(Args::StringToBoolean(llvm::StringRef("0"), true, &success));
+ EXPECT_TRUE(success);
+
+ EXPECT_FALSE(Args::StringToBoolean(llvm::StringRef("10"), false, &success));
+ EXPECT_FALSE(success);
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("10"), true, &success));
+ EXPECT_FALSE(success);
+ EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef(""), true, &success));
+ EXPECT_FALSE(success);
+}
+
+TEST(ArgsTest, StringToChar) {
+ bool success = false;
+
+ EXPECT_EQ('A', Args::StringToChar("A", 'B', nullptr));
+ EXPECT_EQ('B', Args::StringToChar("B", 'A', nullptr));
+
+ EXPECT_EQ('A', Args::StringToChar("A", 'B', &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ('B', Args::StringToChar("B", 'A', &success));
+ EXPECT_TRUE(success);
+
+ EXPECT_EQ('A', Args::StringToChar("", 'A', &success));
+ EXPECT_FALSE(success);
+ EXPECT_EQ('A', Args::StringToChar("ABC", 'A', &success));
+ EXPECT_FALSE(success);
+}
+
+TEST(ArgsTest, StringToScriptLanguage) {
+ bool success = false;
+
+ EXPECT_EQ(lldb::eScriptLanguageDefault,
+ Args::StringToScriptLanguage(llvm::StringRef("default"),
+ lldb::eScriptLanguageNone, nullptr));
+ EXPECT_EQ(lldb::eScriptLanguagePython,
+ Args::StringToScriptLanguage(llvm::StringRef("python"),
+ lldb::eScriptLanguageNone, nullptr));
+ EXPECT_EQ(lldb::eScriptLanguageNone,
+ Args::StringToScriptLanguage(llvm::StringRef("none"),
+ lldb::eScriptLanguagePython, nullptr));
+
+ EXPECT_EQ(lldb::eScriptLanguageDefault,
+ Args::StringToScriptLanguage(llvm::StringRef("default"),
+ lldb::eScriptLanguageNone, &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(lldb::eScriptLanguagePython,
+ Args::StringToScriptLanguage(llvm::StringRef("python"),
+ lldb::eScriptLanguageNone, &success));
+ EXPECT_TRUE(success);
+ EXPECT_EQ(lldb::eScriptLanguageNone,
+ Args::StringToScriptLanguage(llvm::StringRef("none"),
+ lldb::eScriptLanguagePython,
+ &success));
+ EXPECT_TRUE(success);
+
+ EXPECT_EQ(lldb::eScriptLanguagePython,
+ Args::StringToScriptLanguage(llvm::StringRef("invalid"),
+ lldb::eScriptLanguagePython,
+ &success));
+ EXPECT_FALSE(success);
+}
+
+TEST(ArgsTest, StringToVersion) {}
+
+// Environment Variable Tests
+
+class EnvVarFixture: public ::testing::Test {
+protected:
+
+ void SetUp() {
+ args.AppendArgument(llvm::StringRef("Arg1=foo"));
+ args.AppendArgument(llvm::StringRef("Arg2"));
+ args.AppendArgument(llvm::StringRef("Arg3=bar"));
+ }
+
+ size_t GetIndexForEnvVar(llvm::StringRef envvar_name) {
+ size_t argument_index = std::numeric_limits<size_t>::max();
+ EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name,
+ &argument_index));
+ EXPECT_LT(argument_index, args.GetArgumentCount());
+ return argument_index;
+ }
+
+ Args args;
+};
+
+
+TEST_F(EnvVarFixture, TestContainsEnvironmentVariableNoValue) {
+ EXPECT_TRUE(args.ContainsEnvironmentVariable(llvm::StringRef("Arg2")));
+}
+
+TEST_F(EnvVarFixture, TestContainsEnvironmentVariableWithValue) {
+ EXPECT_TRUE(args.ContainsEnvironmentVariable(llvm::StringRef("Arg3")));
+}
+
+TEST_F(EnvVarFixture, TestContainsEnvironmentVariableNonExistentVariable) {
+ auto nonexistent_envvar = llvm::StringRef("ThisEnvVarShouldNotExist");
+ EXPECT_FALSE(args.ContainsEnvironmentVariable(nonexistent_envvar));
+}
+
+TEST_F(EnvVarFixture, TestReplaceEnvironmentVariableInitialNoValueWithNoValue) {
+ auto envvar_name = llvm::StringRef("Arg2");
+ auto argument_index = GetIndexForEnvVar(envvar_name);
+
+ args.AddOrReplaceEnvironmentVariable(envvar_name, llvm::StringRef(""));
+ EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name));
+ EXPECT_EQ(envvar_name, args.GetArgumentAtIndex(argument_index));
+}
+
+TEST_F(EnvVarFixture, TestReplaceEnvironmentVariableInitialNoValueWithValue) {
+ auto envvar_name = llvm::StringRef("Arg2");
+ auto argument_index = GetIndexForEnvVar(envvar_name);
+
+ auto new_value = llvm::StringRef("NewValue");
+ args.AddOrReplaceEnvironmentVariable(envvar_name, new_value);
+ EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name));
+
+ std::stringstream stream;
+ stream << envvar_name.str() << '=' << new_value.str();
+ EXPECT_EQ(llvm::StringRef(stream.str()),
+ args.GetArgumentAtIndex(argument_index));
+}
+
+TEST_F(EnvVarFixture, TestReplaceEnvironmentVariableInitialValueWithNoValue) {
+ auto envvar_name = llvm::StringRef("Arg1");
+ auto argument_index = GetIndexForEnvVar(envvar_name);
+
+ args.AddOrReplaceEnvironmentVariable(envvar_name, llvm::StringRef(""));
+ EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name));
+ EXPECT_EQ(envvar_name, args.GetArgumentAtIndex(argument_index));
+}
+
+TEST_F(EnvVarFixture, TestReplaceEnvironmentVariableInitialValueWithValue) {
+ auto envvar_name = llvm::StringRef("Arg1");
+ auto argument_index = GetIndexForEnvVar(envvar_name);
+
+ auto new_value = llvm::StringRef("NewValue");
+ args.AddOrReplaceEnvironmentVariable(envvar_name, new_value);
+ EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name));
+
+ std::stringstream stream;
+ stream << envvar_name.str() << '=' << new_value.str();
+ EXPECT_EQ(llvm::StringRef(stream.str()),
+ args.GetArgumentAtIndex(argument_index));
}
diff --git a/unittests/Language/CMakeLists.txt b/unittests/Language/CMakeLists.txt
new file mode 100644
index 000000000000..d5e17c1f2a19
--- /dev/null
+++ b/unittests/Language/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(CPlusPlus)
diff --git a/unittests/Language/CPlusPlus/CMakeLists.txt b/unittests/Language/CPlusPlus/CMakeLists.txt
new file mode 100644
index 000000000000..6cad97cc6d3c
--- /dev/null
+++ b/unittests/Language/CPlusPlus/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_unittest(LanguageCPlusPlusTests
+ CPlusPlusLanguageTest.cpp
+ )
diff --git a/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
new file mode 100644
index 000000000000..26de31d52a33
--- /dev/null
+++ b/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
@@ -0,0 +1,40 @@
+//===-- CPlusPlusLanguageTest.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+
+using namespace lldb_private;
+
+TEST(CPlusPlusLanguage, MethodName) {
+ struct TestCase {
+ std::string input;
+ std::string context, basename, arguments, qualifiers, scope_qualified_name;
+ };
+
+ TestCase test_cases[] = {
+ {"foo::bar(baz)", "foo", "bar", "(baz)", "", "foo::bar"},
+ {"std::basic_ostream<char, std::char_traits<char> >& "
+ "std::operator<<<std::char_traits<char> >"
+ "(std::basic_ostream<char, std::char_traits<char> >&, char const*)",
+ "std", "operator<<<std::char_traits<char> >",
+ "(std::basic_ostream<char, std::char_traits<char> >&, char const*)", "",
+ "std::operator<<<std::char_traits<char> >"}};
+
+ for (const auto &test : test_cases) {
+ CPlusPlusLanguage::MethodName method(ConstString(test.input));
+ EXPECT_TRUE(method.IsValid());
+ EXPECT_EQ(test.context, method.GetContext());
+ EXPECT_EQ(test.basename, method.GetBasename());
+ EXPECT_EQ(test.arguments, method.GetArguments());
+ EXPECT_EQ(test.qualifiers, method.GetQualifiers());
+ EXPECT_EQ(test.scope_qualified_name, method.GetScopeQualifiedName());
+ }
+}
diff --git a/unittests/Platform/CMakeLists.txt b/unittests/Platform/CMakeLists.txt
new file mode 100644
index 000000000000..af1121dac7b6
--- /dev/null
+++ b/unittests/Platform/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_unittest(LLDBPlatformTests
+ PlatformDarwinTest.cpp
+ )
diff --git a/unittests/Platform/PlatformDarwinTest.cpp b/unittests/Platform/PlatformDarwinTest.cpp
new file mode 100644
index 000000000000..a16e2d99ede6
--- /dev/null
+++ b/unittests/Platform/PlatformDarwinTest.cpp
@@ -0,0 +1,56 @@
+//===-- PlatformDarwinTest.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "Plugins/Platform/MacOSX/PlatformDarwin.h"
+
+#include "llvm/ADT/StringRef.h"
+
+#include <tuple>
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(PlatformDarwinTest, TestParseVersionBuildDir) {
+ uint32_t A, B, C;
+ llvm::StringRef D;
+
+ std::tie(A, B, C, D) = PlatformDarwin::ParseVersionBuildDir("1.2.3 (test1)");
+ EXPECT_EQ(1u, A);
+ EXPECT_EQ(2u, B);
+ EXPECT_EQ(3u, C);
+ EXPECT_EQ("test1", D);
+
+ std::tie(A, B, C, D) = PlatformDarwin::ParseVersionBuildDir("2.3 (test2)");
+ EXPECT_EQ(2u, A);
+ EXPECT_EQ(3u, B);
+ EXPECT_EQ("test2", D);
+
+ std::tie(A, B, C, D) = PlatformDarwin::ParseVersionBuildDir("3 (test3)");
+ EXPECT_EQ(3u, A);
+ EXPECT_EQ("test3", D);
+
+ std::tie(A, B, C, D) = PlatformDarwin::ParseVersionBuildDir("1.2.3 (test");
+ EXPECT_EQ(1u, A);
+ EXPECT_EQ(2u, B);
+ EXPECT_EQ(3u, C);
+ EXPECT_EQ("test", D);
+
+ std::tie(A, B, C, D) = PlatformDarwin::ParseVersionBuildDir("2.3.4 test");
+ EXPECT_EQ(2u, A);
+ EXPECT_EQ(3u, B);
+ EXPECT_EQ(4u, C);
+ EXPECT_EQ("", D);
+
+ std::tie(A, B, C, D) = PlatformDarwin::ParseVersionBuildDir("3.4.5");
+ EXPECT_EQ(3u, A);
+ EXPECT_EQ(4u, B);
+ EXPECT_EQ(5u, C);
+}
diff --git a/unittests/Process/CMakeLists.txt b/unittests/Process/CMakeLists.txt
new file mode 100644
index 000000000000..70f59382afa1
--- /dev/null
+++ b/unittests/Process/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(gdb-remote)
+add_subdirectory(minidump)
diff --git a/unittests/Process/gdb-remote/CMakeLists.txt b/unittests/Process/gdb-remote/CMakeLists.txt
new file mode 100644
index 000000000000..de4cac11b233
--- /dev/null
+++ b/unittests/Process/gdb-remote/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_lldb_unittest(ProcessGdbRemoteTests
+ GDBRemoteClientBaseTest.cpp
+ GDBRemoteCommunicationClientTest.cpp
+ GDBRemoteTestUtils.cpp
+ )
diff --git a/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp b/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
new file mode 100644
index 000000000000..2cfd52f5767a
--- /dev/null
+++ b/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
@@ -0,0 +1,378 @@
+//===-- GDBRemoteClientBaseTest.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread>
+// when
+// exceptions are disabled.
+#include <eh.h>
+#endif
+#include <future>
+
+#include "GDBRemoteTestUtils.h"
+
+#include "Plugins/Process/Utility/LinuxSignals.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
+#include "lldb/Core/StreamGDBRemote.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private;
+using namespace lldb;
+typedef GDBRemoteCommunication::PacketResult PacketResult;
+
+namespace {
+
+struct MockDelegate : public GDBRemoteClientBase::ContinueDelegate {
+ std::string output;
+ std::string misc_data;
+ unsigned stop_reply_called = 0;
+ std::vector<std::string> structured_data_packets;
+
+ void HandleAsyncStdout(llvm::StringRef out) { output += out; }
+ void HandleAsyncMisc(llvm::StringRef data) { misc_data += data; }
+ void HandleStopReply() { ++stop_reply_called; }
+
+ void HandleAsyncStructuredDataPacket(llvm::StringRef data) {
+ structured_data_packets.push_back(data);
+ }
+};
+
+struct TestClient : public GDBRemoteClientBase {
+ TestClient() : GDBRemoteClientBase("test.client", "test.client.listener") {
+ m_send_acks = false;
+ }
+};
+
+struct ContinueFixture {
+ MockDelegate delegate;
+ TestClient client;
+ MockServer server;
+ ListenerSP listener_sp;
+
+ ContinueFixture();
+
+ StateType SendCPacket(StringExtractorGDBRemote &response) {
+ return client.SendContinuePacketAndWaitForResponse(delegate, LinuxSignals(),
+ "c", response);
+ }
+
+ void WaitForRunEvent() {
+ EventSP event_sp;
+ listener_sp->GetEventForBroadcasterWithType(
+ &client, TestClient::eBroadcastBitRunPacketSent, event_sp, llvm::None);
+ }
+};
+
+ContinueFixture::ContinueFixture()
+ : listener_sp(Listener::MakeListener("listener")) {
+ Connect(client, server);
+ listener_sp->StartListeningForEvents(&client,
+ TestClient::eBroadcastBitRunPacketSent);
+}
+
+} // end anonymous namespace
+
+class GDBRemoteClientBaseTest : public GDBRemoteTest {};
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) {
+ StringExtractorGDBRemote response;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // Continue. The inferior will stop with a signal.
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
+ ASSERT_EQ("T01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+
+ // Continue. The inferior will exit.
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("W01"));
+ ASSERT_EQ(eStateExited, fix.SendCPacket(response));
+ ASSERT_EQ("W01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+
+ // Continue. The inferior will get killed.
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("X01"));
+ ASSERT_EQ(eStateExited, fix.SendCPacket(response));
+ ASSERT_EQ("X01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) {
+ StringExtractorGDBRemote continue_response, response;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // SendAsyncSignal should do nothing when we are not running.
+ ASSERT_FALSE(fix.client.SendAsyncSignal(0x47));
+
+ // Continue. After the run packet is sent, send an async signal.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return fix.SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ fix.WaitForRunEvent();
+
+ std::future<bool> async_result = std::async(
+ std::launch::async, [&] { return fix.client.SendAsyncSignal(0x47); });
+
+ // First we'll get interrupted.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
+
+ // Then we get the signal packet.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("C47", response.GetStringRef());
+ ASSERT_TRUE(async_result.get());
+
+ // And we report back a signal stop.
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T47"));
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T47", continue_response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) {
+ StringExtractorGDBRemote continue_response, async_response, response;
+ const bool send_async = true;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // Continue. After the run packet is sent, send an async packet.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return fix.SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ fix.WaitForRunEvent();
+
+ // Sending without async enabled should fail.
+ ASSERT_EQ(
+ PacketResult::ErrorSendFailed,
+ fix.client.SendPacketAndWaitForResponse("qTest1", response, !send_async));
+
+ std::future<PacketResult> async_result = std::async(std::launch::async, [&] {
+ return fix.client.SendPacketAndWaitForResponse("qTest2", async_response,
+ send_async);
+ });
+
+ // First we'll get interrupted.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
+
+ // Then we get the async packet.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("qTest2", response.GetStringRef());
+
+ // Send the response and receive it.
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("QTest2"));
+ ASSERT_EQ(PacketResult::Success, async_result.get());
+ ASSERT_EQ("QTest2", async_response.GetStringRef());
+
+ // And we get resumed again.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T01", continue_response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) {
+ StringExtractorGDBRemote continue_response, response;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // Interrupt should do nothing when we're not running.
+ ASSERT_FALSE(fix.client.Interrupt());
+
+ // Continue. After the run packet is sent, send an interrupt.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return fix.SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ fix.WaitForRunEvent();
+
+ std::future<bool> async_result =
+ std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
+
+ // We get interrupted.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
+
+ // And that's it.
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T13", continue_response.GetStringRef());
+ ASSERT_TRUE(async_result.get());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) {
+ StringExtractorGDBRemote continue_response, response;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // Continue. After the run packet is sent, send an interrupt.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return fix.SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ fix.WaitForRunEvent();
+
+ std::future<bool> async_result =
+ std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
+
+ // However, the target stops due to a different reason than the original
+ // interrupt.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T01", continue_response.GetStringRef());
+ ASSERT_TRUE(async_result.get());
+
+ // The subsequent continue packet should work normally.
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
+ ASSERT_EQ("T01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) {
+ StringExtractorGDBRemote continue_response, async_response, response;
+ const bool send_async = true;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // Interrupt should do nothing when we're not running.
+ ASSERT_FALSE(fix.client.Interrupt());
+
+ // Continue. After the run packet is sent, send an async signal.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return fix.SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ fix.WaitForRunEvent();
+
+ std::future<bool> interrupt_result =
+ std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
+
+ // We get interrupted. We'll send two packets to simulate a buggy stub.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
+
+ // We should stop.
+ ASSERT_EQ(eStateStopped, continue_state.get());
+ ASSERT_EQ("T13", continue_response.GetStringRef());
+ ASSERT_TRUE(interrupt_result.get());
+
+ // Packet stream should remain synchronized.
+ std::future<PacketResult> send_result = std::async(std::launch::async, [&] {
+ return fix.client.SendPacketAndWaitForResponse("qTest", async_response,
+ !send_async);
+ });
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("qTest", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("QTest"));
+ ASSERT_EQ(PacketResult::Success, send_result.get());
+ ASSERT_EQ("QTest", async_response.GetStringRef());
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) {
+ StringExtractorGDBRemote response;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // Continue. We'll have the server send a bunch of async packets before it
+ // stops.
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("O4142"));
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("Apro"));
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("O4344"));
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("Afile"));
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
+ ASSERT_EQ("T01", response.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+
+ EXPECT_EQ("ABCD", fix.delegate.output);
+ EXPECT_EQ("profile", fix.delegate.misc_data);
+ EXPECT_EQ(1u, fix.delegate.stop_reply_called);
+}
+
+TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {
+ // Build the plain-text version of the JSON data we will have the
+ // server send.
+ const std::string json_payload =
+ "{ \"type\": \"MyFeatureType\", "
+ " \"elements\": [ \"entry1\", \"entry2\" ] }";
+ const std::string json_packet = "JSON-async:" + json_payload;
+
+ // Escape it properly for transit.
+ StreamGDBRemote stream;
+ stream.PutEscapedBytes(json_packet.c_str(), json_packet.length());
+ stream.Flush();
+
+ // Set up the
+ StringExtractorGDBRemote response;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // Send async structured data packet, then stop.
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket(stream.GetData()));
+ ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
+ ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
+ ASSERT_EQ("T01", response.GetStringRef());
+ ASSERT_EQ(1ul, fix.delegate.structured_data_packets.size());
+
+ // Verify the packet contents. It should have been unescaped upon packet
+ // reception.
+ ASSERT_EQ(json_packet, fix.delegate.structured_data_packets[0]);
+}
+
+TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) {
+ StringExtractorGDBRemote continue_response, response;
+ ContinueFixture fix;
+ if (HasFailure())
+ return;
+
+ // Continue. After the run packet is sent, send an interrupt.
+ std::future<StateType> continue_state = std::async(
+ std::launch::async, [&] { return fix.SendCPacket(continue_response); });
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("c", response.GetStringRef());
+ fix.WaitForRunEvent();
+
+ std::future<bool> async_result =
+ std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
+
+ // We get interrupted, but we don't send a stop packet.
+ ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
+ ASSERT_EQ("\x03", response.GetStringRef());
+
+ // The functions should still terminate (after a timeout).
+ ASSERT_TRUE(async_result.get());
+ ASSERT_EQ(eStateInvalid, continue_state.get());
+}
diff --git a/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
new file mode 100644
index 000000000000..84b354d75170
--- /dev/null
+++ b/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -0,0 +1,307 @@
+//===-- GDBRemoteCommunicationClientTest.cpp --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread>
+// when
+// exceptions are disabled.
+#include <eh.h>
+#endif
+#include <future>
+
+#include "GDBRemoteTestUtils.h"
+
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/StructuredData.h"
+
+#include "llvm/ADT/ArrayRef.h"
+
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private;
+using namespace lldb;
+using namespace llvm;
+
+namespace {
+
+typedef GDBRemoteCommunication::PacketResult PacketResult;
+
+struct TestClient : public GDBRemoteCommunicationClient {
+ TestClient() { m_send_acks = false; }
+};
+
+void Handle_QThreadSuffixSupported(MockServer &server, bool supported) {
+ StringExtractorGDBRemote request;
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
+ ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef());
+ if (supported)
+ ASSERT_EQ(PacketResult::Success, server.SendOKResponse());
+ else
+ ASSERT_EQ(PacketResult::Success, server.SendUnimplementedResponse(nullptr));
+}
+
+void HandlePacket(MockServer &server, StringRef expected, StringRef response) {
+ StringExtractorGDBRemote request;
+ ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
+ ASSERT_EQ(expected, request.GetStringRef());
+ ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
+}
+
+uint8_t all_registers[] = {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'};
+std::string all_registers_hex = "404142434445464748494a4b4c4d4e4f";
+uint8_t one_register[] = {'A', 'B', 'C', 'D'};
+std::string one_register_hex = "41424344";
+
+} // end anonymous namespace
+
+class GDBRemoteCommunicationClientTest : public GDBRemoteTest {};
+
+TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ const lldb::tid_t tid = 0x47;
+ const uint32_t reg_num = 4;
+ std::future<bool> write_result = std::async(std::launch::async, [&] {
+ return client.WriteRegister(tid, reg_num, one_register);
+ });
+
+ Handle_QThreadSuffixSupported(server, true);
+
+ HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK");
+ ASSERT_TRUE(write_result.get());
+
+ write_result = std::async(std::launch::async, [&] {
+ return client.WriteAllRegisters(tid, all_registers);
+ });
+
+ HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK");
+ ASSERT_TRUE(write_result.get());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ const lldb::tid_t tid = 0x47;
+ const uint32_t reg_num = 4;
+ std::future<bool> write_result = std::async(std::launch::async, [&] {
+ return client.WriteRegister(tid, reg_num, one_register);
+ });
+
+ Handle_QThreadSuffixSupported(server, false);
+ HandlePacket(server, "Hg47", "OK");
+ HandlePacket(server, "P4=" + one_register_hex, "OK");
+ ASSERT_TRUE(write_result.get());
+
+ write_result = std::async(std::launch::async, [&] {
+ return client.WriteAllRegisters(tid, all_registers);
+ });
+
+ HandlePacket(server, "G" + all_registers_hex, "OK");
+ ASSERT_TRUE(write_result.get());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ const lldb::tid_t tid = 0x47;
+ const uint32_t reg_num = 4;
+ std::future<bool> async_result = std::async(
+ std::launch::async, [&] { return client.GetpPacketSupported(tid); });
+ Handle_QThreadSuffixSupported(server, true);
+ HandlePacket(server, "p0;thread:0047;", one_register_hex);
+ ASSERT_TRUE(async_result.get());
+
+ std::future<DataBufferSP> read_result = std::async(
+ std::launch::async, [&] { return client.ReadRegister(tid, reg_num); });
+ HandlePacket(server, "p4;thread:0047;", "41424344");
+ auto buffer_sp = read_result.get();
+ ASSERT_TRUE(bool(buffer_sp));
+ ASSERT_EQ(0,
+ memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register));
+
+ read_result = std::async(std::launch::async,
+ [&] { return client.ReadAllRegisters(tid); });
+ HandlePacket(server, "g;thread:0047;", all_registers_hex);
+ buffer_sp = read_result.get();
+ ASSERT_TRUE(bool(buffer_sp));
+ ASSERT_EQ(0,
+ memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers));
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ const lldb::tid_t tid = 0x47;
+ uint32_t save_id;
+ std::future<bool> async_result = std::async(std::launch::async, [&] {
+ return client.SaveRegisterState(tid, save_id);
+ });
+ Handle_QThreadSuffixSupported(server, false);
+ HandlePacket(server, "Hg47", "OK");
+ HandlePacket(server, "QSaveRegisterState", "1");
+ ASSERT_TRUE(async_result.get());
+ EXPECT_EQ(1u, save_id);
+
+ async_result = std::async(std::launch::async, [&] {
+ return client.RestoreRegisterState(tid, save_id);
+ });
+ HandlePacket(server, "QRestoreRegisterState:1", "OK");
+ ASSERT_TRUE(async_result.get());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ const lldb::tid_t tid = 0x47;
+ std::future<bool> async_result = std::async(
+ std::launch::async, [&] { return client.SyncThreadState(tid); });
+ HandlePacket(server, "qSyncThreadStateSupported", "OK");
+ HandlePacket(server, "QSyncThreadState:0047;", "OK");
+ ASSERT_TRUE(async_result.get());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ llvm::Triple triple("i386-pc-linux");
+
+ FileSpec file_specs[] = {
+ FileSpec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix),
+ FileSpec("/foo/baz.so", false, FileSpec::ePathSyntaxPosix)};
+ std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
+ std::async(std::launch::async,
+ [&] { return client.GetModulesInfo(file_specs, triple); });
+ HandlePacket(
+ server, "jModulesInfo:["
+ R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)"
+ R"({"file":"/foo/baz.so","triple":"i386-pc-linux"}])",
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");
+
+ auto result = async_result.get();
+ ASSERT_TRUE(result.hasValue());
+ ASSERT_EQ(1u, result->size());
+ EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath());
+ EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple());
+ EXPECT_EQ(UUID("@ABCDEFGHIJKLMNO", 16), result.getValue()[0].GetUUID());
+ EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
+ EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ llvm::Triple triple("i386-pc-linux");
+ FileSpec file_spec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix);
+
+ const char *invalid_responses[] = {
+ "OK", "E47", "[]",
+ // no UUID
+ R"([{"triple":"i386-pc-linux",)"
+ R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])",
+ // no triple
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f",)"
+ R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}])",
+ // no file_path
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ R"("file_offset":0,"file_size":1234}])",
+ // no file_offset
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ R"("file_path":"/foo/bar.so","file_size":1234}])",
+ // no file_size
+ R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
+ R"("file_path":"/foo/bar.so","file_offset":0}])",
+ };
+
+ for (const char *response : invalid_responses) {
+ std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
+ std::async(std::launch::async,
+ [&] { return client.GetModulesInfo(file_spec, triple); });
+ HandlePacket(
+ server,
+ R"(jModulesInfo:[{"file":"/foo/bar.so","triple":"i386-pc-linux"}])",
+ response);
+
+ ASSERT_FALSE(async_result.get().hasValue()) << "response was: " << response;
+ }
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
+ TestClient client;
+ MockServer server;
+ Connect(client, server);
+ if (HasFailure())
+ return;
+
+ std::thread server_thread([&server] {
+ for (;;) {
+ StringExtractorGDBRemote request;
+ PacketResult result = server.GetPacket(request);
+ if (result == PacketResult::ErrorDisconnected)
+ return;
+ ASSERT_EQ(PacketResult::Success, result);
+ StringRef ref = request.GetStringRef();
+ ASSERT_TRUE(ref.consume_front("qSpeedTest:response_size:"));
+ int size;
+ ASSERT_FALSE(ref.consumeInteger(10, size)) << "ref: " << ref;
+ std::string response(size, 'X');
+ ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
+ }
+ });
+
+ StreamString ss;
+ client.TestPacketSpeed(10, 32, 32, 4096, true, ss);
+ client.Disconnect();
+ server_thread.join();
+
+ auto object_sp = StructuredData::ParseJSON(ss.GetString());
+ ASSERT_TRUE(bool(object_sp));
+ auto dict_sp = object_sp->GetAsDictionary();
+ ASSERT_TRUE(bool(dict_sp));
+
+ object_sp = dict_sp->GetValueForKey("packet_speeds");
+ ASSERT_TRUE(bool(object_sp));
+ dict_sp = object_sp->GetAsDictionary();
+ ASSERT_TRUE(bool(dict_sp));
+
+ int num_packets;
+ ASSERT_TRUE(dict_sp->GetValueForKeyAsInteger("num_packets", num_packets))
+ << ss.GetString();
+ ASSERT_EQ(10, num_packets);
+}
diff --git a/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp b/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp
new file mode 100644
index 000000000000..58cc9f50586a
--- /dev/null
+++ b/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp
@@ -0,0 +1,69 @@
+//===-- GDBRemoteTestUtils.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread>
+// when
+// exceptions are disabled.
+#include <eh.h>
+#endif
+
+#include "GDBRemoteTestUtils.h"
+
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
+
+#include <future>
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+void GDBRemoteTest::SetUpTestCase() {
+#if defined(_MSC_VER)
+ WSADATA data;
+ ::WSAStartup(MAKEWORD(2, 2), &data);
+#endif
+}
+
+void GDBRemoteTest::TearDownTestCase() {
+#if defined(_MSC_VER)
+ ::WSACleanup();
+#endif
+}
+
+void Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server) {
+ bool child_processes_inherit = false;
+ Error error;
+ TCPSocket listen_socket(child_processes_inherit, error);
+ ASSERT_FALSE(error.Fail());
+ error = listen_socket.Listen("127.0.0.1:0", 5);
+ ASSERT_FALSE(error.Fail());
+
+ Socket *accept_socket;
+ std::future<Error> accept_error = std::async(std::launch::async, [&] {
+ return listen_socket.Accept("127.0.0.1:0", child_processes_inherit,
+ accept_socket);
+ });
+
+ char connect_remote_address[64];
+ snprintf(connect_remote_address, sizeof(connect_remote_address),
+ "connect://localhost:%u", listen_socket.GetLocalPortNumber());
+
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(
+ new ConnectionFileDescriptor());
+ ASSERT_EQ(conn_ap->Connect(connect_remote_address, nullptr),
+ lldb::eConnectionStatusSuccess);
+
+ client.SetConnection(conn_ap.release());
+ ASSERT_TRUE(accept_error.get().Success());
+ server.SetConnection(new ConnectionFileDescriptor(accept_socket));
+}
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
diff --git a/unittests/Process/gdb-remote/GDBRemoteTestUtils.h b/unittests/Process/gdb-remote/GDBRemoteTestUtils.h
new file mode 100644
index 000000000000..d7700f23e5ab
--- /dev/null
+++ b/unittests/Process/gdb-remote/GDBRemoteTestUtils.h
@@ -0,0 +1,51 @@
+//===-- GDBRemoteTestUtils.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef lldb_unittests_Process_gdb_remote_GDBRemoteTestUtils_h
+#define lldb_unittests_Process_gdb_remote_GDBRemoteTestUtils_h
+
+#include "gtest/gtest.h"
+
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class GDBRemoteTest : public testing::Test {
+public:
+ static void SetUpTestCase();
+
+ static void TearDownTestCase();
+};
+
+void Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server);
+
+struct MockServer : public GDBRemoteCommunicationServer {
+ MockServer()
+ : GDBRemoteCommunicationServer("mock-server", "mock-server.listener") {
+ m_send_acks = false;
+ }
+
+ PacketResult SendPacket(llvm::StringRef payload) {
+ return GDBRemoteCommunicationServer::SendPacketNoLock(payload);
+ }
+
+ PacketResult GetPacket(StringExtractorGDBRemote &response) {
+ const bool sync_on_timeout = false;
+ return WaitForPacketNoLock(response, std::chrono::seconds(1),
+ sync_on_timeout);
+ }
+
+ using GDBRemoteCommunicationServer::SendOKResponse;
+ using GDBRemoteCommunicationServer::SendUnimplementedResponse;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // lldb_unittests_Process_gdb_remote_GDBRemoteTestUtils_h
diff --git a/unittests/Process/minidump/CMakeLists.txt b/unittests/Process/minidump/CMakeLists.txt
new file mode 100644
index 000000000000..10cb8c34f352
--- /dev/null
+++ b/unittests/Process/minidump/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_lldb_unittest(LLDBMinidumpTests
+ MinidumpParserTest.cpp
+ )
+
+set(test_inputs
+ linux-i386.dmp
+ linux-x86_64.dmp
+ linux-x86_64_not_crashed.dmp
+ fizzbuzz_no_heap.dmp
+ fizzbuzz_wow64.dmp)
+
+add_unittest_inputs(LLDBMinidumpTests "${test_inputs}")
diff --git a/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp b/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp
new file mode 100644
index 000000000000..19008c91fc3e
--- /dev/null
+++ b/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp
Binary files differ
diff --git a/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp b/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp
new file mode 100644
index 000000000000..3d97186f2cd2
--- /dev/null
+++ b/unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp
Binary files differ
diff --git a/unittests/Process/minidump/Inputs/linux-i386.dmp b/unittests/Process/minidump/Inputs/linux-i386.dmp
new file mode 100644
index 000000000000..946a7cf0355b
--- /dev/null
+++ b/unittests/Process/minidump/Inputs/linux-i386.dmp
Binary files differ
diff --git a/unittests/Process/minidump/Inputs/linux-x86_64.cpp b/unittests/Process/minidump/Inputs/linux-x86_64.cpp
new file mode 100644
index 000000000000..827fe67b503b
--- /dev/null
+++ b/unittests/Process/minidump/Inputs/linux-x86_64.cpp
@@ -0,0 +1,28 @@
+// Example source from breakpad's linux tutorial
+// https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/linux_starter_guide.md
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "client/linux/handler/exception_handler.h"
+
+static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
+ void *context, bool succeeded) {
+ printf("Dump path: %s\n", descriptor.path());
+ return succeeded;
+}
+
+void crash() {
+ volatile int *a = (int *)(NULL);
+ *a = 1;
+}
+
+int main(int argc, char *argv[]) {
+ google_breakpad::MinidumpDescriptor descriptor("/tmp");
+ google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL,
+ true, -1);
+ printf("pid: %d\n", getpid());
+ crash();
+ return 0;
+}
diff --git a/unittests/Process/minidump/Inputs/linux-x86_64.dmp b/unittests/Process/minidump/Inputs/linux-x86_64.dmp
new file mode 100644
index 000000000000..29a12d6a2ebc
--- /dev/null
+++ b/unittests/Process/minidump/Inputs/linux-x86_64.dmp
Binary files differ
diff --git a/unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmp b/unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmp
new file mode 100644
index 000000000000..ad4b61a7bbb4
--- /dev/null
+++ b/unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmp
Binary files differ
diff --git a/unittests/Process/minidump/MinidumpParserTest.cpp b/unittests/Process/minidump/MinidumpParserTest.cpp
new file mode 100644
index 000000000000..83225e88ee03
--- /dev/null
+++ b/unittests/Process/minidump/MinidumpParserTest.cpp
@@ -0,0 +1,453 @@
+//===-- MinidumpTypesTest.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Project includes
+#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/minidump/MinidumpParser.h"
+#include "Plugins/Process/minidump/MinidumpTypes.h"
+#include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h"
+#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
+
+// Other libraries and framework includes
+#include "gtest/gtest.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+// C includes
+
+// C++ includes
+#include <memory>
+
+extern const char *TestMainArgv0;
+
+using namespace lldb_private;
+using namespace minidump;
+
+class MinidumpParserTest : public testing::Test {
+public:
+ void SetUp() override {
+ llvm::StringRef dmp_folder = llvm::sys::path::parent_path(TestMainArgv0);
+ inputs_folder = dmp_folder;
+ llvm::sys::path::append(inputs_folder, "Inputs");
+ }
+
+ void SetUpData(const char *minidump_filename, size_t load_size = SIZE_MAX) {
+ llvm::SmallString<128> filename = inputs_folder;
+ llvm::sys::path::append(filename, minidump_filename);
+ FileSpec minidump_file(filename.c_str(), false);
+ lldb::DataBufferSP data_sp(
+ minidump_file.MemoryMapFileContents(0, load_size));
+ llvm::Optional<MinidumpParser> optional_parser =
+ MinidumpParser::Create(data_sp);
+ ASSERT_TRUE(optional_parser.hasValue());
+ parser.reset(new MinidumpParser(optional_parser.getValue()));
+ ASSERT_GT(parser->GetData().size(), 0UL);
+ }
+
+ llvm::SmallString<128> inputs_folder;
+ std::unique_ptr<MinidumpParser> parser;
+};
+
+TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) {
+ SetUpData("linux-x86_64.dmp");
+ llvm::ArrayRef<MinidumpThread> thread_list;
+
+ thread_list = parser->GetThreads();
+ ASSERT_EQ(1UL, thread_list.size());
+
+ const MinidumpThread thread = thread_list[0];
+
+ EXPECT_EQ(16001UL, thread.thread_id);
+
+ llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread);
+ EXPECT_EQ(1232UL, context.size());
+}
+
+TEST_F(MinidumpParserTest, GetThreadsTruncatedFile) {
+ SetUpData("linux-x86_64.dmp", 200);
+ llvm::ArrayRef<MinidumpThread> thread_list;
+
+ thread_list = parser->GetThreads();
+ ASSERT_EQ(0UL, thread_list.size());
+}
+
+TEST_F(MinidumpParserTest, GetArchitecture) {
+ SetUpData("linux-x86_64.dmp");
+ ASSERT_EQ(llvm::Triple::ArchType::x86_64,
+ parser->GetArchitecture().GetMachine());
+ ASSERT_EQ(llvm::Triple::OSType::Linux,
+ parser->GetArchitecture().GetTriple().getOS());
+}
+
+TEST_F(MinidumpParserTest, GetMiscInfo) {
+ SetUpData("linux-x86_64.dmp");
+ const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();
+ ASSERT_EQ(nullptr, misc_info);
+}
+
+TEST_F(MinidumpParserTest, GetLinuxProcStatus) {
+ SetUpData("linux-x86_64.dmp");
+ llvm::Optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus();
+ ASSERT_TRUE(proc_status.hasValue());
+ lldb::pid_t pid = proc_status->GetPid();
+ ASSERT_EQ(16001UL, pid);
+}
+
+TEST_F(MinidumpParserTest, GetPid) {
+ SetUpData("linux-x86_64.dmp");
+ llvm::Optional<lldb::pid_t> pid = parser->GetPid();
+ ASSERT_TRUE(pid.hasValue());
+ ASSERT_EQ(16001UL, pid.getValue());
+}
+
+TEST_F(MinidumpParserTest, GetModuleList) {
+ SetUpData("linux-x86_64.dmp");
+ llvm::ArrayRef<MinidumpModule> modules = parser->GetModuleList();
+ ASSERT_EQ(8UL, modules.size());
+ std::string module_names[8] = {
+ "/usr/local/google/home/dvlahovski/projects/test_breakpad/a.out",
+ "/lib/x86_64-linux-gnu/libm-2.19.so",
+ "/lib/x86_64-linux-gnu/libc-2.19.so",
+ "/lib/x86_64-linux-gnu/libgcc_s.so.1",
+ "/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19",
+ "/lib/x86_64-linux-gnu/libpthread-2.19.so",
+ "/lib/x86_64-linux-gnu/ld-2.19.so",
+ "linux-gate.so",
+ };
+
+ for (int i = 0; i < 8; ++i) {
+ llvm::Optional<std::string> name =
+ parser->GetMinidumpString(modules[i].module_name_rva);
+ ASSERT_TRUE(name.hasValue());
+ EXPECT_EQ(module_names[i], name.getValue());
+ }
+}
+
+TEST_F(MinidumpParserTest, GetFilteredModuleList) {
+ SetUpData("linux-x86_64_not_crashed.dmp");
+ llvm::ArrayRef<MinidumpModule> modules = parser->GetModuleList();
+ std::vector<const MinidumpModule *> filtered_modules =
+ parser->GetFilteredModuleList();
+ EXPECT_EQ(10UL, modules.size());
+ EXPECT_EQ(9UL, filtered_modules.size());
+ // EXPECT_GT(modules.size(), filtered_modules.size());
+ bool found = false;
+ for (size_t i = 0; i < filtered_modules.size(); ++i) {
+ llvm::Optional<std::string> name =
+ parser->GetMinidumpString(filtered_modules[i]->module_name_rva);
+ ASSERT_TRUE(name.hasValue());
+ if (name.getValue() == "/tmp/test/linux-x86_64_not_crashed") {
+ ASSERT_FALSE(found) << "There should be only one module with this name "
+ "in the filtered module list";
+ found = true;
+ ASSERT_EQ(0x400000UL, filtered_modules[i]->base_of_image);
+ }
+ }
+}
+
+TEST_F(MinidumpParserTest, GetExceptionStream) {
+ SetUpData("linux-x86_64.dmp");
+ const MinidumpExceptionStream *exception_stream =
+ parser->GetExceptionStream();
+ ASSERT_NE(nullptr, exception_stream);
+ ASSERT_EQ(11UL, exception_stream->exception_record.exception_code);
+}
+
+void check_mem_range_exists(std::unique_ptr<MinidumpParser> &parser,
+ const uint64_t range_start,
+ const uint64_t range_size) {
+ llvm::Optional<minidump::Range> range = parser->FindMemoryRange(range_start);
+ ASSERT_TRUE(range.hasValue()) << "There is no range containing this address";
+ EXPECT_EQ(range_start, range->start);
+ EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size());
+}
+
+TEST_F(MinidumpParserTest, FindMemoryRange) {
+ SetUpData("linux-x86_64.dmp");
+ // There are two memory ranges in the file (size is in bytes, decimal):
+ // 1) 0x401d46 256
+ // 2) 0x7ffceb34a000 12288
+ EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue());
+ EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue());
+
+ check_mem_range_exists(parser, 0x401d46, 256);
+ EXPECT_FALSE(parser->FindMemoryRange(0x401d46 + 256).hasValue());
+
+ check_mem_range_exists(parser, 0x7ffceb34a000, 12288);
+ EXPECT_FALSE(parser->FindMemoryRange(0x7ffceb34a000 + 12288).hasValue());
+}
+
+TEST_F(MinidumpParserTest, GetMemory) {
+ SetUpData("linux-x86_64.dmp");
+
+ EXPECT_EQ(128UL, parser->GetMemory(0x401d46, 128).size());
+ EXPECT_EQ(256UL, parser->GetMemory(0x401d46, 512).size());
+
+ EXPECT_EQ(12288UL, parser->GetMemory(0x7ffceb34a000, 12288).size());
+ EXPECT_EQ(1024UL, parser->GetMemory(0x7ffceb34a000, 1024).size());
+
+ EXPECT_TRUE(parser->GetMemory(0x500000, 512).empty());
+}
+
+TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {
+ SetUpData("fizzbuzz_wow64.dmp");
+
+ // There are a lot of ranges in the file, just testing with some of them
+ EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue());
+ EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue());
+ check_mem_range_exists(parser, 0x10000, 65536); // first range
+ check_mem_range_exists(parser, 0x40000, 4096);
+ EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).hasValue());
+ check_mem_range_exists(parser, 0x77c12000, 8192);
+ check_mem_range_exists(parser, 0x7ffe0000, 4096); // last range
+ EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).hasValue());
+}
+
+void check_region_info(std::unique_ptr<MinidumpParser> &parser,
+ const uint64_t addr, MemoryRegionInfo::OptionalBool read,
+ MemoryRegionInfo::OptionalBool write,
+ MemoryRegionInfo::OptionalBool exec) {
+ auto range_info = parser->GetMemoryRegionInfo(addr);
+ ASSERT_TRUE(range_info.hasValue());
+ EXPECT_EQ(read, range_info->GetReadable());
+ EXPECT_EQ(write, range_info->GetWritable());
+ EXPECT_EQ(exec, range_info->GetExecutable());
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
+ SetUpData("fizzbuzz_wow64.dmp");
+
+ const auto yes = MemoryRegionInfo::eYes;
+ const auto no = MemoryRegionInfo::eNo;
+
+ check_region_info(parser, 0x00000, no, no, no);
+ check_region_info(parser, 0x10000, yes, yes, no);
+ check_region_info(parser, 0x20000, yes, yes, no);
+ check_region_info(parser, 0x30000, yes, yes, no);
+ check_region_info(parser, 0x31000, no, no, no);
+ check_region_info(parser, 0x40000, yes, no, no);
+}
+
+// Windows Minidump tests
+// fizzbuzz_no_heap.dmp is copied from the WinMiniDump tests
+TEST_F(MinidumpParserTest, GetArchitectureWindows) {
+ SetUpData("fizzbuzz_no_heap.dmp");
+ ASSERT_EQ(llvm::Triple::ArchType::x86,
+ parser->GetArchitecture().GetMachine());
+ ASSERT_EQ(llvm::Triple::OSType::Win32,
+ parser->GetArchitecture().GetTriple().getOS());
+}
+
+TEST_F(MinidumpParserTest, GetLinuxProcStatusWindows) {
+ SetUpData("fizzbuzz_no_heap.dmp");
+ llvm::Optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus();
+ ASSERT_FALSE(proc_status.hasValue());
+}
+
+TEST_F(MinidumpParserTest, GetMiscInfoWindows) {
+ SetUpData("fizzbuzz_no_heap.dmp");
+ const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();
+ ASSERT_NE(nullptr, misc_info);
+ llvm::Optional<lldb::pid_t> pid = misc_info->GetPid();
+ ASSERT_TRUE(pid.hasValue());
+ ASSERT_EQ(4440UL, pid.getValue());
+}
+
+TEST_F(MinidumpParserTest, GetPidWindows) {
+ SetUpData("fizzbuzz_no_heap.dmp");
+ llvm::Optional<lldb::pid_t> pid = parser->GetPid();
+ ASSERT_TRUE(pid.hasValue());
+ ASSERT_EQ(4440UL, pid.getValue());
+}
+
+// wow64
+TEST_F(MinidumpParserTest, GetPidWow64) {
+ SetUpData("fizzbuzz_wow64.dmp");
+ llvm::Optional<lldb::pid_t> pid = parser->GetPid();
+ ASSERT_TRUE(pid.hasValue());
+ ASSERT_EQ(7836UL, pid.getValue());
+}
+
+TEST_F(MinidumpParserTest, GetModuleListWow64) {
+ SetUpData("fizzbuzz_wow64.dmp");
+ llvm::ArrayRef<MinidumpModule> modules = parser->GetModuleList();
+ ASSERT_EQ(16UL, modules.size());
+ std::string module_names[16] = {
+ R"(D:\src\llvm\llvm\tools\lldb\packages\Python\lldbsuite\test\functionalities\postmortem\wow64_minidump\fizzbuzz.exe)",
+ R"(C:\Windows\System32\ntdll.dll)",
+ R"(C:\Windows\System32\wow64.dll)",
+ R"(C:\Windows\System32\wow64win.dll)",
+ R"(C:\Windows\System32\wow64cpu.dll)",
+ R"(D:\src\llvm\llvm\tools\lldb\packages\Python\lldbsuite\test\functionalities\postmortem\wow64_minidump\fizzbuzz.exe)",
+ R"(C:\Windows\SysWOW64\ntdll.dll)",
+ R"(C:\Windows\SysWOW64\kernel32.dll)",
+ R"(C:\Windows\SysWOW64\KERNELBASE.dll)",
+ R"(C:\Windows\SysWOW64\advapi32.dll)",
+ R"(C:\Windows\SysWOW64\msvcrt.dll)",
+ R"(C:\Windows\SysWOW64\sechost.dll)",
+ R"(C:\Windows\SysWOW64\rpcrt4.dll)",
+ R"(C:\Windows\SysWOW64\sspicli.dll)",
+ R"(C:\Windows\SysWOW64\CRYPTBASE.dll)",
+ R"(C:\Windows\System32\api-ms-win-core-synch-l1-2-0.DLL)",
+ };
+
+ for (int i = 0; i < 16; ++i) {
+ llvm::Optional<std::string> name =
+ parser->GetMinidumpString(modules[i].module_name_rva);
+ ASSERT_TRUE(name.hasValue());
+ EXPECT_EQ(module_names[i], name.getValue());
+ }
+}
+
+// Register tests
+#define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x))
+#define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x))
+
+TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_32) {
+ SetUpData("linux-i386.dmp");
+ llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads();
+ const MinidumpThread thread = thread_list[0];
+ llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
+
+ ArchSpec arch = parser->GetArchitecture();
+ RegisterInfoInterface *reg_interface = new RegisterContextLinux_i386(arch);
+ lldb::DataBufferSP buf =
+ ConvertMinidumpContext_x86_32(registers, reg_interface);
+ ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize());
+
+ const RegisterInfo *reg_info = reg_interface->GetRegisterInfo();
+
+ std::map<uint64_t, uint32_t> reg_values;
+
+ reg_values[lldb_eax_i386] = 0x00000000;
+ reg_values[lldb_ebx_i386] = 0xf7778000;
+ reg_values[lldb_ecx_i386] = 0x00000001;
+ reg_values[lldb_edx_i386] = 0xff9dd4a3;
+ reg_values[lldb_edi_i386] = 0x080482a8;
+ reg_values[lldb_esi_i386] = 0xff9dd55c;
+ reg_values[lldb_ebp_i386] = 0xff9dd53c;
+ reg_values[lldb_esp_i386] = 0xff9dd52c;
+ reg_values[lldb_eip_i386] = 0x080482a0;
+ reg_values[lldb_eflags_i386] = 0x00010282;
+ reg_values[lldb_cs_i386] = 0x00000023;
+ reg_values[lldb_fs_i386] = 0x00000000;
+ reg_values[lldb_gs_i386] = 0x00000063;
+ reg_values[lldb_ss_i386] = 0x0000002b;
+ reg_values[lldb_ds_i386] = 0x0000002b;
+ reg_values[lldb_es_i386] = 0x0000002b;
+
+ for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount();
+ ++reg_index) {
+ if (reg_values.find(reg_index) != reg_values.end()) {
+ EXPECT_EQ(reg_values[reg_index],
+ REG_VAL32(buf->GetBytes() + reg_info[reg_index].byte_offset));
+ }
+ }
+}
+
+TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_64) {
+ SetUpData("linux-x86_64.dmp");
+ llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads();
+ const MinidumpThread thread = thread_list[0];
+ llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
+
+ ArchSpec arch = parser->GetArchitecture();
+ RegisterInfoInterface *reg_interface = new RegisterContextLinux_x86_64(arch);
+ lldb::DataBufferSP buf =
+ ConvertMinidumpContext_x86_64(registers, reg_interface);
+ ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize());
+
+ const RegisterInfo *reg_info = reg_interface->GetRegisterInfo();
+
+ std::map<uint64_t, uint64_t> reg_values;
+
+ reg_values[lldb_rax_x86_64] = 0x0000000000000000;
+ reg_values[lldb_rbx_x86_64] = 0x0000000000000000;
+ reg_values[lldb_rcx_x86_64] = 0x0000000000000010;
+ reg_values[lldb_rdx_x86_64] = 0x0000000000000000;
+ reg_values[lldb_rdi_x86_64] = 0x00007ffceb349cf0;
+ reg_values[lldb_rsi_x86_64] = 0x0000000000000000;
+ reg_values[lldb_rbp_x86_64] = 0x00007ffceb34a210;
+ reg_values[lldb_rsp_x86_64] = 0x00007ffceb34a210;
+ reg_values[lldb_r8_x86_64] = 0x00007fe9bc1aa9c0;
+ reg_values[lldb_r9_x86_64] = 0x0000000000000000;
+ reg_values[lldb_r10_x86_64] = 0x00007fe9bc3f16a0;
+ reg_values[lldb_r11_x86_64] = 0x0000000000000246;
+ reg_values[lldb_r12_x86_64] = 0x0000000000401c92;
+ reg_values[lldb_r13_x86_64] = 0x00007ffceb34a430;
+ reg_values[lldb_r14_x86_64] = 0x0000000000000000;
+ reg_values[lldb_r15_x86_64] = 0x0000000000000000;
+ reg_values[lldb_rip_x86_64] = 0x0000000000401dc6;
+ reg_values[lldb_rflags_x86_64] = 0x0000000000010206;
+ reg_values[lldb_cs_x86_64] = 0x0000000000000033;
+ reg_values[lldb_fs_x86_64] = 0x0000000000000000;
+ reg_values[lldb_gs_x86_64] = 0x0000000000000000;
+ reg_values[lldb_ss_x86_64] = 0x0000000000000000;
+ reg_values[lldb_ds_x86_64] = 0x0000000000000000;
+ reg_values[lldb_es_x86_64] = 0x0000000000000000;
+
+ for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount();
+ ++reg_index) {
+ if (reg_values.find(reg_index) != reg_values.end()) {
+ EXPECT_EQ(reg_values[reg_index],
+ REG_VAL64(buf->GetBytes() + reg_info[reg_index].byte_offset));
+ }
+ }
+}
+
+TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_32_wow64) {
+ SetUpData("fizzbuzz_wow64.dmp");
+ llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads();
+ const MinidumpThread thread = thread_list[0];
+ llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(thread));
+
+ ArchSpec arch = parser->GetArchitecture();
+ RegisterInfoInterface *reg_interface = new RegisterContextLinux_i386(arch);
+ lldb::DataBufferSP buf =
+ ConvertMinidumpContext_x86_32(registers, reg_interface);
+ ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize());
+
+ const RegisterInfo *reg_info = reg_interface->GetRegisterInfo();
+
+ std::map<uint64_t, uint32_t> reg_values;
+
+ reg_values[lldb_eax_i386] = 0x00000000;
+ reg_values[lldb_ebx_i386] = 0x0037f608;
+ reg_values[lldb_ecx_i386] = 0x00e61578;
+ reg_values[lldb_edx_i386] = 0x00000008;
+ reg_values[lldb_edi_i386] = 0x00000000;
+ reg_values[lldb_esi_i386] = 0x00000002;
+ reg_values[lldb_ebp_i386] = 0x0037f654;
+ reg_values[lldb_esp_i386] = 0x0037f5b8;
+ reg_values[lldb_eip_i386] = 0x77ce01fd;
+ reg_values[lldb_eflags_i386] = 0x00000246;
+ reg_values[lldb_cs_i386] = 0x00000023;
+ reg_values[lldb_fs_i386] = 0x00000053;
+ reg_values[lldb_gs_i386] = 0x0000002b;
+ reg_values[lldb_ss_i386] = 0x0000002b;
+ reg_values[lldb_ds_i386] = 0x0000002b;
+ reg_values[lldb_es_i386] = 0x0000002b;
+
+ for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount();
+ ++reg_index) {
+ if (reg_values.find(reg_index) != reg_values.end()) {
+ EXPECT_EQ(reg_values[reg_index],
+ REG_VAL32(buf->GetBytes() + reg_info[reg_index].byte_offset));
+ }
+ }
+} \ No newline at end of file
diff --git a/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp b/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp
index c239a1601b32..192e64d07034 100644
--- a/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp
+++ b/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp
@@ -7,591 +7,593 @@
//
//===----------------------------------------------------------------------===//
+#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
#include "gtest/gtest.h"
+#include "Plugins/ScriptInterpreter/Python/PythonDataObjects.h"
+#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
-#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
-#include "Plugins/ScriptInterpreter/Python/PythonDataObjects.h"
-#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
#include "PythonTestSuite.h"
using namespace lldb_private;
-class PythonDataObjectsTest : public PythonTestSuite
-{
- public:
- void
- SetUp() override
- {
- PythonTestSuite::SetUp();
-
- PythonString sys_module("sys");
- m_sys_module.Reset(PyRefType::Owned, PyImport_Import(sys_module.get()));
- m_main_module = PythonModule::MainModule();
- m_builtins_module = PythonModule::BuiltinsModule();
- }
-
- void
- TearDown() override
- {
- m_sys_module.Reset();
- m_main_module.Reset();
- m_builtins_module.Reset();
-
- PythonTestSuite::TearDown();
- }
-
- protected:
- PythonModule m_sys_module;
- PythonModule m_main_module;
- PythonModule m_builtins_module;
+class PythonDataObjectsTest : public PythonTestSuite {
+public:
+ void SetUp() override {
+ PythonTestSuite::SetUp();
+
+ PythonString sys_module("sys");
+ m_sys_module.Reset(PyRefType::Owned, PyImport_Import(sys_module.get()));
+ m_main_module = PythonModule::MainModule();
+ m_builtins_module = PythonModule::BuiltinsModule();
+ }
+
+ void TearDown() override {
+ m_sys_module.Reset();
+ m_main_module.Reset();
+ m_builtins_module.Reset();
+
+ PythonTestSuite::TearDown();
+ }
+
+protected:
+ PythonModule m_sys_module;
+ PythonModule m_main_module;
+ PythonModule m_builtins_module;
};
-TEST_F(PythonDataObjectsTest, TestOwnedReferences)
-{
- // After creating a new object, the refcount should be >= 1
- PyObject *obj = PyLong_FromLong(3);
- Py_ssize_t original_refcnt = obj->ob_refcnt;
- EXPECT_LE(1, original_refcnt);
+TEST_F(PythonDataObjectsTest, TestOwnedReferences) {
+ // After creating a new object, the refcount should be >= 1
+ PyObject *obj = PyLong_FromLong(3);
+ Py_ssize_t original_refcnt = obj->ob_refcnt;
+ EXPECT_LE(1, original_refcnt);
- // If we take an owned reference, the refcount should be the same
- PythonObject owned_long(PyRefType::Owned, obj);
- EXPECT_EQ(original_refcnt, owned_long.get()->ob_refcnt);
+ // If we take an owned reference, the refcount should be the same
+ PythonObject owned_long(PyRefType::Owned, obj);
+ EXPECT_EQ(original_refcnt, owned_long.get()->ob_refcnt);
- // Take another reference and verify that the refcount increases by 1
- PythonObject strong_ref(owned_long);
- EXPECT_EQ(original_refcnt + 1, strong_ref.get()->ob_refcnt);
+ // Take another reference and verify that the refcount increases by 1
+ PythonObject strong_ref(owned_long);
+ EXPECT_EQ(original_refcnt + 1, strong_ref.get()->ob_refcnt);
- // If we reset the first one, the refcount should be the original value.
- owned_long.Reset();
- EXPECT_EQ(original_refcnt, strong_ref.get()->ob_refcnt);
+ // If we reset the first one, the refcount should be the original value.
+ owned_long.Reset();
+ EXPECT_EQ(original_refcnt, strong_ref.get()->ob_refcnt);
}
-TEST_F(PythonDataObjectsTest, TestResetting)
-{
- PythonDictionary dict(PyInitialValue::Empty);
+TEST_F(PythonDataObjectsTest, TestResetting) {
+ PythonDictionary dict(PyInitialValue::Empty);
- PyObject *new_dict = PyDict_New();
- dict.Reset(PyRefType::Owned, new_dict);
- EXPECT_EQ(new_dict, dict.get());
+ PyObject *new_dict = PyDict_New();
+ dict.Reset(PyRefType::Owned, new_dict);
+ EXPECT_EQ(new_dict, dict.get());
- dict.Reset(PyRefType::Owned, nullptr);
- EXPECT_EQ(nullptr, dict.get());
+ dict.Reset(PyRefType::Owned, nullptr);
+ EXPECT_EQ(nullptr, dict.get());
- dict.Reset(PyRefType::Owned, PyDict_New());
- EXPECT_NE(nullptr, dict.get());
- dict.Reset();
- EXPECT_EQ(nullptr, dict.get());
+ dict.Reset(PyRefType::Owned, PyDict_New());
+ EXPECT_NE(nullptr, dict.get());
+ dict.Reset();
+ EXPECT_EQ(nullptr, dict.get());
}
-TEST_F(PythonDataObjectsTest, TestBorrowedReferences)
-{
- PythonInteger long_value(PyRefType::Owned, PyLong_FromLong(3));
- Py_ssize_t original_refcnt = long_value.get()->ob_refcnt;
- EXPECT_LE(1, original_refcnt);
+TEST_F(PythonDataObjectsTest, TestBorrowedReferences) {
+ PythonInteger long_value(PyRefType::Owned, PyLong_FromLong(3));
+ Py_ssize_t original_refcnt = long_value.get()->ob_refcnt;
+ EXPECT_LE(1, original_refcnt);
- PythonInteger borrowed_long(PyRefType::Borrowed, long_value.get());
- EXPECT_EQ(original_refcnt + 1, borrowed_long.get()->ob_refcnt);
+ PythonInteger borrowed_long(PyRefType::Borrowed, long_value.get());
+ EXPECT_EQ(original_refcnt + 1, borrowed_long.get()->ob_refcnt);
}
-TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionNoDot)
-{
- PythonObject sys_module = m_main_module.ResolveName("sys");
- EXPECT_EQ(m_sys_module.get(), sys_module.get());
- EXPECT_TRUE(sys_module.IsAllocated());
- EXPECT_TRUE(PythonModule::Check(sys_module.get()));
+TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionNoDot) {
+ PythonObject sys_module = m_main_module.ResolveName("sys");
+ EXPECT_EQ(m_sys_module.get(), sys_module.get());
+ EXPECT_TRUE(sys_module.IsAllocated());
+ EXPECT_TRUE(PythonModule::Check(sys_module.get()));
}
-TEST_F(PythonDataObjectsTest, TestModuleNameResolutionNoDot)
-{
- PythonObject sys_path = m_sys_module.ResolveName("path");
- PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
- EXPECT_TRUE(sys_path.IsAllocated());
- EXPECT_TRUE(sys_version_info.IsAllocated());
+TEST_F(PythonDataObjectsTest, TestModuleNameResolutionNoDot) {
+ PythonObject sys_path = m_sys_module.ResolveName("path");
+ PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
+ EXPECT_TRUE(sys_path.IsAllocated());
+ EXPECT_TRUE(sys_version_info.IsAllocated());
- EXPECT_TRUE(PythonList::Check(sys_path.get()));
+ EXPECT_TRUE(PythonList::Check(sys_path.get()));
}
-TEST_F(PythonDataObjectsTest, TestTypeNameResolutionNoDot)
-{
- PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
+TEST_F(PythonDataObjectsTest, TestTypeNameResolutionNoDot) {
+ PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
- PythonObject version_info_type(PyRefType::Owned, PyObject_Type(sys_version_info.get()));
- EXPECT_TRUE(version_info_type.IsAllocated());
- PythonObject major_version_field = version_info_type.ResolveName("major");
- EXPECT_TRUE(major_version_field.IsAllocated());
+ PythonObject version_info_type(PyRefType::Owned,
+ PyObject_Type(sys_version_info.get()));
+ EXPECT_TRUE(version_info_type.IsAllocated());
+ PythonObject major_version_field = version_info_type.ResolveName("major");
+ EXPECT_TRUE(major_version_field.IsAllocated());
}
-TEST_F(PythonDataObjectsTest, TestInstanceNameResolutionNoDot)
-{
- PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
- PythonObject major_version_field = sys_version_info.ResolveName("major");
- PythonObject minor_version_field = sys_version_info.ResolveName("minor");
+TEST_F(PythonDataObjectsTest, TestInstanceNameResolutionNoDot) {
+ PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
+ PythonObject major_version_field = sys_version_info.ResolveName("major");
+ PythonObject minor_version_field = sys_version_info.ResolveName("minor");
- EXPECT_TRUE(major_version_field.IsAllocated());
- EXPECT_TRUE(minor_version_field.IsAllocated());
+ EXPECT_TRUE(major_version_field.IsAllocated());
+ EXPECT_TRUE(minor_version_field.IsAllocated());
- PythonInteger major_version_value = major_version_field.AsType<PythonInteger>();
- PythonInteger minor_version_value = minor_version_field.AsType<PythonInteger>();
+ PythonInteger major_version_value =
+ major_version_field.AsType<PythonInteger>();
+ PythonInteger minor_version_value =
+ minor_version_field.AsType<PythonInteger>();
- EXPECT_EQ(PY_MAJOR_VERSION, major_version_value.GetInteger());
- EXPECT_EQ(PY_MINOR_VERSION, minor_version_value.GetInteger());
+ EXPECT_EQ(PY_MAJOR_VERSION, major_version_value.GetInteger());
+ EXPECT_EQ(PY_MINOR_VERSION, minor_version_value.GetInteger());
}
-TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionWithDot)
-{
- PythonObject sys_path = m_main_module.ResolveName("sys.path");
- EXPECT_TRUE(sys_path.IsAllocated());
- EXPECT_TRUE(PythonList::Check(sys_path.get()));
+TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionWithDot) {
+ PythonObject sys_path = m_main_module.ResolveName("sys.path");
+ EXPECT_TRUE(sys_path.IsAllocated());
+ EXPECT_TRUE(PythonList::Check(sys_path.get()));
- PythonInteger version_major = m_main_module.ResolveName(
- "sys.version_info.major").AsType<PythonInteger>();
- PythonInteger version_minor = m_main_module.ResolveName(
- "sys.version_info.minor").AsType<PythonInteger>();
- EXPECT_TRUE(version_major.IsAllocated());
- EXPECT_TRUE(version_minor.IsAllocated());
- EXPECT_EQ(PY_MAJOR_VERSION, version_major.GetInteger());
- EXPECT_EQ(PY_MINOR_VERSION, version_minor.GetInteger());
+ PythonInteger version_major =
+ m_main_module.ResolveName("sys.version_info.major")
+ .AsType<PythonInteger>();
+ PythonInteger version_minor =
+ m_main_module.ResolveName("sys.version_info.minor")
+ .AsType<PythonInteger>();
+ EXPECT_TRUE(version_major.IsAllocated());
+ EXPECT_TRUE(version_minor.IsAllocated());
+ EXPECT_EQ(PY_MAJOR_VERSION, version_major.GetInteger());
+ EXPECT_EQ(PY_MINOR_VERSION, version_minor.GetInteger());
}
-TEST_F(PythonDataObjectsTest, TestDictionaryResolutionWithDot)
-{
- // Make up a custom dictionary with "sys" pointing to the `sys` module.
- PythonDictionary dict(PyInitialValue::Empty);
- dict.SetItemForKey(PythonString("sys"), m_sys_module);
+TEST_F(PythonDataObjectsTest, TestDictionaryResolutionWithDot) {
+ // Make up a custom dictionary with "sys" pointing to the `sys` module.
+ PythonDictionary dict(PyInitialValue::Empty);
+ dict.SetItemForKey(PythonString("sys"), m_sys_module);
- // Now use that dictionary to resolve `sys.version_info.major`
- PythonInteger version_major = PythonObject::ResolveNameWithDictionary(
- "sys.version_info.major", dict).AsType<PythonInteger>();
- PythonInteger version_minor = PythonObject::ResolveNameWithDictionary(
- "sys.version_info.minor", dict).AsType<PythonInteger>();
- EXPECT_EQ(PY_MAJOR_VERSION, version_major.GetInteger());
- EXPECT_EQ(PY_MINOR_VERSION, version_minor.GetInteger());
+ // Now use that dictionary to resolve `sys.version_info.major`
+ PythonInteger version_major =
+ PythonObject::ResolveNameWithDictionary("sys.version_info.major", dict)
+ .AsType<PythonInteger>();
+ PythonInteger version_minor =
+ PythonObject::ResolveNameWithDictionary("sys.version_info.minor", dict)
+ .AsType<PythonInteger>();
+ EXPECT_EQ(PY_MAJOR_VERSION, version_major.GetInteger());
+ EXPECT_EQ(PY_MINOR_VERSION, version_minor.GetInteger());
}
-TEST_F(PythonDataObjectsTest, TestPythonInteger)
-{
+TEST_F(PythonDataObjectsTest, TestPythonInteger) {
// Test that integers behave correctly when wrapped by a PythonInteger.
#if PY_MAJOR_VERSION < 3
- // Verify that `PythonInt` works correctly when given a PyInt object.
- // Note that PyInt doesn't exist in Python 3.x, so this is only for 2.x
- PyObject *py_int = PyInt_FromLong(12);
- EXPECT_TRUE(PythonInteger::Check(py_int));
- PythonInteger python_int(PyRefType::Owned, py_int);
-
- EXPECT_EQ(PyObjectType::Integer, python_int.GetObjectType());
- EXPECT_EQ(12, python_int.GetInteger());
+ // Verify that `PythonInt` works correctly when given a PyInt object.
+ // Note that PyInt doesn't exist in Python 3.x, so this is only for 2.x
+ PyObject *py_int = PyInt_FromLong(12);
+ EXPECT_TRUE(PythonInteger::Check(py_int));
+ PythonInteger python_int(PyRefType::Owned, py_int);
+
+ EXPECT_EQ(PyObjectType::Integer, python_int.GetObjectType());
+ EXPECT_EQ(12, python_int.GetInteger());
#endif
- // Verify that `PythonInteger` works correctly when given a PyLong object.
- PyObject *py_long = PyLong_FromLong(12);
- EXPECT_TRUE(PythonInteger::Check(py_long));
- PythonInteger python_long(PyRefType::Owned, py_long);
- EXPECT_EQ(PyObjectType::Integer, python_long.GetObjectType());
+ // Verify that `PythonInteger` works correctly when given a PyLong object.
+ PyObject *py_long = PyLong_FromLong(12);
+ EXPECT_TRUE(PythonInteger::Check(py_long));
+ PythonInteger python_long(PyRefType::Owned, py_long);
+ EXPECT_EQ(PyObjectType::Integer, python_long.GetObjectType());
- // Verify that you can reset the value and that it is reflected properly.
- python_long.SetInteger(40);
- EXPECT_EQ(40, python_long.GetInteger());
+ // Verify that you can reset the value and that it is reflected properly.
+ python_long.SetInteger(40);
+ EXPECT_EQ(40, python_long.GetInteger());
- // Test that creating a `PythonInteger` object works correctly with the
- // int constructor.
- PythonInteger constructed_int(7);
- EXPECT_EQ(7, constructed_int.GetInteger());
+ // Test that creating a `PythonInteger` object works correctly with the
+ // int constructor.
+ PythonInteger constructed_int(7);
+ EXPECT_EQ(7, constructed_int.GetInteger());
}
-TEST_F(PythonDataObjectsTest, TestPythonBytes)
-{
- static const char *test_bytes = "PythonDataObjectsTest::TestPythonBytes";
- PyObject *py_bytes = PyBytes_FromString(test_bytes);
- EXPECT_TRUE(PythonBytes::Check(py_bytes));
- PythonBytes python_bytes(PyRefType::Owned, py_bytes);
+TEST_F(PythonDataObjectsTest, TestPythonBytes) {
+ static const char *test_bytes = "PythonDataObjectsTest::TestPythonBytes";
+ PyObject *py_bytes = PyBytes_FromString(test_bytes);
+ EXPECT_TRUE(PythonBytes::Check(py_bytes));
+ PythonBytes python_bytes(PyRefType::Owned, py_bytes);
#if PY_MAJOR_VERSION < 3
- EXPECT_TRUE(PythonString::Check(py_bytes));
- EXPECT_EQ(PyObjectType::String, python_bytes.GetObjectType());
+ EXPECT_TRUE(PythonString::Check(py_bytes));
+ EXPECT_EQ(PyObjectType::String, python_bytes.GetObjectType());
#else
- EXPECT_FALSE(PythonString::Check(py_bytes));
- EXPECT_EQ(PyObjectType::Bytes, python_bytes.GetObjectType());
+ EXPECT_FALSE(PythonString::Check(py_bytes));
+ EXPECT_EQ(PyObjectType::Bytes, python_bytes.GetObjectType());
#endif
- llvm::ArrayRef<uint8_t> bytes = python_bytes.GetBytes();
- EXPECT_EQ(bytes.size(), strlen(test_bytes));
- EXPECT_EQ(0, ::memcmp(bytes.data(), test_bytes, bytes.size()));
+ llvm::ArrayRef<uint8_t> bytes = python_bytes.GetBytes();
+ EXPECT_EQ(bytes.size(), strlen(test_bytes));
+ EXPECT_EQ(0, ::memcmp(bytes.data(), test_bytes, bytes.size()));
}
-TEST_F(PythonDataObjectsTest, TestPythonByteArray)
-{
- static const char *test_bytes = "PythonDataObjectsTest::TestPythonByteArray";
- llvm::StringRef orig_bytes(test_bytes);
- PyObject *py_bytes = PyByteArray_FromStringAndSize(test_bytes, orig_bytes.size());
- EXPECT_TRUE(PythonByteArray::Check(py_bytes));
- PythonByteArray python_bytes(PyRefType::Owned, py_bytes);
- EXPECT_EQ(PyObjectType::ByteArray, python_bytes.GetObjectType());
+TEST_F(PythonDataObjectsTest, TestPythonByteArray) {
+ static const char *test_bytes = "PythonDataObjectsTest::TestPythonByteArray";
+ llvm::StringRef orig_bytes(test_bytes);
+ PyObject *py_bytes =
+ PyByteArray_FromStringAndSize(test_bytes, orig_bytes.size());
+ EXPECT_TRUE(PythonByteArray::Check(py_bytes));
+ PythonByteArray python_bytes(PyRefType::Owned, py_bytes);
+ EXPECT_EQ(PyObjectType::ByteArray, python_bytes.GetObjectType());
- llvm::ArrayRef<uint8_t> after_bytes = python_bytes.GetBytes();
- EXPECT_EQ(after_bytes.size(), orig_bytes.size());
- EXPECT_EQ(0, ::memcmp(orig_bytes.data(), test_bytes, orig_bytes.size()));
+ llvm::ArrayRef<uint8_t> after_bytes = python_bytes.GetBytes();
+ EXPECT_EQ(after_bytes.size(), orig_bytes.size());
+ EXPECT_EQ(0, ::memcmp(orig_bytes.data(), test_bytes, orig_bytes.size()));
}
-TEST_F(PythonDataObjectsTest, TestPythonString)
-{
- // Test that strings behave correctly when wrapped by a PythonString.
+TEST_F(PythonDataObjectsTest, TestPythonString) {
+ // Test that strings behave correctly when wrapped by a PythonString.
- static const char *test_string = "PythonDataObjectsTest::TestPythonString1";
- static const char *test_string2 = "PythonDataObjectsTest::TestPythonString2";
+ static const char *test_string = "PythonDataObjectsTest::TestPythonString1";
+ static const char *test_string2 = "PythonDataObjectsTest::TestPythonString2";
#if PY_MAJOR_VERSION < 3
- // Verify that `PythonString` works correctly when given a PyString object.
- // Note that PyString doesn't exist in Python 3.x, so this is only for 2.x
- PyObject *py_string = PyString_FromString(test_string);
- EXPECT_TRUE(PythonString::Check(py_string));
- PythonString python_string(PyRefType::Owned, py_string);
-
- EXPECT_EQ(PyObjectType::String, python_string.GetObjectType());
- EXPECT_STREQ(test_string, python_string.GetString().data());
+ // Verify that `PythonString` works correctly when given a PyString object.
+ // Note that PyString doesn't exist in Python 3.x, so this is only for 2.x
+ PyObject *py_string = PyString_FromString(test_string);
+ EXPECT_TRUE(PythonString::Check(py_string));
+ PythonString python_string(PyRefType::Owned, py_string);
+
+ EXPECT_EQ(PyObjectType::String, python_string.GetObjectType());
+ EXPECT_STREQ(test_string, python_string.GetString().data());
#else
- // Verify that `PythonString` works correctly when given a PyUnicode object.
- PyObject *py_unicode = PyUnicode_FromString(test_string);
- EXPECT_TRUE(PythonString::Check(py_unicode));
- PythonString python_unicode(PyRefType::Owned, py_unicode);
- EXPECT_EQ(PyObjectType::String, python_unicode.GetObjectType());
- EXPECT_STREQ(test_string, python_unicode.GetString().data());
+ // Verify that `PythonString` works correctly when given a PyUnicode object.
+ PyObject *py_unicode = PyUnicode_FromString(test_string);
+ EXPECT_TRUE(PythonString::Check(py_unicode));
+ PythonString python_unicode(PyRefType::Owned, py_unicode);
+ EXPECT_EQ(PyObjectType::String, python_unicode.GetObjectType());
+ EXPECT_STREQ(test_string, python_unicode.GetString().data());
#endif
- // Test that creating a `PythonString` object works correctly with the
- // string constructor
- PythonString constructed_string(test_string2);
- EXPECT_STREQ(test_string2, constructed_string.GetString().str().c_str());
+ // Test that creating a `PythonString` object works correctly with the
+ // string constructor
+ PythonString constructed_string(test_string2);
+ EXPECT_EQ(test_string2, constructed_string.GetString());
}
-TEST_F(PythonDataObjectsTest, TestPythonStringToStr)
-{
- const char *c_str = "PythonDataObjectsTest::TestPythonStringToStr";
+TEST_F(PythonDataObjectsTest, TestPythonStringToStr) {
+ const char *GetString = "PythonDataObjectsTest::TestPythonStringToStr";
- PythonString str(c_str);
- EXPECT_STREQ(c_str, str.GetString().str().c_str());
+ PythonString str(GetString);
+ EXPECT_EQ(GetString, str.GetString());
- PythonString str_str = str.Str();
- EXPECT_STREQ(c_str, str_str.GetString().str().c_str());
+ PythonString str_str = str.Str();
+ EXPECT_EQ(GetString, str_str.GetString());
}
-TEST_F(PythonDataObjectsTest, TestPythonIntegerToStr)
-{
-}
+TEST_F(PythonDataObjectsTest, TestPythonIntegerToStr) {}
-TEST_F(PythonDataObjectsTest, TestPythonIntegerToStructuredInteger)
-{
- PythonInteger integer(7);
- auto int_sp = integer.CreateStructuredInteger();
- EXPECT_EQ(7U, int_sp->GetValue());
+TEST_F(PythonDataObjectsTest, TestPythonIntegerToStructuredInteger) {
+ PythonInteger integer(7);
+ auto int_sp = integer.CreateStructuredInteger();
+ EXPECT_EQ(7U, int_sp->GetValue());
}
-TEST_F(PythonDataObjectsTest, TestPythonStringToStructuredString)
-{
- static const char *test_string = "PythonDataObjectsTest::TestPythonStringToStructuredString";
- PythonString constructed_string(test_string);
- auto string_sp = constructed_string.CreateStructuredString();
- EXPECT_STREQ(test_string, string_sp->GetStringValue().c_str());
+TEST_F(PythonDataObjectsTest, TestPythonStringToStructuredString) {
+ static const char *test_string =
+ "PythonDataObjectsTest::TestPythonStringToStructuredString";
+ PythonString constructed_string(test_string);
+ auto string_sp = constructed_string.CreateStructuredString();
+ EXPECT_EQ(test_string, string_sp->GetStringValue());
}
-TEST_F(PythonDataObjectsTest, TestPythonListValueEquality)
-{
- // Test that a list which is built through the native
- // Python API behaves correctly when wrapped by a PythonList.
- static const unsigned list_size = 2;
- static const long long_value0 = 5;
- static const char *const string_value1 = "String Index 1";
+TEST_F(PythonDataObjectsTest, TestPythonListValueEquality) {
+ // Test that a list which is built through the native
+ // Python API behaves correctly when wrapped by a PythonList.
+ static const unsigned list_size = 2;
+ static const long long_value0 = 5;
+ static const char *const string_value1 = "String Index 1";
- PyObject *py_list = PyList_New(2);
- EXPECT_TRUE(PythonList::Check(py_list));
- PythonList list(PyRefType::Owned, py_list);
+ PyObject *py_list = PyList_New(2);
+ EXPECT_TRUE(PythonList::Check(py_list));
+ PythonList list(PyRefType::Owned, py_list);
- PythonObject list_items[list_size];
- list_items[0].Reset(PythonInteger(long_value0));
- list_items[1].Reset(PythonString(string_value1));
+ PythonObject list_items[list_size];
+ list_items[0].Reset(PythonInteger(long_value0));
+ list_items[1].Reset(PythonString(string_value1));
- for (unsigned i = 0; i < list_size; ++i)
- list.SetItemAtIndex(i, list_items[i]);
+ for (unsigned i = 0; i < list_size; ++i)
+ list.SetItemAtIndex(i, list_items[i]);
- EXPECT_EQ(list_size, list.GetSize());
- EXPECT_EQ(PyObjectType::List, list.GetObjectType());
+ EXPECT_EQ(list_size, list.GetSize());
+ EXPECT_EQ(PyObjectType::List, list.GetObjectType());
- // Verify that the values match
- PythonObject chk_value1 = list.GetItemAtIndex(0);
- PythonObject chk_value2 = list.GetItemAtIndex(1);
- EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
- EXPECT_TRUE(PythonString::Check(chk_value2.get()));
+ // Verify that the values match
+ PythonObject chk_value1 = list.GetItemAtIndex(0);
+ PythonObject chk_value2 = list.GetItemAtIndex(1);
+ EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
+ EXPECT_TRUE(PythonString::Check(chk_value2.get()));
- PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
- PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
+ PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
+ PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
- EXPECT_EQ(long_value0, chk_int.GetInteger());
- EXPECT_STREQ(string_value1, chk_str.GetString().str().c_str());
+ EXPECT_EQ(long_value0, chk_int.GetInteger());
+ EXPECT_EQ(string_value1, chk_str.GetString());
}
-TEST_F(PythonDataObjectsTest, TestPythonListManipulation)
-{
- // Test that manipulation of a PythonList behaves correctly when
- // wrapped by a PythonDictionary.
+TEST_F(PythonDataObjectsTest, TestPythonListManipulation) {
+ // Test that manipulation of a PythonList behaves correctly when
+ // wrapped by a PythonDictionary.
- static const long long_value0 = 5;
- static const char *const string_value1 = "String Index 1";
+ static const long long_value0 = 5;
+ static const char *const string_value1 = "String Index 1";
- PythonList list(PyInitialValue::Empty);
- PythonInteger integer(long_value0);
- PythonString string(string_value1);
+ PythonList list(PyInitialValue::Empty);
+ PythonInteger integer(long_value0);
+ PythonString string(string_value1);
- list.AppendItem(integer);
- list.AppendItem(string);
- EXPECT_EQ(2U, list.GetSize());
+ list.AppendItem(integer);
+ list.AppendItem(string);
+ EXPECT_EQ(2U, list.GetSize());
- // Verify that the values match
- PythonObject chk_value1 = list.GetItemAtIndex(0);
- PythonObject chk_value2 = list.GetItemAtIndex(1);
- EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
- EXPECT_TRUE(PythonString::Check(chk_value2.get()));
+ // Verify that the values match
+ PythonObject chk_value1 = list.GetItemAtIndex(0);
+ PythonObject chk_value2 = list.GetItemAtIndex(1);
+ EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
+ EXPECT_TRUE(PythonString::Check(chk_value2.get()));
- PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
- PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
+ PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
+ PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
- EXPECT_EQ(long_value0, chk_int.GetInteger());
- EXPECT_STREQ(string_value1, chk_str.GetString().str().c_str());
+ EXPECT_EQ(long_value0, chk_int.GetInteger());
+ EXPECT_EQ(string_value1, chk_str.GetString());
}
-TEST_F(PythonDataObjectsTest, TestPythonListToStructuredList)
-{
- static const long long_value0 = 5;
- static const char *const string_value1 = "String Index 1";
+TEST_F(PythonDataObjectsTest, TestPythonListToStructuredList) {
+ static const long long_value0 = 5;
+ static const char *const string_value1 = "String Index 1";
- PythonList list(PyInitialValue::Empty);
- list.AppendItem(PythonInteger(long_value0));
- list.AppendItem(PythonString(string_value1));
+ PythonList list(PyInitialValue::Empty);
+ list.AppendItem(PythonInteger(long_value0));
+ list.AppendItem(PythonString(string_value1));
- auto array_sp = list.CreateStructuredArray();
- EXPECT_EQ(StructuredData::Type::eTypeInteger, array_sp->GetItemAtIndex(0)->GetType());
- EXPECT_EQ(StructuredData::Type::eTypeString, array_sp->GetItemAtIndex(1)->GetType());
+ auto array_sp = list.CreateStructuredArray();
+ EXPECT_EQ(StructuredData::Type::eTypeInteger,
+ array_sp->GetItemAtIndex(0)->GetType());
+ EXPECT_EQ(StructuredData::Type::eTypeString,
+ array_sp->GetItemAtIndex(1)->GetType());
- auto int_sp = array_sp->GetItemAtIndex(0)->GetAsInteger();
- auto string_sp = array_sp->GetItemAtIndex(1)->GetAsString();
+ auto int_sp = array_sp->GetItemAtIndex(0)->GetAsInteger();
+ auto string_sp = array_sp->GetItemAtIndex(1)->GetAsString();
- EXPECT_EQ(long_value0, long(int_sp->GetValue()));
- EXPECT_STREQ(string_value1, string_sp->GetValue().c_str());
+ EXPECT_EQ(long_value0, long(int_sp->GetValue()));
+ EXPECT_EQ(string_value1, string_sp->GetValue());
}
-TEST_F(PythonDataObjectsTest, TestPythonTupleSize)
-{
- PythonTuple tuple(PyInitialValue::Empty);
- EXPECT_EQ(0U, tuple.GetSize());
+TEST_F(PythonDataObjectsTest, TestPythonTupleSize) {
+ PythonTuple tuple(PyInitialValue::Empty);
+ EXPECT_EQ(0U, tuple.GetSize());
- tuple = PythonTuple(3);
- EXPECT_EQ(3U, tuple.GetSize());
+ tuple = PythonTuple(3);
+ EXPECT_EQ(3U, tuple.GetSize());
}
-TEST_F(PythonDataObjectsTest, TestPythonTupleValues)
-{
- PythonTuple tuple(3);
+TEST_F(PythonDataObjectsTest, TestPythonTupleValues) {
+ PythonTuple tuple(3);
- PythonInteger int_value(1);
- PythonString string_value("Test");
- PythonObject none_value(PyRefType::Borrowed, Py_None);
+ PythonInteger int_value(1);
+ PythonString string_value("Test");
+ PythonObject none_value(PyRefType::Borrowed, Py_None);
- tuple.SetItemAtIndex(0, int_value);
- tuple.SetItemAtIndex(1, string_value);
- tuple.SetItemAtIndex(2, none_value);
+ tuple.SetItemAtIndex(0, int_value);
+ tuple.SetItemAtIndex(1, string_value);
+ tuple.SetItemAtIndex(2, none_value);
- EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
+ EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
+ EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
+ EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
}
-TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList)
-{
- PythonInteger int_value(1);
- PythonString string_value("Test");
- PythonObject none_value(PyRefType::Borrowed, Py_None);
- PythonTuple tuple{ int_value, string_value, none_value };
- EXPECT_EQ(3U, tuple.GetSize());
+TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList) {
+ PythonInteger int_value(1);
+ PythonString string_value("Test");
+ PythonObject none_value(PyRefType::Borrowed, Py_None);
+ PythonTuple tuple{int_value, string_value, none_value};
+ EXPECT_EQ(3U, tuple.GetSize());
- EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
+ EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
+ EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
+ EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
}
-TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList2)
-{
- PythonInteger int_value(1);
- PythonString string_value("Test");
- PythonObject none_value(PyRefType::Borrowed, Py_None);
+TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList2) {
+ PythonInteger int_value(1);
+ PythonString string_value("Test");
+ PythonObject none_value(PyRefType::Borrowed, Py_None);
- PythonTuple tuple{ int_value.get(), string_value.get(), none_value.get() };
- EXPECT_EQ(3U, tuple.GetSize());
+ PythonTuple tuple{int_value.get(), string_value.get(), none_value.get()};
+ EXPECT_EQ(3U, tuple.GetSize());
- EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
+ EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
+ EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
+ EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
}
-TEST_F(PythonDataObjectsTest, TestPythonTupleToStructuredList)
-{
- PythonInteger int_value(1);
- PythonString string_value("Test");
+TEST_F(PythonDataObjectsTest, TestPythonTupleToStructuredList) {
+ PythonInteger int_value(1);
+ PythonString string_value("Test");
- PythonTuple tuple{ int_value.get(), string_value.get() };
+ PythonTuple tuple{int_value.get(), string_value.get()};
- auto array_sp = tuple.CreateStructuredArray();
- EXPECT_EQ(tuple.GetSize(), array_sp->GetSize());
- EXPECT_EQ(StructuredData::Type::eTypeInteger, array_sp->GetItemAtIndex(0)->GetType());
- EXPECT_EQ(StructuredData::Type::eTypeString, array_sp->GetItemAtIndex(1)->GetType());
+ auto array_sp = tuple.CreateStructuredArray();
+ EXPECT_EQ(tuple.GetSize(), array_sp->GetSize());
+ EXPECT_EQ(StructuredData::Type::eTypeInteger,
+ array_sp->GetItemAtIndex(0)->GetType());
+ EXPECT_EQ(StructuredData::Type::eTypeString,
+ array_sp->GetItemAtIndex(1)->GetType());
}
-TEST_F(PythonDataObjectsTest, TestPythonDictionaryValueEquality)
-{
- // Test that a dictionary which is built through the native
- // Python API behaves correctly when wrapped by a PythonDictionary.
- static const unsigned dict_entries = 2;
- const char *key_0 = "Key 0";
- int key_1 = 1;
- const int value_0 = 0;
- const char *value_1 = "Value 1";
+TEST_F(PythonDataObjectsTest, TestPythonDictionaryValueEquality) {
+ // Test that a dictionary which is built through the native
+ // Python API behaves correctly when wrapped by a PythonDictionary.
+ static const unsigned dict_entries = 2;
+ const char *key_0 = "Key 0";
+ int key_1 = 1;
+ const int value_0 = 0;
+ const char *value_1 = "Value 1";
- PythonObject py_keys[dict_entries];
- PythonObject py_values[dict_entries];
+ PythonObject py_keys[dict_entries];
+ PythonObject py_values[dict_entries];
- py_keys[0].Reset(PythonString(key_0));
- py_keys[1].Reset(PythonInteger(key_1));
- py_values[0].Reset(PythonInteger(value_0));
- py_values[1].Reset(PythonString(value_1));
+ py_keys[0].Reset(PythonString(key_0));
+ py_keys[1].Reset(PythonInteger(key_1));
+ py_values[0].Reset(PythonInteger(value_0));
+ py_values[1].Reset(PythonString(value_1));
- PyObject *py_dict = PyDict_New();
- EXPECT_TRUE(PythonDictionary::Check(py_dict));
- PythonDictionary dict(PyRefType::Owned, py_dict);
+ PyObject *py_dict = PyDict_New();
+ EXPECT_TRUE(PythonDictionary::Check(py_dict));
+ PythonDictionary dict(PyRefType::Owned, py_dict);
- for (unsigned i = 0; i < dict_entries; ++i)
- PyDict_SetItem(py_dict, py_keys[i].get(), py_values[i].get());
- EXPECT_EQ(dict.GetSize(), dict_entries);
- EXPECT_EQ(PyObjectType::Dictionary, dict.GetObjectType());
+ for (unsigned i = 0; i < dict_entries; ++i)
+ PyDict_SetItem(py_dict, py_keys[i].get(), py_values[i].get());
+ EXPECT_EQ(dict.GetSize(), dict_entries);
+ EXPECT_EQ(PyObjectType::Dictionary, dict.GetObjectType());
- // Verify that the values match
- PythonObject chk_value1 = dict.GetItemForKey(py_keys[0]);
- PythonObject chk_value2 = dict.GetItemForKey(py_keys[1]);
- EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
- EXPECT_TRUE(PythonString::Check(chk_value2.get()));
+ // Verify that the values match
+ PythonObject chk_value1 = dict.GetItemForKey(py_keys[0]);
+ PythonObject chk_value2 = dict.GetItemForKey(py_keys[1]);
+ EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
+ EXPECT_TRUE(PythonString::Check(chk_value2.get()));
- PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
- PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
+ PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
+ PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
- EXPECT_EQ(value_0, chk_int.GetInteger());
- EXPECT_STREQ(value_1, chk_str.GetString().str().c_str());
+ EXPECT_EQ(value_0, chk_int.GetInteger());
+ EXPECT_EQ(value_1, chk_str.GetString());
}
-TEST_F(PythonDataObjectsTest, TestPythonDictionaryManipulation)
-{
- // Test that manipulation of a dictionary behaves correctly when wrapped
- // by a PythonDictionary.
- static const unsigned dict_entries = 2;
+TEST_F(PythonDataObjectsTest, TestPythonDictionaryManipulation) {
+ // Test that manipulation of a dictionary behaves correctly when wrapped
+ // by a PythonDictionary.
+ static const unsigned dict_entries = 2;
- const char *const key_0 = "Key 0";
- const char *const key_1 = "Key 1";
- const long value_0 = 1;
- const char *const value_1 = "Value 1";
+ const char *const key_0 = "Key 0";
+ const char *const key_1 = "Key 1";
+ const long value_0 = 1;
+ const char *const value_1 = "Value 1";
- PythonString keys[dict_entries];
- PythonObject values[dict_entries];
+ PythonString keys[dict_entries];
+ PythonObject values[dict_entries];
- keys[0].Reset(PythonString(key_0));
- keys[1].Reset(PythonString(key_1));
- values[0].Reset(PythonInteger(value_0));
- values[1].Reset(PythonString(value_1));
+ keys[0].Reset(PythonString(key_0));
+ keys[1].Reset(PythonString(key_1));
+ values[0].Reset(PythonInteger(value_0));
+ values[1].Reset(PythonString(value_1));
- PythonDictionary dict(PyInitialValue::Empty);
- for (int i = 0; i < 2; ++i)
- dict.SetItemForKey(keys[i], values[i]);
+ PythonDictionary dict(PyInitialValue::Empty);
+ for (int i = 0; i < 2; ++i)
+ dict.SetItemForKey(keys[i], values[i]);
- EXPECT_EQ(dict_entries, dict.GetSize());
+ EXPECT_EQ(dict_entries, dict.GetSize());
- // Verify that the keys and values match
- PythonObject chk_value1 = dict.GetItemForKey(keys[0]);
- PythonObject chk_value2 = dict.GetItemForKey(keys[1]);
- EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
- EXPECT_TRUE(PythonString::Check(chk_value2.get()));
+ // Verify that the keys and values match
+ PythonObject chk_value1 = dict.GetItemForKey(keys[0]);
+ PythonObject chk_value2 = dict.GetItemForKey(keys[1]);
+ EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
+ EXPECT_TRUE(PythonString::Check(chk_value2.get()));
- PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
- PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
+ PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
+ PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
- EXPECT_EQ(value_0, chk_int.GetInteger());
- EXPECT_STREQ(value_1, chk_str.GetString().str().c_str());
+ EXPECT_EQ(value_0, chk_int.GetInteger());
+ EXPECT_EQ(value_1, chk_str.GetString());
}
-TEST_F(PythonDataObjectsTest, TestPythonDictionaryToStructuredDictionary)
-{
- static const char *const string_key0 = "String Key 0";
- static const char *const string_key1 = "String Key 1";
-
- static const char *const string_value0 = "String Value 0";
- static const long int_value1 = 7;
-
- PythonDictionary dict(PyInitialValue::Empty);
- dict.SetItemForKey(PythonString(string_key0), PythonString(string_value0));
- dict.SetItemForKey(PythonString(string_key1), PythonInteger(int_value1));
-
- auto dict_sp = dict.CreateStructuredDictionary();
- EXPECT_EQ(2U, dict_sp->GetSize());
+TEST_F(PythonDataObjectsTest, TestPythonDictionaryToStructuredDictionary) {
+ static const char *const string_key0 = "String Key 0";
+ static const char *const string_key1 = "String Key 1";
- EXPECT_TRUE(dict_sp->HasKey(string_key0));
- EXPECT_TRUE(dict_sp->HasKey(string_key1));
+ static const char *const string_value0 = "String Value 0";
+ static const long int_value1 = 7;
- auto string_sp = dict_sp->GetValueForKey(string_key0)->GetAsString();
- auto int_sp = dict_sp->GetValueForKey(string_key1)->GetAsInteger();
+ PythonDictionary dict(PyInitialValue::Empty);
+ dict.SetItemForKey(PythonString(string_key0), PythonString(string_value0));
+ dict.SetItemForKey(PythonString(string_key1), PythonInteger(int_value1));
+
+ auto dict_sp = dict.CreateStructuredDictionary();
+ EXPECT_EQ(2U, dict_sp->GetSize());
- EXPECT_STREQ(string_value0, string_sp->GetValue().c_str());
- EXPECT_EQ(int_value1, long(int_sp->GetValue()));
+ EXPECT_TRUE(dict_sp->HasKey(string_key0));
+ EXPECT_TRUE(dict_sp->HasKey(string_key1));
+
+ auto string_sp = dict_sp->GetValueForKey(string_key0)->GetAsString();
+ auto int_sp = dict_sp->GetValueForKey(string_key1)->GetAsInteger();
+
+ EXPECT_EQ(string_value0, string_sp->GetValue());
+ EXPECT_EQ(int_value1, long(int_sp->GetValue()));
}
-
-TEST_F(PythonDataObjectsTest, TestPythonCallableCheck)
-{
- PythonObject sys_exc_info = m_sys_module.ResolveName("exc_info");
- PythonObject none(PyRefType::Borrowed, Py_None);
-
- EXPECT_TRUE(PythonCallable::Check(sys_exc_info.get()));
- EXPECT_FALSE(PythonCallable::Check(none.get()));
+
+TEST_F(PythonDataObjectsTest, TestPythonCallableCheck) {
+ PythonObject sys_exc_info = m_sys_module.ResolveName("exc_info");
+ PythonObject none(PyRefType::Borrowed, Py_None);
+
+ EXPECT_TRUE(PythonCallable::Check(sys_exc_info.get()));
+ EXPECT_FALSE(PythonCallable::Check(none.get()));
}
-TEST_F(PythonDataObjectsTest, TestPythonCallableInvoke)
-{
- auto list = m_builtins_module.ResolveName("list").AsType<PythonCallable>();
- PythonInteger one(1);
- PythonString two("two");
- PythonTuple three = { one, two };
+TEST_F(PythonDataObjectsTest, TestPythonCallableInvoke) {
+ auto list = m_builtins_module.ResolveName("list").AsType<PythonCallable>();
+ PythonInteger one(1);
+ PythonString two("two");
+ PythonTuple three = {one, two};
- PythonTuple tuple_to_convert = { one, two, three };
- PythonObject result = list({ tuple_to_convert });
+ PythonTuple tuple_to_convert = {one, two, three};
+ PythonObject result = list({tuple_to_convert});
- EXPECT_TRUE(PythonList::Check(result.get()));
- auto list_result = result.AsType<PythonList>();
- EXPECT_EQ(3U, list_result.GetSize());
- EXPECT_EQ(one.get(), list_result.GetItemAtIndex(0).get());
- EXPECT_EQ(two.get(), list_result.GetItemAtIndex(1).get());
- EXPECT_EQ(three.get(), list_result.GetItemAtIndex(2).get());
+ EXPECT_TRUE(PythonList::Check(result.get()));
+ auto list_result = result.AsType<PythonList>();
+ EXPECT_EQ(3U, list_result.GetSize());
+ EXPECT_EQ(one.get(), list_result.GetItemAtIndex(0).get());
+ EXPECT_EQ(two.get(), list_result.GetItemAtIndex(1).get());
+ EXPECT_EQ(three.get(), list_result.GetItemAtIndex(2).get());
}
-TEST_F(PythonDataObjectsTest, TestPythonFile)
-{
- File file(FileSystem::DEV_NULL, File::eOpenOptionRead);
- PythonFile py_file(file, "r");
- EXPECT_TRUE(PythonFile::Check(py_file.get()));
+TEST_F(PythonDataObjectsTest, TestPythonFile) {
+ File file(FileSystem::DEV_NULL, File::eOpenOptionRead);
+ PythonFile py_file(file, "r");
+ EXPECT_TRUE(PythonFile::Check(py_file.get()));
}
-TEST_F(PythonDataObjectsTest, TestObjectAttributes)
-{
- PythonInteger py_int(42);
- EXPECT_TRUE(py_int.HasAttribute("numerator"));
- EXPECT_FALSE(py_int.HasAttribute("this_should_not_exist"));
+TEST_F(PythonDataObjectsTest, TestObjectAttributes) {
+ PythonInteger py_int(42);
+ EXPECT_TRUE(py_int.HasAttribute("numerator"));
+ EXPECT_FALSE(py_int.HasAttribute("this_should_not_exist"));
- PythonInteger numerator_attr = py_int.GetAttributeValue("numerator").AsType<PythonInteger>();
- EXPECT_TRUE(numerator_attr.IsAllocated());
- EXPECT_EQ(42, numerator_attr.GetInteger());
+ PythonInteger numerator_attr =
+ py_int.GetAttributeValue("numerator").AsType<PythonInteger>();
+ EXPECT_TRUE(numerator_attr.IsAllocated());
+ EXPECT_EQ(42, numerator_attr.GetInteger());
+}
+
+TEST_F(PythonDataObjectsTest, TestExtractingUInt64ThroughStructuredData) {
+ // Make up a custom dictionary with "sys" pointing to the `sys` module.
+ const char *key_name = "addr";
+ const uint64_t value = 0xf000000000000000ull;
+ PythonDictionary python_dict(PyInitialValue::Empty);
+ PythonInteger python_ull_value(PyRefType::Owned,
+ PyLong_FromUnsignedLongLong(value));
+ python_dict.SetItemForKey(PythonString(key_name), python_ull_value);
+ StructuredData::ObjectSP structured_data_sp =
+ python_dict.CreateStructuredObject();
+ EXPECT_TRUE((bool)structured_data_sp);
+ if (structured_data_sp) {
+ StructuredData::Dictionary *structured_dict_ptr =
+ structured_data_sp->GetAsDictionary();
+ EXPECT_TRUE(structured_dict_ptr != nullptr);
+ if (structured_dict_ptr) {
+ StructuredData::ObjectSP structured_addr_value_sp =
+ structured_dict_ptr->GetValueForKey(key_name);
+ EXPECT_TRUE((bool)structured_addr_value_sp);
+ const uint64_t extracted_value =
+ structured_addr_value_sp->GetIntegerValue(123);
+ EXPECT_TRUE(extracted_value == value);
+ }
+ }
}
diff --git a/unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp b/unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp
index ddac220c7954..523a07ee8079 100644
--- a/unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp
+++ b/unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp
@@ -1,4 +1,5 @@
-//===-- PythonExceptionStateTest.cpp ------------------------------*- C++ -*-===//
+//===-- PythonExceptionStateTest.cpp ------------------------------*- C++
+//-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -9,166 +10,156 @@
#include "gtest/gtest.h"
-#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
#include "Plugins/ScriptInterpreter/Python/PythonDataObjects.h"
#include "Plugins/ScriptInterpreter/Python/PythonExceptionState.h"
#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
+#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
#include "PythonTestSuite.h"
using namespace lldb_private;
-class PythonExceptionStateTest : public PythonTestSuite
-{
- public:
- protected:
- void
- RaiseException()
- {
- PyErr_SetString(PyExc_RuntimeError, "PythonExceptionStateTest test error");
- }
+class PythonExceptionStateTest : public PythonTestSuite {
+public:
+protected:
+ void RaiseException() {
+ PyErr_SetString(PyExc_RuntimeError, "PythonExceptionStateTest test error");
+ }
};
-TEST_F(PythonExceptionStateTest, TestExceptionStateChecking)
-{
- PyErr_Clear();
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+TEST_F(PythonExceptionStateTest, TestExceptionStateChecking) {
+ PyErr_Clear();
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- RaiseException();
- EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
+ RaiseException();
+ EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
- PyErr_Clear();
+ PyErr_Clear();
}
-TEST_F(PythonExceptionStateTest, TestAcquisitionSemantics)
-{
- PyErr_Clear();
- PythonExceptionState no_error(false);
- EXPECT_FALSE(no_error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
-
- PyErr_Clear();
- RaiseException();
- PythonExceptionState error(false);
- EXPECT_TRUE(error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- error.Discard();
-
- PyErr_Clear();
- RaiseException();
- error.Acquire(false);
- EXPECT_TRUE(error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
-
- PyErr_Clear();
+TEST_F(PythonExceptionStateTest, TestAcquisitionSemantics) {
+ PyErr_Clear();
+ PythonExceptionState no_error(false);
+ EXPECT_FALSE(no_error.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+
+ PyErr_Clear();
+ RaiseException();
+ PythonExceptionState error(false);
+ EXPECT_TRUE(error.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ error.Discard();
+
+ PyErr_Clear();
+ RaiseException();
+ error.Acquire(false);
+ EXPECT_TRUE(error.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+
+ PyErr_Clear();
}
-TEST_F(PythonExceptionStateTest, TestDiscardSemantics)
-{
- PyErr_Clear();
+TEST_F(PythonExceptionStateTest, TestDiscardSemantics) {
+ PyErr_Clear();
- // Test that discarding an exception does not restore the exception
- // state even when auto-restore==true is set
- RaiseException();
- PythonExceptionState error(true);
- EXPECT_TRUE(error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ // Test that discarding an exception does not restore the exception
+ // state even when auto-restore==true is set
+ RaiseException();
+ PythonExceptionState error(true);
+ EXPECT_TRUE(error.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- error.Discard();
- EXPECT_FALSE(error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ error.Discard();
+ EXPECT_FALSE(error.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
}
-TEST_F(PythonExceptionStateTest, TestResetSemantics)
-{
- PyErr_Clear();
-
- // Resetting when auto-restore is true should restore.
- RaiseException();
- PythonExceptionState error(true);
- EXPECT_TRUE(error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- error.Reset();
- EXPECT_FALSE(error.IsError());
- EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
+TEST_F(PythonExceptionStateTest, TestResetSemantics) {
+ PyErr_Clear();
+
+ // Resetting when auto-restore is true should restore.
+ RaiseException();
+ PythonExceptionState error(true);
+ EXPECT_TRUE(error.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ error.Reset();
+ EXPECT_FALSE(error.IsError());
+ EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
+
+ PyErr_Clear();
+
+ // Resetting when auto-restore is false should discard.
+ RaiseException();
+ PythonExceptionState error2(false);
+ EXPECT_TRUE(error2.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ error2.Reset();
+ EXPECT_FALSE(error2.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+
+ PyErr_Clear();
+}
- PyErr_Clear();
+TEST_F(PythonExceptionStateTest, TestManualRestoreSemantics) {
+ PyErr_Clear();
+ RaiseException();
+ PythonExceptionState error(false);
+ EXPECT_TRUE(error.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- // Resetting when auto-restore is false should discard.
- RaiseException();
- PythonExceptionState error2(false);
- EXPECT_TRUE(error2.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- error2.Reset();
- EXPECT_FALSE(error2.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ error.Restore();
+ EXPECT_FALSE(error.IsError());
+ EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
- PyErr_Clear();
+ PyErr_Clear();
}
-TEST_F(PythonExceptionStateTest, TestManualRestoreSemantics)
-{
- PyErr_Clear();
+TEST_F(PythonExceptionStateTest, TestAutoRestoreSemantics) {
+ PyErr_Clear();
+ // Test that using the auto-restore flag correctly restores the exception
+ // state on destruction, and not using the auto-restore flag correctly
+ // does NOT restore the state on destruction.
+ {
RaiseException();
PythonExceptionState error(false);
EXPECT_TRUE(error.IsError());
EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ }
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- error.Restore();
- EXPECT_FALSE(error.IsError());
- EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
-
- PyErr_Clear();
-}
-
-TEST_F(PythonExceptionStateTest, TestAutoRestoreSemantics)
-{
- PyErr_Clear();
- // Test that using the auto-restore flag correctly restores the exception
- // state on destruction, and not using the auto-restore flag correctly
- // does NOT restore the state on destruction.
- {
- RaiseException();
- PythonExceptionState error(false);
- EXPECT_TRUE(error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- }
+ PyErr_Clear();
+ {
+ RaiseException();
+ PythonExceptionState error(true);
+ EXPECT_TRUE(error.IsError());
EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ }
+ EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
- PyErr_Clear();
- {
- RaiseException();
- PythonExceptionState error(true);
- EXPECT_TRUE(error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- }
- EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
-
- PyErr_Clear();
+ PyErr_Clear();
}
-TEST_F(PythonExceptionStateTest, TestAutoRestoreChanged)
-{
- // Test that if we re-acquire with different auto-restore semantics,
- // that the new semantics are respected.
- PyErr_Clear();
+TEST_F(PythonExceptionStateTest, TestAutoRestoreChanged) {
+ // Test that if we re-acquire with different auto-restore semantics,
+ // that the new semantics are respected.
+ PyErr_Clear();
- RaiseException();
- PythonExceptionState error(false);
- EXPECT_TRUE(error.IsError());
+ RaiseException();
+ PythonExceptionState error(false);
+ EXPECT_TRUE(error.IsError());
- error.Reset();
- EXPECT_FALSE(error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ error.Reset();
+ EXPECT_FALSE(error.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- RaiseException();
- error.Acquire(true);
- EXPECT_TRUE(error.IsError());
- EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
+ RaiseException();
+ error.Acquire(true);
+ EXPECT_TRUE(error.IsError());
+ EXPECT_FALSE(PythonExceptionState::HasErrorOccurred());
- error.Reset();
- EXPECT_FALSE(error.IsError());
- EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
+ error.Reset();
+ EXPECT_FALSE(error.IsError());
+ EXPECT_TRUE(PythonExceptionState::HasErrorOccurred());
- PyErr_Clear();
+ PyErr_Clear();
}
diff --git a/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
index 5eb1c72598a8..608f3ee45e5e 100644
--- a/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ b/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -7,37 +7,33 @@
//
//===----------------------------------------------------------------------===//
+#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
#include "gtest/gtest.h"
-#include "lldb/Host/HostInfo.h"
-#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
+#include "lldb/Host/HostInfo.h"
#include "PythonTestSuite.h"
using namespace lldb_private;
-void
-PythonTestSuite::SetUp()
-{
- HostInfoBase::Initialize();
- // ScriptInterpreterPython::Initialize() depends on HostInfo being
- // initializedso it can compute the python directory etc.
- ScriptInterpreterPython::Initialize();
- ScriptInterpreterPython::InitializePrivate();
-
- // Although we don't care about concurrency for the purposes of running
- // this test suite, Python requires the GIL to be locked even for
- // deallocating memory, which can happen when you call Py_DECREF or
- // Py_INCREF. So acquire the GIL for the entire duration of this
- // test suite.
- m_gil_state = PyGILState_Ensure();
+void PythonTestSuite::SetUp() {
+ HostInfoBase::Initialize();
+ // ScriptInterpreterPython::Initialize() depends on HostInfo being
+ // initializedso it can compute the python directory etc.
+ ScriptInterpreterPython::Initialize();
+ ScriptInterpreterPython::InitializePrivate();
+
+ // Although we don't care about concurrency for the purposes of running
+ // this test suite, Python requires the GIL to be locked even for
+ // deallocating memory, which can happen when you call Py_DECREF or
+ // Py_INCREF. So acquire the GIL for the entire duration of this
+ // test suite.
+ m_gil_state = PyGILState_Ensure();
}
-void
-PythonTestSuite::TearDown()
-{
- PyGILState_Release(m_gil_state);
+void PythonTestSuite::TearDown() {
+ PyGILState_Release(m_gil_state);
- ScriptInterpreterPython::Terminate();
+ ScriptInterpreterPython::Terminate();
}
diff --git a/unittests/ScriptInterpreter/Python/PythonTestSuite.h b/unittests/ScriptInterpreter/Python/PythonTestSuite.h
index 461fc1d5676c..ad0478875bef 100644
--- a/unittests/ScriptInterpreter/Python/PythonTestSuite.h
+++ b/unittests/ScriptInterpreter/Python/PythonTestSuite.h
@@ -11,16 +11,12 @@
using namespace lldb_private;
-class PythonTestSuite : public testing::Test
-{
+class PythonTestSuite : public testing::Test {
public:
- void
- SetUp() override;
+ void SetUp() override;
- void
- TearDown() override;
+ void TearDown() override;
private:
- PyGILState_STATE m_gil_state;
+ PyGILState_STATE m_gil_state;
};
-
diff --git a/unittests/Symbol/TestClangASTContext.cpp b/unittests/Symbol/TestClangASTContext.cpp
index 3f166ab9cc72..ed49c2657c7a 100644
--- a/unittests/Symbol/TestClangASTContext.cpp
+++ b/unittests/Symbol/TestClangASTContext.cpp
@@ -1,4 +1,5 @@
-//===-- TestClangASTContext.cpp ---------------------------------------*- C++ -*-===//
+//===-- TestClangASTContext.cpp ---------------------------------------*- C++
+//-*-===//
//
// The LLVM Compiler Infrastructure
@@ -20,296 +21,358 @@ using namespace clang;
using namespace lldb;
using namespace lldb_private;
-class TestClangASTContext : public testing::Test
-{
+class TestClangASTContext : public testing::Test {
public:
- static void
- SetUpTestCase()
- {
- HostInfo::Initialize();
- }
-
- static void
- TearDownTestCase()
- {
- HostInfo::Terminate();
- }
-
- virtual void
- SetUp() override
- {
- std::string triple = HostInfo::GetTargetTriple();
- m_ast.reset(new ClangASTContext(triple.c_str()));
- }
-
- virtual void
- TearDown() override
- {
- m_ast.reset();
- }
+ static void SetUpTestCase() { HostInfo::Initialize(); }
+
+ static void TearDownTestCase() { HostInfo::Terminate(); }
+
+ virtual void SetUp() override {
+ std::string triple = HostInfo::GetTargetTriple();
+ m_ast.reset(new ClangASTContext(triple.c_str()));
+ }
+
+ virtual void TearDown() override { m_ast.reset(); }
protected:
- std::unique_ptr<ClangASTContext> m_ast;
-
- QualType
- GetBasicQualType(BasicType type) const
- {
- return ClangUtil::GetQualType(m_ast->GetBasicTypeFromAST(type));
- }
-
- QualType
- GetBasicQualType(const char *name) const
- {
- return ClangUtil::GetQualType(m_ast->GetBuiltinTypeByName(ConstString(name)));
- }
+ std::unique_ptr<ClangASTContext> m_ast;
+
+ QualType GetBasicQualType(BasicType type) const {
+ return ClangUtil::GetQualType(m_ast->GetBasicTypeFromAST(type));
+ }
+
+ QualType GetBasicQualType(const char *name) const {
+ return ClangUtil::GetQualType(
+ m_ast->GetBuiltinTypeByName(ConstString(name)));
+ }
};
-TEST_F(TestClangASTContext, TestGetBasicTypeFromEnum)
-{
- clang::ASTContext *context = m_ast->getASTContext();
-
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeBool), context->BoolTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar), context->CharTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar16), context->Char16Ty));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar32), context->Char32Ty));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeDouble), context->DoubleTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeDoubleComplex), context->DoubleComplexTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeFloat), context->FloatTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeFloatComplex), context->FloatComplexTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeHalf), context->HalfTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeInt), context->IntTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeInt128), context->Int128Ty));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLong), context->LongTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongDouble), context->LongDoubleTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongDoubleComplex), context->LongDoubleComplexTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongLong), context->LongLongTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeNullPtr), context->NullPtrTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCClass), context->getObjCClassType()));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCID), context->getObjCIdType()));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCSel), context->getObjCSelType()));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeShort), context->ShortTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeSignedChar), context->SignedCharTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedChar), context->UnsignedCharTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedInt), context->UnsignedIntTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedInt128), context->UnsignedInt128Ty));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedLong), context->UnsignedLongTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedLongLong), context->UnsignedLongLongTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedShort), context->UnsignedShortTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeVoid), context->VoidTy));
- EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeWChar), context->WCharTy));
+TEST_F(TestClangASTContext, TestGetBasicTypeFromEnum) {
+ clang::ASTContext *context = m_ast->getASTContext();
+
+ EXPECT_TRUE(
+ context->hasSameType(GetBasicQualType(eBasicTypeBool), context->BoolTy));
+ EXPECT_TRUE(
+ context->hasSameType(GetBasicQualType(eBasicTypeChar), context->CharTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar16),
+ context->Char16Ty));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar32),
+ context->Char32Ty));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeDouble),
+ context->DoubleTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeDoubleComplex),
+ context->DoubleComplexTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeFloat),
+ context->FloatTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeFloatComplex),
+ context->FloatComplexTy));
+ EXPECT_TRUE(
+ context->hasSameType(GetBasicQualType(eBasicTypeHalf), context->HalfTy));
+ EXPECT_TRUE(
+ context->hasSameType(GetBasicQualType(eBasicTypeInt), context->IntTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeInt128),
+ context->Int128Ty));
+ EXPECT_TRUE(
+ context->hasSameType(GetBasicQualType(eBasicTypeLong), context->LongTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongDouble),
+ context->LongDoubleTy));
+ EXPECT_TRUE(
+ context->hasSameType(GetBasicQualType(eBasicTypeLongDoubleComplex),
+ context->LongDoubleComplexTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongLong),
+ context->LongLongTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeNullPtr),
+ context->NullPtrTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCClass),
+ context->getObjCClassType()));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCID),
+ context->getObjCIdType()));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCSel),
+ context->getObjCSelType()));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeShort),
+ context->ShortTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeSignedChar),
+ context->SignedCharTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedChar),
+ context->UnsignedCharTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedInt),
+ context->UnsignedIntTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedInt128),
+ context->UnsignedInt128Ty));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedLong),
+ context->UnsignedLongTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedLongLong),
+ context->UnsignedLongLongTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedShort),
+ context->UnsignedShortTy));
+ EXPECT_TRUE(
+ context->hasSameType(GetBasicQualType(eBasicTypeVoid), context->VoidTy));
+ EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeWChar),
+ context->WCharTy));
}
-TEST_F(TestClangASTContext, TestGetBasicTypeFromName)
-{
- EXPECT_EQ(GetBasicQualType(eBasicTypeChar), GetBasicQualType("char"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeSignedChar), GetBasicQualType("signed char"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedChar), GetBasicQualType("unsigned char"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeWChar), GetBasicQualType("wchar_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeSignedWChar), GetBasicQualType("signed wchar_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedWChar), GetBasicQualType("unsigned wchar_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort), GetBasicQualType("unsigned short"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort), GetBasicQualType("unsigned short int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("signed int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt), GetBasicQualType("unsigned int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt), GetBasicQualType("unsigned"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong), GetBasicQualType("unsigned long"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong), GetBasicQualType("unsigned long int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong), GetBasicQualType("long long"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong), GetBasicQualType("long long int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong), GetBasicQualType("unsigned long long"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong), GetBasicQualType("unsigned long long int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt128), GetBasicQualType("__uint128_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeVoid), GetBasicQualType("void"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeBool), GetBasicQualType("bool"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeFloat), GetBasicQualType("float"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeDouble), GetBasicQualType("double"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLongDouble), GetBasicQualType("long double"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeObjCID), GetBasicQualType("id"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeObjCSel), GetBasicQualType("SEL"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeNullPtr), GetBasicQualType("nullptr"));
+TEST_F(TestClangASTContext, TestGetBasicTypeFromName) {
+ EXPECT_EQ(GetBasicQualType(eBasicTypeChar), GetBasicQualType("char"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeSignedChar),
+ GetBasicQualType("signed char"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedChar),
+ GetBasicQualType("unsigned char"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeWChar), GetBasicQualType("wchar_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeSignedWChar),
+ GetBasicQualType("signed wchar_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedWChar),
+ GetBasicQualType("unsigned wchar_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort),
+ GetBasicQualType("unsigned short"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort),
+ GetBasicQualType("unsigned short int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("signed int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt),
+ GetBasicQualType("unsigned int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt),
+ GetBasicQualType("unsigned"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong),
+ GetBasicQualType("unsigned long"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong),
+ GetBasicQualType("unsigned long int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong),
+ GetBasicQualType("long long"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong),
+ GetBasicQualType("long long int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong),
+ GetBasicQualType("unsigned long long"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong),
+ GetBasicQualType("unsigned long long int"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt128),
+ GetBasicQualType("__uint128_t"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeVoid), GetBasicQualType("void"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeBool), GetBasicQualType("bool"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeFloat), GetBasicQualType("float"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeDouble), GetBasicQualType("double"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeLongDouble),
+ GetBasicQualType("long double"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeObjCID), GetBasicQualType("id"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeObjCSel), GetBasicQualType("SEL"));
+ EXPECT_EQ(GetBasicQualType(eBasicTypeNullPtr), GetBasicQualType("nullptr"));
}
-void
-VerifyEncodingAndBitSize(clang::ASTContext *context, lldb::Encoding encoding, int bit_size)
-{
- CompilerType type = ClangASTContext::GetBuiltinTypeForEncodingAndBitSize(context, encoding, bit_size);
- EXPECT_TRUE(type.IsValid());
-
- QualType qtype = ClangUtil::GetQualType(type);
- EXPECT_FALSE(qtype.isNull());
- if (qtype.isNull())
- return;
-
- uint64_t actual_size = context->getTypeSize(qtype);
- EXPECT_EQ(bit_size, actual_size);
-
- const clang::Type *type_ptr = qtype.getTypePtr();
- EXPECT_NE(nullptr, type_ptr);
- if (!type_ptr)
- return;
-
- EXPECT_TRUE(type_ptr->isBuiltinType());
- if (encoding == eEncodingSint)
- EXPECT_TRUE(type_ptr->isSignedIntegerType());
- else if (encoding == eEncodingUint)
- EXPECT_TRUE(type_ptr->isUnsignedIntegerType());
- else if (encoding == eEncodingIEEE754)
- EXPECT_TRUE(type_ptr->isFloatingType());
+void VerifyEncodingAndBitSize(clang::ASTContext *context,
+ lldb::Encoding encoding, unsigned int bit_size) {
+ CompilerType type = ClangASTContext::GetBuiltinTypeForEncodingAndBitSize(
+ context, encoding, bit_size);
+ EXPECT_TRUE(type.IsValid());
+
+ QualType qtype = ClangUtil::GetQualType(type);
+ EXPECT_FALSE(qtype.isNull());
+ if (qtype.isNull())
+ return;
+
+ uint64_t actual_size = context->getTypeSize(qtype);
+ EXPECT_EQ(bit_size, actual_size);
+
+ const clang::Type *type_ptr = qtype.getTypePtr();
+ EXPECT_NE(nullptr, type_ptr);
+ if (!type_ptr)
+ return;
+
+ EXPECT_TRUE(type_ptr->isBuiltinType());
+ if (encoding == eEncodingSint)
+ EXPECT_TRUE(type_ptr->isSignedIntegerType());
+ else if (encoding == eEncodingUint)
+ EXPECT_TRUE(type_ptr->isUnsignedIntegerType());
+ else if (encoding == eEncodingIEEE754)
+ EXPECT_TRUE(type_ptr->isFloatingType());
}
-TEST_F(TestClangASTContext, TestBuiltinTypeForEncodingAndBitSize)
-{
- clang::ASTContext *context = m_ast->getASTContext();
-
- // Make sure we can get types of every possible size in every possible encoding.
- // We can't make any guarantee about which specific type we get, because the standard
- // isn't that specific. We only need to make sure the compiler hands us some type that
- // is both a builtin type and matches the requested bit size.
- VerifyEncodingAndBitSize(context, eEncodingSint, 8);
- VerifyEncodingAndBitSize(context, eEncodingSint, 16);
- VerifyEncodingAndBitSize(context, eEncodingSint, 32);
- VerifyEncodingAndBitSize(context, eEncodingSint, 64);
- VerifyEncodingAndBitSize(context, eEncodingSint, 128);
-
- VerifyEncodingAndBitSize(context, eEncodingUint, 8);
- VerifyEncodingAndBitSize(context, eEncodingUint, 16);
- VerifyEncodingAndBitSize(context, eEncodingUint, 32);
- VerifyEncodingAndBitSize(context, eEncodingUint, 64);
- VerifyEncodingAndBitSize(context, eEncodingUint, 128);
-
- VerifyEncodingAndBitSize(context, eEncodingIEEE754, 32);
- VerifyEncodingAndBitSize(context, eEncodingIEEE754, 64);
+TEST_F(TestClangASTContext, TestBuiltinTypeForEncodingAndBitSize) {
+ clang::ASTContext *context = m_ast->getASTContext();
+
+ // Make sure we can get types of every possible size in every possible
+ // encoding.
+ // We can't make any guarantee about which specific type we get, because the
+ // standard
+ // isn't that specific. We only need to make sure the compiler hands us some
+ // type that
+ // is both a builtin type and matches the requested bit size.
+ VerifyEncodingAndBitSize(context, eEncodingSint, 8);
+ VerifyEncodingAndBitSize(context, eEncodingSint, 16);
+ VerifyEncodingAndBitSize(context, eEncodingSint, 32);
+ VerifyEncodingAndBitSize(context, eEncodingSint, 64);
+ VerifyEncodingAndBitSize(context, eEncodingSint, 128);
+
+ VerifyEncodingAndBitSize(context, eEncodingUint, 8);
+ VerifyEncodingAndBitSize(context, eEncodingUint, 16);
+ VerifyEncodingAndBitSize(context, eEncodingUint, 32);
+ VerifyEncodingAndBitSize(context, eEncodingUint, 64);
+ VerifyEncodingAndBitSize(context, eEncodingUint, 128);
+
+ VerifyEncodingAndBitSize(context, eEncodingIEEE754, 32);
+ VerifyEncodingAndBitSize(context, eEncodingIEEE754, 64);
}
-TEST_F(TestClangASTContext, TestIsClangType)
-{
- clang::ASTContext *context = m_ast->getASTContext();
- lldb::opaque_compiler_type_t bool_ctype = ClangASTContext::GetOpaqueCompilerType(context, lldb::eBasicTypeBool);
- CompilerType bool_type(m_ast.get(), bool_ctype);
- CompilerType record_type = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct,
- lldb::eLanguageTypeC_plus_plus, nullptr);
- // Clang builtin type and record type should pass
- EXPECT_TRUE(ClangUtil::IsClangType(bool_type));
- EXPECT_TRUE(ClangUtil::IsClangType(record_type));
-
- // Default constructed type should fail
- EXPECT_FALSE(ClangUtil::IsClangType(CompilerType()));
-
- // Go type should fail
- GoASTContext go_ast;
- CompilerType go_type(&go_ast, bool_ctype);
- EXPECT_FALSE(ClangUtil::IsClangType(go_type));
+TEST_F(TestClangASTContext, TestIsClangType) {
+ clang::ASTContext *context = m_ast->getASTContext();
+ lldb::opaque_compiler_type_t bool_ctype =
+ ClangASTContext::GetOpaqueCompilerType(context, lldb::eBasicTypeBool);
+ CompilerType bool_type(m_ast.get(), bool_ctype);
+ CompilerType record_type = m_ast->CreateRecordType(
+ nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct,
+ lldb::eLanguageTypeC_plus_plus, nullptr);
+ // Clang builtin type and record type should pass
+ EXPECT_TRUE(ClangUtil::IsClangType(bool_type));
+ EXPECT_TRUE(ClangUtil::IsClangType(record_type));
+
+ // Default constructed type should fail
+ EXPECT_FALSE(ClangUtil::IsClangType(CompilerType()));
+
+ // Go type should fail
+ GoASTContext go_ast;
+ CompilerType go_type(&go_ast, bool_ctype);
+ EXPECT_FALSE(ClangUtil::IsClangType(go_type));
}
-TEST_F(TestClangASTContext, TestRemoveFastQualifiers)
-{
- CompilerType record_type = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct,
- lldb::eLanguageTypeC_plus_plus, nullptr);
- QualType qt;
-
- qt = ClangUtil::GetQualType(record_type);
- EXPECT_EQ(0, qt.getLocalFastQualifiers());
- record_type = record_type.AddConstModifier();
- record_type = record_type.AddVolatileModifier();
- record_type = record_type.AddRestrictModifier();
- qt = ClangUtil::GetQualType(record_type);
- EXPECT_NE(0, qt.getLocalFastQualifiers());
- record_type = ClangUtil::RemoveFastQualifiers(record_type);
- qt = ClangUtil::GetQualType(record_type);
- EXPECT_EQ(0, qt.getLocalFastQualifiers());
+TEST_F(TestClangASTContext, TestRemoveFastQualifiers) {
+ CompilerType record_type = m_ast->CreateRecordType(
+ nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct,
+ lldb::eLanguageTypeC_plus_plus, nullptr);
+ QualType qt;
+
+ qt = ClangUtil::GetQualType(record_type);
+ EXPECT_EQ(0u, qt.getLocalFastQualifiers());
+ record_type = record_type.AddConstModifier();
+ record_type = record_type.AddVolatileModifier();
+ record_type = record_type.AddRestrictModifier();
+ qt = ClangUtil::GetQualType(record_type);
+ EXPECT_NE(0u, qt.getLocalFastQualifiers());
+ record_type = ClangUtil::RemoveFastQualifiers(record_type);
+ qt = ClangUtil::GetQualType(record_type);
+ EXPECT_EQ(0u, qt.getLocalFastQualifiers());
}
-TEST_F(TestClangASTContext, TestConvertAccessTypeToAccessSpecifier)
-{
- EXPECT_EQ(AS_none, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessNone));
- EXPECT_EQ(AS_none, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPackage));
- EXPECT_EQ(AS_public, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPublic));
- EXPECT_EQ(AS_private, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPrivate));
- EXPECT_EQ(AS_protected, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessProtected));
+TEST_F(TestClangASTContext, TestConvertAccessTypeToAccessSpecifier) {
+ EXPECT_EQ(AS_none,
+ ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessNone));
+ EXPECT_EQ(AS_none, ClangASTContext::ConvertAccessTypeToAccessSpecifier(
+ eAccessPackage));
+ EXPECT_EQ(AS_public,
+ ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPublic));
+ EXPECT_EQ(AS_private, ClangASTContext::ConvertAccessTypeToAccessSpecifier(
+ eAccessPrivate));
+ EXPECT_EQ(AS_protected, ClangASTContext::ConvertAccessTypeToAccessSpecifier(
+ eAccessProtected));
}
-TEST_F(TestClangASTContext, TestUnifyAccessSpecifiers)
-{
- // Unifying two of the same type should return the same type
- EXPECT_EQ(AS_public, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_public));
- EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_private));
- EXPECT_EQ(AS_protected, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_protected));
-
- // Otherwise the result should be the strictest of the two.
- EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_public));
- EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_protected));
- EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_private));
- EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_private));
- EXPECT_EQ(AS_protected, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_public));
- EXPECT_EQ(AS_protected, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_protected));
-
- // None is stricter than everything (by convention)
- EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_public));
- EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_protected));
- EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_private));
- EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_none));
- EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_none));
- EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_none));
+TEST_F(TestClangASTContext, TestUnifyAccessSpecifiers) {
+ // Unifying two of the same type should return the same type
+ EXPECT_EQ(AS_public,
+ ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_public));
+ EXPECT_EQ(AS_private,
+ ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_private));
+ EXPECT_EQ(AS_protected,
+ ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_protected));
+
+ // Otherwise the result should be the strictest of the two.
+ EXPECT_EQ(AS_private,
+ ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_public));
+ EXPECT_EQ(AS_private,
+ ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_protected));
+ EXPECT_EQ(AS_private,
+ ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_private));
+ EXPECT_EQ(AS_private,
+ ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_private));
+ EXPECT_EQ(AS_protected,
+ ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_public));
+ EXPECT_EQ(AS_protected,
+ ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_protected));
+
+ // None is stricter than everything (by convention)
+ EXPECT_EQ(AS_none,
+ ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_public));
+ EXPECT_EQ(AS_none,
+ ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_protected));
+ EXPECT_EQ(AS_none,
+ ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_private));
+ EXPECT_EQ(AS_none,
+ ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_none));
+ EXPECT_EQ(AS_none,
+ ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_none));
+ EXPECT_EQ(AS_none,
+ ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_none));
}
-TEST_F(TestClangASTContext, TestRecordHasFields)
-{
- CompilerType int_type = ClangASTContext::GetBasicType(m_ast->getASTContext(), eBasicTypeInt);
-
- // Test that a record with no fields returns false
- CompilerType empty_base = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "EmptyBase", clang::TTK_Struct,
- lldb::eLanguageTypeC_plus_plus, nullptr);
- ClangASTContext::StartTagDeclarationDefinition(empty_base);
- ClangASTContext::CompleteTagDeclarationDefinition(empty_base);
-
- RecordDecl *empty_base_decl = ClangASTContext::GetAsRecordDecl(empty_base);
- EXPECT_NE(nullptr, empty_base_decl);
- EXPECT_FALSE(ClangASTContext::RecordHasFields(empty_base_decl));
-
- // Test that a record with direct fields returns true
- CompilerType non_empty_base = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "NonEmptyBase",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- ClangASTContext::StartTagDeclarationDefinition(non_empty_base);
- FieldDecl *non_empty_base_field_decl =
- m_ast->AddFieldToRecordType(non_empty_base, "MyField", int_type, eAccessPublic, 0);
- ClangASTContext::CompleteTagDeclarationDefinition(non_empty_base);
- RecordDecl *non_empty_base_decl = ClangASTContext::GetAsRecordDecl(non_empty_base);
- EXPECT_NE(nullptr, non_empty_base_decl);
- EXPECT_NE(nullptr, non_empty_base_field_decl);
- EXPECT_TRUE(ClangASTContext::RecordHasFields(non_empty_base_decl));
-
- // Test that a record with no direct fields, but fields in a base returns true
- CompilerType empty_derived = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "EmptyDerived",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- ClangASTContext::StartTagDeclarationDefinition(empty_derived);
- CXXBaseSpecifier *non_empty_base_spec =
- m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), lldb::eAccessPublic, false, false);
- bool result = m_ast->SetBaseClassesForClassType(empty_derived.GetOpaqueQualType(), &non_empty_base_spec, 1);
- ClangASTContext::CompleteTagDeclarationDefinition(empty_derived);
- EXPECT_TRUE(result);
- CXXRecordDecl *empty_derived_non_empty_base_cxx_decl = m_ast->GetAsCXXRecordDecl(empty_derived.GetOpaqueQualType());
- RecordDecl *empty_derived_non_empty_base_decl = ClangASTContext::GetAsRecordDecl(empty_derived);
- EXPECT_EQ(1, ClangASTContext::GetNumBaseClasses(empty_derived_non_empty_base_cxx_decl, false));
- EXPECT_TRUE(ClangASTContext::RecordHasFields(empty_derived_non_empty_base_decl));
-
- // Test that a record with no direct fields, but fields in a virtual base returns true
- CompilerType empty_derived2 = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "EmptyDerived2",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- ClangASTContext::StartTagDeclarationDefinition(empty_derived2);
- CXXBaseSpecifier *non_empty_vbase_spec =
- m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), lldb::eAccessPublic, true, false);
- result = m_ast->SetBaseClassesForClassType(empty_derived2.GetOpaqueQualType(), &non_empty_vbase_spec, 1);
- ClangASTContext::CompleteTagDeclarationDefinition(empty_derived2);
- EXPECT_TRUE(result);
- CXXRecordDecl *empty_derived_non_empty_vbase_cxx_decl =
- m_ast->GetAsCXXRecordDecl(empty_derived2.GetOpaqueQualType());
- RecordDecl *empty_derived_non_empty_vbase_decl = ClangASTContext::GetAsRecordDecl(empty_derived2);
- EXPECT_EQ(1, ClangASTContext::GetNumBaseClasses(empty_derived_non_empty_vbase_cxx_decl, false));
- EXPECT_TRUE(ClangASTContext::RecordHasFields(empty_derived_non_empty_vbase_decl));
+TEST_F(TestClangASTContext, TestRecordHasFields) {
+ CompilerType int_type =
+ ClangASTContext::GetBasicType(m_ast->getASTContext(), eBasicTypeInt);
+
+ // Test that a record with no fields returns false
+ CompilerType empty_base = m_ast->CreateRecordType(
+ nullptr, lldb::eAccessPublic, "EmptyBase", clang::TTK_Struct,
+ lldb::eLanguageTypeC_plus_plus, nullptr);
+ ClangASTContext::StartTagDeclarationDefinition(empty_base);
+ ClangASTContext::CompleteTagDeclarationDefinition(empty_base);
+
+ RecordDecl *empty_base_decl = ClangASTContext::GetAsRecordDecl(empty_base);
+ EXPECT_NE(nullptr, empty_base_decl);
+ EXPECT_FALSE(ClangASTContext::RecordHasFields(empty_base_decl));
+
+ // Test that a record with direct fields returns true
+ CompilerType non_empty_base = m_ast->CreateRecordType(
+ nullptr, lldb::eAccessPublic, "NonEmptyBase", clang::TTK_Struct,
+ lldb::eLanguageTypeC_plus_plus, nullptr);
+ ClangASTContext::StartTagDeclarationDefinition(non_empty_base);
+ FieldDecl *non_empty_base_field_decl = m_ast->AddFieldToRecordType(
+ non_empty_base, "MyField", int_type, eAccessPublic, 0);
+ ClangASTContext::CompleteTagDeclarationDefinition(non_empty_base);
+ RecordDecl *non_empty_base_decl =
+ ClangASTContext::GetAsRecordDecl(non_empty_base);
+ EXPECT_NE(nullptr, non_empty_base_decl);
+ EXPECT_NE(nullptr, non_empty_base_field_decl);
+ EXPECT_TRUE(ClangASTContext::RecordHasFields(non_empty_base_decl));
+
+ // Test that a record with no direct fields, but fields in a base returns true
+ CompilerType empty_derived = m_ast->CreateRecordType(
+ nullptr, lldb::eAccessPublic, "EmptyDerived", clang::TTK_Struct,
+ lldb::eLanguageTypeC_plus_plus, nullptr);
+ ClangASTContext::StartTagDeclarationDefinition(empty_derived);
+ CXXBaseSpecifier *non_empty_base_spec = m_ast->CreateBaseClassSpecifier(
+ non_empty_base.GetOpaqueQualType(), lldb::eAccessPublic, false, false);
+ bool result = m_ast->SetBaseClassesForClassType(
+ empty_derived.GetOpaqueQualType(), &non_empty_base_spec, 1);
+ ClangASTContext::CompleteTagDeclarationDefinition(empty_derived);
+ EXPECT_TRUE(result);
+ CXXRecordDecl *empty_derived_non_empty_base_cxx_decl =
+ m_ast->GetAsCXXRecordDecl(empty_derived.GetOpaqueQualType());
+ RecordDecl *empty_derived_non_empty_base_decl =
+ ClangASTContext::GetAsRecordDecl(empty_derived);
+ EXPECT_EQ(1u, ClangASTContext::GetNumBaseClasses(
+ empty_derived_non_empty_base_cxx_decl, false));
+ EXPECT_TRUE(
+ ClangASTContext::RecordHasFields(empty_derived_non_empty_base_decl));
+
+ // Test that a record with no direct fields, but fields in a virtual base
+ // returns true
+ CompilerType empty_derived2 = m_ast->CreateRecordType(
+ nullptr, lldb::eAccessPublic, "EmptyDerived2", clang::TTK_Struct,
+ lldb::eLanguageTypeC_plus_plus, nullptr);
+ ClangASTContext::StartTagDeclarationDefinition(empty_derived2);
+ CXXBaseSpecifier *non_empty_vbase_spec = m_ast->CreateBaseClassSpecifier(
+ non_empty_base.GetOpaqueQualType(), lldb::eAccessPublic, true, false);
+ result = m_ast->SetBaseClassesForClassType(empty_derived2.GetOpaqueQualType(),
+ &non_empty_vbase_spec, 1);
+ ClangASTContext::CompleteTagDeclarationDefinition(empty_derived2);
+ EXPECT_TRUE(result);
+ CXXRecordDecl *empty_derived_non_empty_vbase_cxx_decl =
+ m_ast->GetAsCXXRecordDecl(empty_derived2.GetOpaqueQualType());
+ RecordDecl *empty_derived_non_empty_vbase_decl =
+ ClangASTContext::GetAsRecordDecl(empty_derived2);
+ EXPECT_EQ(1u, ClangASTContext::GetNumBaseClasses(
+ empty_derived_non_empty_vbase_cxx_decl, false));
+ EXPECT_TRUE(
+ ClangASTContext::RecordHasFields(empty_derived_non_empty_vbase_decl));
}
diff --git a/unittests/SymbolFile/CMakeLists.txt b/unittests/SymbolFile/CMakeLists.txt
index dcf9ebdb1161..cc12e467905a 100644
--- a/unittests/SymbolFile/CMakeLists.txt
+++ b/unittests/SymbolFile/CMakeLists.txt
@@ -1 +1,4 @@
-add_subdirectory(PDB)
+add_subdirectory(DWARF)
+if (LLVM_ENABLE_DIA_SDK)
+ add_subdirectory(PDB)
+endif()
diff --git a/unittests/SymbolFile/DWARF/CMakeLists.txt b/unittests/SymbolFile/DWARF/CMakeLists.txt
new file mode 100644
index 000000000000..c0e4300dadd7
--- /dev/null
+++ b/unittests/SymbolFile/DWARF/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_lldb_unittest(SymbolFileDWARFTests
+ SymbolFileDWARFTests.cpp
+ )
+
+set(test_inputs
+ test-dwarf.exe)
+
+add_unittest_inputs(SymbolFileDWARFTests "${test_inputs}")
diff --git a/unittests/SymbolFile/PDB/Inputs/test-dwarf.cpp b/unittests/SymbolFile/DWARF/Inputs/test-dwarf.cpp
index f86ff3d875b4..a987e6a9a363 100644
--- a/unittests/SymbolFile/PDB/Inputs/test-dwarf.cpp
+++ b/unittests/SymbolFile/DWARF/Inputs/test-dwarf.cpp
@@ -1,14 +1,6 @@
// Compile with "cl /c /Zi /GR- test.cpp"
// Link with "link test.obj /debug /nodefaultlib /entry:main /out:test.exe"
-int __cdecl _purecall(void)
-{
- return 0;
-}
+int __cdecl _purecall(void) { return 0; }
-int
-main(int argc, char **argv)
-{
-
- return 0;
-}
+int main(int argc, char **argv) { return 0; }
diff --git a/unittests/SymbolFile/PDB/Inputs/test-dwarf.exe b/unittests/SymbolFile/DWARF/Inputs/test-dwarf.exe
index 15e1910b4b8b..15e1910b4b8b 100644
--- a/unittests/SymbolFile/PDB/Inputs/test-dwarf.exe
+++ b/unittests/SymbolFile/DWARF/Inputs/test-dwarf.exe
Binary files differ
diff --git a/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp b/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp
new file mode 100644
index 000000000000..10465d785ac9
--- /dev/null
+++ b/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp
@@ -0,0 +1,83 @@
+//===-- PythonDataObjectsTests.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
+
+extern const char *TestMainArgv0;
+
+using namespace lldb_private;
+
+class SymbolFileDWARFTests : public testing::Test {
+public:
+ void SetUp() override {
+// Initialize and TearDown the plugin every time, so we get a brand new
+// AST every time so that modifications to the AST from each test don't
+// leak into the next test.
+ HostInfo::Initialize();
+ ObjectFilePECOFF::Initialize();
+ SymbolFileDWARF::Initialize();
+ ClangASTContext::Initialize();
+ SymbolFilePDB::Initialize();
+
+ llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0);
+ llvm::SmallString<128> inputs_folder = exe_folder;
+ llvm::sys::path::append(inputs_folder, "Inputs");
+
+ m_dwarf_test_exe = inputs_folder;
+ llvm::sys::path::append(m_dwarf_test_exe, "test-dwarf.exe");
+ }
+
+ void TearDown() override {
+ SymbolFilePDB::Terminate();
+ ClangASTContext::Initialize();
+ SymbolFileDWARF::Terminate();
+ ObjectFilePECOFF::Terminate();
+ HostInfo::Terminate();
+ }
+
+protected:
+ llvm::SmallString<128> m_dwarf_test_exe;
+};
+
+TEST_F(SymbolFileDWARFTests, TestAbilitiesForDWARF) {
+ // Test that when we have Dwarf debug info, SymbolFileDWARF is used.
+ FileSpec fspec(m_dwarf_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+ EXPECT_NE(nullptr, symfile);
+ EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic());
+
+ uint32_t expected_abilities = SymbolFile::kAllAbilities;
+ EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
+}
diff --git a/unittests/SymbolFile/PDB/CMakeLists.txt b/unittests/SymbolFile/PDB/CMakeLists.txt
index fcfb5e3062c9..37adf39463d4 100644
--- a/unittests/SymbolFile/PDB/CMakeLists.txt
+++ b/unittests/SymbolFile/PDB/CMakeLists.txt
@@ -5,8 +5,7 @@ add_lldb_unittest(SymbolFilePDBTests
set(test_inputs
test-pdb.exe
test-pdb.pdb
- test-dwarf.exe
test-pdb-types.exe
test-pdb-types.pdb)
-add_unittest_inputs(SymbolFilePDBTests "${test_inputs}")
+add_unittest_inputs(SymbolFilePDBTests "${test_inputs}")
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp b/unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp
index d36f15e53fb7..33d7df0e4a82 100644
--- a/unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp
@@ -1,9 +1,7 @@
// Compile with "cl /c /Zi /GR- test-pdb-alt.cpp"
-// Link with "link test-pdb.obj test-pdb-alt.obj /debug /nodefaultlib /entry:main /out:test-pdb.exe"
+// Link with "link test-pdb.obj test-pdb-alt.obj /debug /nodefaultlib
+// /entry:main /out:test-pdb.exe"
#include "test-pdb.h"
-int bar(int n)
-{
- return n-1;
-}
+int bar(int n) { return n - 1; }
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h b/unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h
index fc63b50d13c9..d0a93d8f39e8 100644
--- a/unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h
@@ -1,9 +1,6 @@
#ifndef TEST_PDB_NESTED_H
#define TEST_PDB_NESTED_H
-inline int baz(int n)
-{
- return n+1;
-}
+inline int baz(int n) { return n + 1; }
#endif \ No newline at end of file
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp b/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp
index 9639a3f4b722..89d69c12963e 100644
--- a/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp
@@ -1,5 +1,6 @@
// Compile with "cl /c /Zi /GR- /EHsc test-pdb-types.cpp"
-// Link with "link test-pdb-types.obj /debug /nodefaultlib /entry:main /out:test-pdb-types.exe"
+// Link with "link test-pdb-types.obj /debug /nodefaultlib /entry:main
+// /out:test-pdb-types.exe"
using namespace std;
@@ -21,42 +22,29 @@ static const int sizeof_double = sizeof(double);
static const int sizeof_bool = sizeof(bool);
static const int sizeof_wchar = sizeof(wchar_t);
-enum Enum
-{
- EValue1 = 1,
- EValue2 = 2,
+enum Enum {
+ EValue1 = 1,
+ EValue2 = 2,
};
-enum ShortEnum : short
-{
- ESValue1 = 1,
- ESValue2 = 2
-};
+enum ShortEnum : short { ESValue1 = 1, ESValue2 = 2 };
-namespace NS
-{
-class NSClass
-{
- float f;
- double d;
+namespace NS {
+class NSClass {
+ float f;
+ double d;
};
}
-class Class
-{
+class Class {
public:
- class NestedClass
- {
- Enum e;
- };
- ShortEnum se;
+ class NestedClass {
+ Enum e;
+ };
+ ShortEnum se;
};
-int
-test_func(int a, int b)
-{
- return a + b;
-}
+int test_func(int a, int b) { return a + b; }
typedef Class ClassTypedef;
typedef NS::NSClass NSClassTypedef;
@@ -71,16 +59,14 @@ static const int sizeof_ClassTypedef = sizeof(ClassTypedef);
static const int sizeof_NSClassTypedef = sizeof(NSClassTypedef);
static const int sizeof_GlobalArray = sizeof(GlobalArray);
-int
-main(int argc, char **argv)
-{
- ShortEnum e1;
- Enum e2;
- Class c1;
- Class::NestedClass c2;
- NS::NSClass c3;
+int main(int argc, char **argv) {
+ ShortEnum e1;
+ Enum e2;
+ Class c1;
+ Class::NestedClass c2;
+ NS::NSClass c3;
- ClassTypedef t1;
- NSClassTypedef t2;
- return test_func(1, 2);
+ ClassTypedef t1;
+ NSClassTypedef t2;
+ return test_func(1, 2);
}
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb.cpp b/unittests/SymbolFile/PDB/Inputs/test-pdb.cpp
index c9bf057cfbfb..77956acd8750 100644
--- a/unittests/SymbolFile/PDB/Inputs/test-pdb.cpp
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb.cpp
@@ -1,15 +1,9 @@
// Compile with "cl /c /Zi /GR- test-pdb.cpp"
-// Link with "link test-pdb.obj /debug /nodefaultlib /entry:main /out:test-pdb.exe"
+// Link with "link test-pdb.obj /debug /nodefaultlib /entry:main
+// /out:test-pdb.exe"
#include "test-pdb.h"
-int __cdecl _purecall(void)
-{
- return 0;
-}
+int __cdecl _purecall(void) { return 0; }
-int
-main(int argc, char **argv)
-{
- return foo(argc) + bar(argc);
-}
+int main(int argc, char **argv) { return foo(argc) + bar(argc); }
diff --git a/unittests/SymbolFile/PDB/Inputs/test-pdb.h b/unittests/SymbolFile/PDB/Inputs/test-pdb.h
index 273343bb03b0..077d9d6b1fac 100644
--- a/unittests/SymbolFile/PDB/Inputs/test-pdb.h
+++ b/unittests/SymbolFile/PDB/Inputs/test-pdb.h
@@ -5,9 +5,6 @@
int bar(int n);
-inline int foo(int n)
-{
- return baz(n)+1;
-}
+inline int foo(int n) { return baz(n) + 1; }
#endif \ No newline at end of file
diff --git a/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp b/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp
index b303ae7bac4b..5aedffecfe90 100644
--- a/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp
+++ b/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp
@@ -10,7 +10,6 @@
#include "gtest/gtest.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Config/config.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/Support/FileSystem.h"
@@ -42,542 +41,535 @@ extern const char *TestMainArgv0;
using namespace lldb_private;
-class SymbolFilePDBTests : public testing::Test
-{
+class SymbolFilePDBTests : public testing::Test {
public:
- void
- SetUp() override
- {
+ void SetUp() override {
// Initialize and TearDown the plugin every time, so we get a brand new
// AST every time so that modifications to the AST from each test don't
// leak into the next test.
#if defined(_MSC_VER)
- ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+ ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
#endif
- HostInfo::Initialize();
- ObjectFilePECOFF::Initialize();
- SymbolFileDWARF::Initialize();
- ClangASTContext::Initialize();
- SymbolFilePDB::Initialize();
-
- llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0);
- llvm::SmallString<128> inputs_folder = exe_folder;
- llvm::sys::path::append(inputs_folder, "Inputs");
-
- m_pdb_test_exe = inputs_folder;
- m_dwarf_test_exe = inputs_folder;
- m_types_test_exe = inputs_folder;
- llvm::sys::path::append(m_pdb_test_exe, "test-pdb.exe");
- llvm::sys::path::append(m_dwarf_test_exe, "test-dwarf.exe");
- llvm::sys::path::append(m_types_test_exe, "test-pdb-types.exe");
- }
-
- void
- TearDown() override
- {
- SymbolFilePDB::Terminate();
- ClangASTContext::Initialize();
- SymbolFileDWARF::Terminate();
- ObjectFilePECOFF::Terminate();
- HostInfo::Terminate();
+ HostInfo::Initialize();
+ ObjectFilePECOFF::Initialize();
+ SymbolFileDWARF::Initialize();
+ ClangASTContext::Initialize();
+ SymbolFilePDB::Initialize();
+
+ llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0);
+ llvm::SmallString<128> inputs_folder = exe_folder;
+ llvm::sys::path::append(inputs_folder, "Inputs");
+
+ m_pdb_test_exe = inputs_folder;
+ m_types_test_exe = inputs_folder;
+ llvm::sys::path::append(m_pdb_test_exe, "test-pdb.exe");
+ llvm::sys::path::append(m_types_test_exe, "test-pdb-types.exe");
+ }
+
+ void TearDown() override {
+ SymbolFilePDB::Terminate();
+ ClangASTContext::Initialize();
+ SymbolFileDWARF::Terminate();
+ ObjectFilePECOFF::Terminate();
+ HostInfo::Terminate();
#if defined(_MSC_VER)
- ::CoUninitialize();
+ ::CoUninitialize();
#endif
- }
+ }
protected:
- llvm::SmallString<128> m_pdb_test_exe;
- llvm::SmallString<128> m_dwarf_test_exe;
- llvm::SmallString<128> m_types_test_exe;
-
- bool
- FileSpecMatchesAsBaseOrFull(const FileSpec &left, const FileSpec &right) const
- {
- // If the filenames don't match, the paths can't be equal
- if (!left.FileEquals(right))
- return false;
- // If BOTH have a directory, also compare the directories.
- if (left.GetDirectory() && right.GetDirectory())
- return left.DirectoryEquals(right);
-
- // If one has a directory but not the other, they match.
+ llvm::SmallString<128> m_pdb_test_exe;
+ llvm::SmallString<128> m_types_test_exe;
+
+ bool FileSpecMatchesAsBaseOrFull(const FileSpec &left,
+ const FileSpec &right) const {
+ // If the filenames don't match, the paths can't be equal
+ if (!left.FileEquals(right))
+ return false;
+ // If BOTH have a directory, also compare the directories.
+ if (left.GetDirectory() && right.GetDirectory())
+ return left.DirectoryEquals(right);
+
+ // If one has a directory but not the other, they match.
+ return true;
+ }
+
+ void VerifyLineEntry(lldb::ModuleSP module, const SymbolContext &sc,
+ const FileSpec &spec, LineTable &lt, uint32_t line,
+ lldb::addr_t addr) {
+ LineEntry entry;
+ Address address;
+ EXPECT_TRUE(module->ResolveFileAddress(addr, address));
+
+ EXPECT_TRUE(lt.FindLineEntryByAddress(address, entry));
+ EXPECT_EQ(line, entry.line);
+ EXPECT_EQ(address, entry.range.GetBaseAddress());
+
+ EXPECT_TRUE(FileSpecMatchesAsBaseOrFull(spec, entry.file));
+ }
+
+ bool ContainsCompileUnit(const SymbolContextList &sc_list,
+ const FileSpec &spec) const {
+ for (size_t i = 0; i < sc_list.GetSize(); ++i) {
+ const SymbolContext &sc = sc_list[i];
+ if (FileSpecMatchesAsBaseOrFull(*sc.comp_unit, spec))
return true;
}
-
- void
- VerifyLineEntry(lldb::ModuleSP module, const SymbolContext &sc, const FileSpec &spec, LineTable &lt, uint32_t line,
- lldb::addr_t addr)
- {
- LineEntry entry;
- Address address;
- EXPECT_TRUE(module->ResolveFileAddress(addr, address));
-
- EXPECT_TRUE(lt.FindLineEntryByAddress(address, entry));
- EXPECT_EQ(line, entry.line);
- EXPECT_EQ(address, entry.range.GetBaseAddress());
-
- EXPECT_TRUE(FileSpecMatchesAsBaseOrFull(spec, entry.file));
- }
-
- bool
- ContainsCompileUnit(const SymbolContextList &sc_list, const FileSpec &spec) const
- {
- for (size_t i = 0; i < sc_list.GetSize(); ++i)
- {
- const SymbolContext &sc = sc_list[i];
- if (FileSpecMatchesAsBaseOrFull(*sc.comp_unit, spec))
- return true;
- }
- return false;
- }
-
- int
- GetGlobalConstantInteger(const llvm::pdb::IPDBSession &session, llvm::StringRef var) const
- {
- auto global = session.getGlobalScope();
- auto results =
- global->findChildren(llvm::pdb::PDB_SymType::Data, var, llvm::pdb::PDB_NameSearchFlags::NS_Default);
- uint32_t count = results->getChildCount();
- if (count == 0)
- return -1;
-
- auto item = results->getChildAtIndex(0);
- auto symbol = llvm::dyn_cast<llvm::pdb::PDBSymbolData>(item.get());
- if (!symbol)
- return -1;
- llvm::pdb::Variant value = symbol->getValue();
- switch (value.Type)
- {
- case llvm::pdb::PDB_VariantType::Int16:
- return value.Value.Int16;
- case llvm::pdb::PDB_VariantType::Int32:
- return value.Value.Int32;
- case llvm::pdb::PDB_VariantType::UInt16:
- return value.Value.UInt16;
- case llvm::pdb::PDB_VariantType::UInt32:
- return value.Value.UInt32;
- default:
- return 0;
- }
+ return false;
+ }
+
+ uint64_t GetGlobalConstantInteger(const llvm::pdb::IPDBSession &session,
+ llvm::StringRef var) const {
+ auto global = session.getGlobalScope();
+ auto results =
+ global->findChildren(llvm::pdb::PDB_SymType::Data, var,
+ llvm::pdb::PDB_NameSearchFlags::NS_Default);
+ uint32_t count = results->getChildCount();
+ if (count == 0)
+ return -1;
+
+ auto item = results->getChildAtIndex(0);
+ auto symbol = llvm::dyn_cast<llvm::pdb::PDBSymbolData>(item.get());
+ if (!symbol)
+ return -1;
+ llvm::pdb::Variant value = symbol->getValue();
+ switch (value.Type) {
+ case llvm::pdb::PDB_VariantType::Int16:
+ return value.Value.Int16;
+ case llvm::pdb::PDB_VariantType::Int32:
+ return value.Value.Int32;
+ case llvm::pdb::PDB_VariantType::UInt16:
+ return value.Value.UInt16;
+ case llvm::pdb::PDB_VariantType::UInt32:
+ return value.Value.UInt32;
+ default:
+ return 0;
}
+ }
};
-#if defined(HAVE_DIA_SDK)
-#define REQUIRES_DIA_SDK(TestName) TestName
-#else
-#define REQUIRES_DIA_SDK(TestName) DISABLED_##TestName
-#endif
-
-TEST_F(SymbolFilePDBTests, TestAbilitiesForDWARF)
-{
- // Test that when we have Dwarf debug info, SymbolFileDWARF is used.
- FileSpec fspec(m_dwarf_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- EXPECT_NE(nullptr, plugin);
- SymbolFile *symfile = plugin->GetSymbolFile();
- EXPECT_NE(nullptr, symfile);
- EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic());
-
- uint32_t expected_abilities = SymbolFile::kAllAbilities;
- EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
+TEST_F(SymbolFilePDBTests, TestAbilitiesForPDB) {
+ // Test that when we have PDB debug info, SymbolFilePDB is used.
+ FileSpec fspec(m_pdb_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+ EXPECT_NE(nullptr, symfile);
+ EXPECT_EQ(symfile->GetPluginName(), SymbolFilePDB::GetPluginNameStatic());
+
+ uint32_t expected_abilities =
+ SymbolFile::CompileUnits | SymbolFile::LineTables;
+ EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestAbilitiesForPDB))
-{
- // Test that when we have PDB debug info, SymbolFilePDB is used.
- FileSpec fspec(m_pdb_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- EXPECT_NE(nullptr, plugin);
- SymbolFile *symfile = plugin->GetSymbolFile();
- EXPECT_NE(nullptr, symfile);
- EXPECT_EQ(symfile->GetPluginName(), SymbolFilePDB::GetPluginNameStatic());
-
- uint32_t expected_abilities = SymbolFile::CompileUnits | SymbolFile::LineTables;
- EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
+TEST_F(SymbolFilePDBTests, TestResolveSymbolContextBasename) {
+ // Test that attempting to call ResolveSymbolContext with only a basename
+ // finds all full paths
+ // with the same basename
+ FileSpec fspec(m_pdb_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec header_spec("test-pdb.cpp", false);
+ SymbolContextList sc_list;
+ uint32_t result_count = symfile->ResolveSymbolContext(
+ header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
+ EXPECT_EQ(1u, result_count);
+ EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestResolveSymbolContextBasename))
-{
- // Test that attempting to call ResolveSymbolContext with only a basename finds all full paths
- // with the same basename
- FileSpec fspec(m_pdb_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- EXPECT_NE(nullptr, plugin);
- SymbolFile *symfile = plugin->GetSymbolFile();
+TEST_F(SymbolFilePDBTests, TestResolveSymbolContextFullPath) {
+ // Test that attempting to call ResolveSymbolContext with a full path only
+ // finds the one source
+ // file that matches the full path.
+ FileSpec fspec(m_pdb_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec header_spec(
+ R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec",
+ false);
+ SymbolContextList sc_list;
+ uint32_t result_count = symfile->ResolveSymbolContext(
+ header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
+ EXPECT_GE(1u, result_count);
+ EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
+}
- FileSpec header_spec("test-pdb.cpp", false);
+TEST_F(SymbolFilePDBTests,
+ TestLookupOfHeaderFileWithInlines) {
+ // Test that when looking up a header file via ResolveSymbolContext (i.e. a
+ // file that was not by itself
+ // compiled, but only contributes to the combined code of other source files),
+ // a SymbolContext is returned
+ // for each compiland which has line contributions from the requested header.
+ FileSpec fspec(m_pdb_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec header_specs[] = {FileSpec("test-pdb.h", false),
+ FileSpec("test-pdb-nested.h", false)};
+ FileSpec main_cpp_spec("test-pdb.cpp", false);
+ FileSpec alt_cpp_spec("test-pdb-alt.cpp", false);
+ for (const auto &hspec : header_specs) {
SymbolContextList sc_list;
- uint32_t result_count = symfile->ResolveSymbolContext(header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
- EXPECT_EQ(1u, result_count);
- EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
+ uint32_t result_count = symfile->ResolveSymbolContext(
+ hspec, 0, true, lldb::eSymbolContextCompUnit, sc_list);
+ EXPECT_EQ(2u, result_count);
+ EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec));
+ EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec));
+ }
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestResolveSymbolContextFullPath))
-{
- // Test that attempting to call ResolveSymbolContext with a full path only finds the one source
- // file that matches the full path.
- FileSpec fspec(m_pdb_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- EXPECT_NE(nullptr, plugin);
- SymbolFile *symfile = plugin->GetSymbolFile();
-
- FileSpec header_spec(R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec", false);
+TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithNoInlines) {
+ // Test that when looking up a header file via ResolveSymbolContext (i.e. a
+ // file that was not by itself
+ // compiled, but only contributes to the combined code of other source files),
+ // that if check_inlines
+ // is false, no SymbolContexts are returned.
+ FileSpec fspec(m_pdb_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ EXPECT_NE(nullptr, plugin);
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec header_specs[] = {FileSpec("test-pdb.h", false),
+ FileSpec("test-pdb-nested.h", false)};
+ for (const auto &hspec : header_specs) {
SymbolContextList sc_list;
- uint32_t result_count = symfile->ResolveSymbolContext(header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
- EXPECT_GE(1u, result_count);
- EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
+ uint32_t result_count = symfile->ResolveSymbolContext(
+ hspec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
+ EXPECT_EQ(0u, result_count);
+ }
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLookupOfHeaderFileWithInlines))
-{
- // Test that when looking up a header file via ResolveSymbolContext (i.e. a file that was not by itself
- // compiled, but only contributes to the combined code of other source files), a SymbolContext is returned
- // for each compiland which has line contributions from the requested header.
- FileSpec fspec(m_pdb_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- EXPECT_NE(nullptr, plugin);
- SymbolFile *symfile = plugin->GetSymbolFile();
-
- FileSpec header_specs[] = {FileSpec("test-pdb.h", false), FileSpec("test-pdb-nested.h", false)};
- FileSpec main_cpp_spec("test-pdb.cpp", false);
- FileSpec alt_cpp_spec("test-pdb-alt.cpp", false);
- for (const auto &hspec : header_specs)
- {
- SymbolContextList sc_list;
- uint32_t result_count = symfile->ResolveSymbolContext(hspec, 0, true, lldb::eSymbolContextCompUnit, sc_list);
- EXPECT_EQ(2u, result_count);
- EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec));
- EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec));
- }
+TEST_F(SymbolFilePDBTests, TestLineTablesMatchAll) {
+ // Test that when calling ResolveSymbolContext with a line number of 0, all
+ // line entries from
+ // the specified files are returned.
+ FileSpec fspec(m_pdb_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec source_file("test-pdb.cpp", false);
+ FileSpec header1("test-pdb.h", false);
+ FileSpec header2("test-pdb-nested.h", false);
+ uint32_t cus = symfile->GetNumCompileUnits();
+ EXPECT_EQ(2u, cus);
+
+ SymbolContextList sc_list;
+ uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
+
+ uint32_t count =
+ symfile->ResolveSymbolContext(source_file, 0, true, scope, sc_list);
+ EXPECT_EQ(1u, count);
+ SymbolContext sc;
+ EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
+
+ LineTable *lt = sc.comp_unit->GetLineTable();
+ EXPECT_NE(nullptr, lt);
+ count = lt->GetSize();
+ // We expect one extra entry for termination (per function)
+ EXPECT_EQ(16u, count);
+
+ VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
+ VerifyLineEntry(module, sc, source_file, *lt, 8, 0x401043);
+ VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
+
+ VerifyLineEntry(module, sc, source_file, *lt, 13, 0x401050);
+ VerifyLineEntry(module, sc, source_file, *lt, 14, 0x401054);
+ VerifyLineEntry(module, sc, source_file, *lt, 15, 0x401070);
+
+ VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
+ VerifyLineEntry(module, sc, header1, *lt, 10, 0x401093);
+ VerifyLineEntry(module, sc, header1, *lt, 11, 0x4010a2);
+
+ VerifyLineEntry(module, sc, header2, *lt, 5, 0x401080);
+ VerifyLineEntry(module, sc, header2, *lt, 6, 0x401083);
+ VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLookupOfHeaderFileWithNoInlines))
-{
- // Test that when looking up a header file via ResolveSymbolContext (i.e. a file that was not by itself
- // compiled, but only contributes to the combined code of other source files), that if check_inlines
- // is false, no SymbolContexts are returned.
- FileSpec fspec(m_pdb_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- EXPECT_NE(nullptr, plugin);
- SymbolFile *symfile = plugin->GetSymbolFile();
-
- FileSpec header_specs[] = {FileSpec("test-pdb.h", false), FileSpec("test-pdb-nested.h", false)};
- for (const auto &hspec : header_specs)
- {
- SymbolContextList sc_list;
- uint32_t result_count = symfile->ResolveSymbolContext(hspec, 0, false, lldb::eSymbolContextCompUnit, sc_list);
- EXPECT_EQ(0u, result_count);
- }
+TEST_F(SymbolFilePDBTests, TestLineTablesMatchSpecific) {
+ // Test that when calling ResolveSymbolContext with a specific line number,
+ // only line entries
+ // which match the requested line are returned.
+ FileSpec fspec(m_pdb_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFile *symfile = plugin->GetSymbolFile();
+
+ FileSpec source_file("test-pdb.cpp", false);
+ FileSpec header1("test-pdb.h", false);
+ FileSpec header2("test-pdb-nested.h", false);
+ uint32_t cus = symfile->GetNumCompileUnits();
+ EXPECT_EQ(2u, cus);
+
+ SymbolContextList sc_list;
+ uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
+
+ // First test with line 7, and verify that only line 7 entries are added.
+ uint32_t count =
+ symfile->ResolveSymbolContext(source_file, 7, true, scope, sc_list);
+ EXPECT_EQ(1u, count);
+ SymbolContext sc;
+ EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
+
+ LineTable *lt = sc.comp_unit->GetLineTable();
+ EXPECT_NE(nullptr, lt);
+ count = lt->GetSize();
+ // We expect one extra entry for termination
+ EXPECT_EQ(3u, count);
+
+ VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
+ VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
+
+ sc_list.Clear();
+ // Then test with line 9, and verify that only line 9 entries are added.
+ count = symfile->ResolveSymbolContext(source_file, 9, true, scope, sc_list);
+ EXPECT_EQ(1u, count);
+ EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
+
+ lt = sc.comp_unit->GetLineTable();
+ EXPECT_NE(nullptr, lt);
+ count = lt->GetSize();
+ // We expect one extra entry for termination
+ EXPECT_EQ(3u, count);
+
+ VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
+ VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLineTablesMatchAll))
-{
- // Test that when calling ResolveSymbolContext with a line number of 0, all line entries from
- // the specified files are returned.
- FileSpec fspec(m_pdb_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFile *symfile = plugin->GetSymbolFile();
-
- FileSpec source_file("test-pdb.cpp", false);
- FileSpec header1("test-pdb.h", false);
- FileSpec header2("test-pdb-nested.h", false);
- uint32_t cus = symfile->GetNumCompileUnits();
- EXPECT_EQ(2u, cus);
-
- SymbolContextList sc_list;
- uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
-
- uint32_t count = symfile->ResolveSymbolContext(source_file, 0, true, scope, sc_list);
- EXPECT_EQ(1u, count);
- SymbolContext sc;
- EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
-
- LineTable *lt = sc.comp_unit->GetLineTable();
- EXPECT_NE(nullptr, lt);
- count = lt->GetSize();
- // We expect one extra entry for termination (per function)
- EXPECT_EQ(16u, count);
-
- VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
- VerifyLineEntry(module, sc, source_file, *lt, 8, 0x401043);
- VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
-
- VerifyLineEntry(module, sc, source_file, *lt, 13, 0x401050);
- VerifyLineEntry(module, sc, source_file, *lt, 14, 0x401054);
- VerifyLineEntry(module, sc, source_file, *lt, 15, 0x401070);
-
- VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
- VerifyLineEntry(module, sc, header1, *lt, 10, 0x401093);
- VerifyLineEntry(module, sc, header1, *lt, 11, 0x4010a2);
-
- VerifyLineEntry(module, sc, header2, *lt, 5, 0x401080);
- VerifyLineEntry(module, sc, header2, *lt, 6, 0x401083);
- VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
+TEST_F(SymbolFilePDBTests, TestSimpleClassTypes) {
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile =
+ static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("Class"), nullptr, false, 0,
+ searched_files, results));
+ EXPECT_EQ(1u, results.GetSize());
+ lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
+ EXPECT_EQ(ConstString("Class"), udt_type->GetName());
+ CompilerType compiler_type = udt_type->GetForwardCompilerType();
+ EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
+ EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_Class"),
+ udt_type->GetByteSize());
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestLineTablesMatchSpecific))
-{
- // Test that when calling ResolveSymbolContext with a specific line number, only line entries
- // which match the requested line are returned.
- FileSpec fspec(m_pdb_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFile *symfile = plugin->GetSymbolFile();
-
- FileSpec source_file("test-pdb.cpp", false);
- FileSpec header1("test-pdb.h", false);
- FileSpec header2("test-pdb-nested.h", false);
- uint32_t cus = symfile->GetNumCompileUnits();
- EXPECT_EQ(2u, cus);
-
- SymbolContextList sc_list;
- uint32_t scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
-
- // First test with line 7, and verify that only line 7 entries are added.
- uint32_t count = symfile->ResolveSymbolContext(source_file, 7, true, scope, sc_list);
- EXPECT_EQ(1u, count);
- SymbolContext sc;
- EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
-
- LineTable *lt = sc.comp_unit->GetLineTable();
- EXPECT_NE(nullptr, lt);
- count = lt->GetSize();
- // We expect one extra entry for termination
- EXPECT_EQ(3u, count);
-
- VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
- VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
-
- sc_list.Clear();
- // Then test with line 9, and verify that only line 9 entries are added.
- count = symfile->ResolveSymbolContext(source_file, 9, true, scope, sc_list);
- EXPECT_EQ(1u, count);
- EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
-
- lt = sc.comp_unit->GetLineTable();
- EXPECT_NE(nullptr, lt);
- count = lt->GetSize();
- // We expect one extra entry for termination
- EXPECT_EQ(3u, count);
-
- VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
- VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
+TEST_F(SymbolFilePDBTests, TestNestedClassTypes) {
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile =
+ static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("Class::NestedClass"),
+ nullptr, false, 0, searched_files, results));
+ EXPECT_EQ(1u, results.GetSize());
+ lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
+ EXPECT_EQ(ConstString("Class::NestedClass"), udt_type->GetName());
+ CompilerType compiler_type = udt_type->GetForwardCompilerType();
+ EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
+ EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NestedClass"),
+ udt_type->GetByteSize());
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestSimpleClassTypes))
-{
- FileSpec fspec(m_types_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
- const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- SymbolContext sc;
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
- EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("Class"), nullptr, false, 0, searched_files, results));
- EXPECT_EQ(1u, results.GetSize());
- lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString("Class"), udt_type->GetName());
- CompilerType compiler_type = udt_type->GetForwardCompilerType();
- EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
- EXPECT_EQ(uint64_t(GetGlobalConstantInteger(session, "sizeof_Class")), udt_type->GetByteSize());
+TEST_F(SymbolFilePDBTests, TestClassInNamespace) {
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile =
+ static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("NS::NSClass"), nullptr,
+ false, 0, searched_files, results));
+ EXPECT_EQ(1u, results.GetSize());
+ lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
+ EXPECT_EQ(ConstString("NS::NSClass"), udt_type->GetName());
+ CompilerType compiler_type = udt_type->GetForwardCompilerType();
+ EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
+ EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"),
+ udt_type->GetByteSize());
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestNestedClassTypes))
-{
- FileSpec fspec(m_types_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
- const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- SymbolContext sc;
- llvm::DenseSet<SymbolFile *> searched_files;
+TEST_F(SymbolFilePDBTests, TestEnumTypes) {
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile =
+ static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ const char *EnumsToCheck[] = {"Enum", "ShortEnum"};
+ for (auto Enum : EnumsToCheck) {
TypeMap results;
- EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("Class::NestedClass"), nullptr, false, 0, searched_files, results));
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString(Enum), nullptr, false, 0,
+ searched_files, results));
EXPECT_EQ(1u, results.GetSize());
- lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString("Class::NestedClass"), udt_type->GetName());
- CompilerType compiler_type = udt_type->GetForwardCompilerType();
- EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
- EXPECT_EQ(uint64_t(GetGlobalConstantInteger(session, "sizeof_NestedClass")), udt_type->GetByteSize());
-}
-
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestClassInNamespace))
-{
- FileSpec fspec(m_types_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
- const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- SymbolContext sc;
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
- EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString("NS::NSClass"), nullptr, false, 0, searched_files, results));
- EXPECT_EQ(1u, results.GetSize());
- lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString("NS::NSClass"), udt_type->GetName());
- CompilerType compiler_type = udt_type->GetForwardCompilerType();
- EXPECT_TRUE(ClangASTContext::IsClassType(compiler_type.GetOpaqueQualType()));
- EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"), udt_type->GetByteSize());
-}
-
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestEnumTypes))
-{
- FileSpec fspec(m_types_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
- const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- SymbolContext sc;
- llvm::DenseSet<SymbolFile *> searched_files;
- const char *EnumsToCheck[] = {"Enum", "ShortEnum"};
- for (auto Enum : EnumsToCheck)
- {
- TypeMap results;
- EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString(Enum), nullptr, false, 0, searched_files, results));
- EXPECT_EQ(1u, results.GetSize());
- lldb::TypeSP enum_type = results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString(Enum), enum_type->GetName());
- CompilerType compiler_type = enum_type->GetFullCompilerType();
- EXPECT_TRUE(ClangASTContext::IsEnumType(compiler_type.GetOpaqueQualType()));
- clang::EnumDecl *enum_decl = ClangASTContext::GetAsEnumDecl(compiler_type);
- EXPECT_NE(nullptr, enum_decl);
- EXPECT_EQ(2, std::distance(enum_decl->enumerator_begin(), enum_decl->enumerator_end()));
-
- std::string sizeof_var = "sizeof_";
- sizeof_var.append(Enum);
- EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var.c_str()), enum_type->GetByteSize());
- }
+ lldb::TypeSP enum_type = results.GetTypeAtIndex(0);
+ EXPECT_EQ(ConstString(Enum), enum_type->GetName());
+ CompilerType compiler_type = enum_type->GetFullCompilerType();
+ EXPECT_TRUE(ClangASTContext::IsEnumType(compiler_type.GetOpaqueQualType()));
+ clang::EnumDecl *enum_decl = ClangASTContext::GetAsEnumDecl(compiler_type);
+ EXPECT_NE(nullptr, enum_decl);
+ EXPECT_EQ(2, std::distance(enum_decl->enumerator_begin(),
+ enum_decl->enumerator_end()));
+
+ std::string sizeof_var = "sizeof_";
+ sizeof_var.append(Enum);
+ EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
+ enum_type->GetByteSize());
+ }
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestArrayTypes))
-{
- // In order to get this test working, we need to support lookup by symbol name. Because array
- // types themselves do not have names, only the symbols have names (i.e. the name of the array).
+TEST_F(SymbolFilePDBTests, TestArrayTypes) {
+ // In order to get this test working, we need to support lookup by symbol
+ // name. Because array
+ // types themselves do not have names, only the symbols have names (i.e. the
+ // name of the array).
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestFunctionTypes))
-{
- // In order to get this test working, we need to support lookup by symbol name. Because array
- // types themselves do not have names, only the symbols have names (i.e. the name of the array).
+TEST_F(SymbolFilePDBTests, TestFunctionTypes) {
+ // In order to get this test working, we need to support lookup by symbol
+ // name. Because array
+ // types themselves do not have names, only the symbols have names (i.e. the
+ // name of the array).
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestTypedefs))
-{
- FileSpec fspec(m_types_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
- const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- SymbolContext sc;
- llvm::DenseSet<SymbolFile *> searched_files;
+TEST_F(SymbolFilePDBTests, TestTypedefs) {
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile =
+ static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ const llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+
+ const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef"};
+ for (auto Typedef : TypedefsToCheck) {
TypeMap results;
-
- const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef"};
- for (auto Typedef : TypedefsToCheck)
- {
- TypeMap results;
- EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString(Typedef), nullptr, false, 0, searched_files, results));
- EXPECT_EQ(1u, results.GetSize());
- lldb::TypeSP typedef_type = results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString(Typedef), typedef_type->GetName());
- CompilerType compiler_type = typedef_type->GetFullCompilerType();
- ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(compiler_type.GetTypeSystem());
- EXPECT_TRUE(clang_type_system->IsTypedefType(compiler_type.GetOpaqueQualType()));
-
- std::string sizeof_var = "sizeof_";
- sizeof_var.append(Typedef);
- EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var.c_str()), typedef_type->GetByteSize());
- }
+ EXPECT_EQ(1u, symfile->FindTypes(sc, ConstString(Typedef), nullptr, false,
+ 0, searched_files, results));
+ EXPECT_EQ(1u, results.GetSize());
+ lldb::TypeSP typedef_type = results.GetTypeAtIndex(0);
+ EXPECT_EQ(ConstString(Typedef), typedef_type->GetName());
+ CompilerType compiler_type = typedef_type->GetFullCompilerType();
+ ClangASTContext *clang_type_system =
+ llvm::dyn_cast_or_null<ClangASTContext>(compiler_type.GetTypeSystem());
+ EXPECT_TRUE(
+ clang_type_system->IsTypedefType(compiler_type.GetOpaqueQualType()));
+
+ std::string sizeof_var = "sizeof_";
+ sizeof_var.append(Typedef);
+ EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
+ typedef_type->GetByteSize());
+ }
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestRegexNameMatch))
-{
- FileSpec fspec(m_types_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
- SymbolContext sc;
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
- uint32_t num_results = symfile->FindTypes(sc, ConstString(".*"), nullptr, false, 0, searched_files, results);
- EXPECT_GT(num_results, 1u);
- EXPECT_EQ(num_results, results.GetSize());
+TEST_F(SymbolFilePDBTests, TestRegexNameMatch) {
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile =
+ static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ uint32_t num_results = symfile->FindTypes(sc, ConstString(".*"), nullptr,
+ false, 0, searched_files, results);
+ EXPECT_GT(num_results, 1u);
+ EXPECT_EQ(num_results, results.GetSize());
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestMaxMatches))
-{
- FileSpec fspec(m_types_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
- SymbolContext sc;
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
- uint32_t num_results = symfile->FindTypes(sc, ConstString(".*"), nullptr, false, 0, searched_files, results);
- // Try to limit ourselves from 1 to 10 results, otherwise we could be doing this thousands of times.
- // The idea is just to make sure that for a variety of values, the number of limited results always
- // comes out to the number we are expecting.
- uint32_t iterations = std::min(num_results, 10u);
- for (uint32_t i = 1; i <= iterations; ++i)
- {
- uint32_t num_limited_results = symfile->FindTypes(sc, ConstString(".*"), nullptr, false, i, searched_files, results);
- EXPECT_EQ(i, num_limited_results);
- EXPECT_EQ(num_limited_results, results.GetSize());
- }
+TEST_F(SymbolFilePDBTests, TestMaxMatches) {
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile =
+ static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ uint32_t num_results = symfile->FindTypes(sc, ConstString(".*"), nullptr,
+ false, 0, searched_files, results);
+ // Try to limit ourselves from 1 to 10 results, otherwise we could be doing
+ // this thousands of times.
+ // The idea is just to make sure that for a variety of values, the number of
+ // limited results always
+ // comes out to the number we are expecting.
+ uint32_t iterations = std::min(num_results, 10u);
+ for (uint32_t i = 1; i <= iterations; ++i) {
+ uint32_t num_limited_results = symfile->FindTypes(
+ sc, ConstString(".*"), nullptr, false, i, searched_files, results);
+ EXPECT_EQ(i, num_limited_results);
+ EXPECT_EQ(num_limited_results, results.GetSize());
+ }
}
-TEST_F(SymbolFilePDBTests, REQUIRES_DIA_SDK(TestNullName))
-{
- FileSpec fspec(m_types_test_exe.c_str(), false);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolVendor *plugin = module->GetSymbolVendor();
- SymbolFilePDB *symfile = static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
- SymbolContext sc;
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
- uint32_t num_results = symfile->FindTypes(sc, ConstString(), nullptr, false, 0, searched_files, results);
- EXPECT_EQ(0u, num_results);
- EXPECT_EQ(0u, results.GetSize());
+TEST_F(SymbolFilePDBTests, TestNullName) {
+ FileSpec fspec(m_types_test_exe.c_str(), false);
+ ArchSpec aspec("i686-pc-windows");
+ lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
+
+ SymbolVendor *plugin = module->GetSymbolVendor();
+ SymbolFilePDB *symfile =
+ static_cast<SymbolFilePDB *>(plugin->GetSymbolFile());
+ SymbolContext sc;
+ llvm::DenseSet<SymbolFile *> searched_files;
+ TypeMap results;
+ uint32_t num_results = symfile->FindTypes(sc, ConstString(), nullptr, false,
+ 0, searched_files, results);
+ EXPECT_EQ(0u, num_results);
+ EXPECT_EQ(0u, results.GetSize());
}
diff --git a/unittests/UnwindAssembly/CMakeLists.txt b/unittests/UnwindAssembly/CMakeLists.txt
new file mode 100644
index 000000000000..0326011fda84
--- /dev/null
+++ b/unittests/UnwindAssembly/CMakeLists.txt
@@ -0,0 +1,5 @@
+if ("X86" IN_LIST LLVM_TARGETS_TO_BUILD)
+ add_subdirectory(x86)
+endif()
+
+add_subdirectory(InstEmulation)
diff --git a/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt b/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt
new file mode 100644
index 000000000000..5e274a229919
--- /dev/null
+++ b/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt
@@ -0,0 +1,3 @@
+if ("AArch64" IN_LIST LLVM_TARGETS_TO_BUILD)
+ add_lldb_unittest(InstEmulationTests TestArm64InstEmulation.cpp)
+endif()
diff --git a/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp b/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp
new file mode 100644
index 000000000000..d7caf4281d5d
--- /dev/null
+++ b/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp
@@ -0,0 +1,672 @@
+//===-- TestArm64InstEmulation.cpp ------------------------------------*- C++
+//-*-===//
+
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include <vector>
+
+#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
+#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
+#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
+#include "llvm/Support/TargetSelect.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class TestArm64InstEmulation : public testing::Test {
+public:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+ // virtual void SetUp() override { }
+ // virtual void TearDown() override { }
+
+protected:
+};
+
+void TestArm64InstEmulation::SetUpTestCase() {
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllDisassemblers();
+ DisassemblerLLVMC::Initialize();
+ EmulateInstructionARM64::Initialize();
+}
+
+void TestArm64InstEmulation::TearDownTestCase() {
+ DisassemblerLLVMC::Terminate();
+ EmulateInstructionARM64::Terminate();
+}
+
+TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {
+ ArchSpec arch("arm64-apple-ios10", nullptr);
+ UnwindAssemblyInstEmulation *engine =
+ static_cast<UnwindAssemblyInstEmulation *>(
+ UnwindAssemblyInstEmulation::CreateInstance(arch));
+ ASSERT_NE(nullptr, engine);
+
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // 'int main() { }' compiled for arm64-apple-ios with clang
+ uint8_t data[] = {
+ 0xfd, 0x7b, 0xbf, 0xa9, // 0xa9bf7bfd : stp x29, x30, [sp, #-0x10]!
+ 0xfd, 0x03, 0x00, 0x91, // 0x910003fd : mov x29, sp
+ 0xff, 0x43, 0x00, 0xd1, // 0xd10043ff : sub sp, sp, #0x10
+
+ 0xbf, 0x03, 0x00, 0x91, // 0x910003bf : mov sp, x29
+ 0xfd, 0x7b, 0xc1, 0xa8, // 0xa8c17bfd : ldp x29, x30, [sp], #16
+ 0xc0, 0x03, 0x5f, 0xd6, // 0xd65f03c0 : ret
+ };
+
+ // UnwindPlan we expect:
+
+ // row[0]: 0: CFA=sp +0 =>
+ // row[1]: 4: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
+ // row[2]: 8: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]
+ // row[2]: 16: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
+ // row[3]: 20: CFA=sp +0 => fp= <same> lr= <same>
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ sample_range, data, sizeof(data), unwind_plan));
+
+ // CFA=sp +0
+ row_sp = unwind_plan.GetRowForFunctionOffset(0);
+ EXPECT_EQ(0ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+
+ // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ // CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(8);
+ EXPECT_EQ(8ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(16);
+ EXPECT_EQ(16ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ // CFA=sp +0 => fp= <same> lr= <same>
+ row_sp = unwind_plan.GetRowForFunctionOffset(20);
+ EXPECT_EQ(20ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {
+ ArchSpec arch("arm64-apple-ios10", nullptr);
+ UnwindAssemblyInstEmulation *engine =
+ static_cast<UnwindAssemblyInstEmulation *>(
+ UnwindAssemblyInstEmulation::CreateInstance(arch));
+ ASSERT_NE(nullptr, engine);
+
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // disassembly of -[NSPlaceholderString initWithBytes:length:encoding:]
+ // from Foundation for iOS.
+ uint8_t data[] = {
+ 0xf6, 0x57, 0xbd, 0xa9, // 0: 0xa9bd57f6 stp x22, x21, [sp, #-48]!
+ 0xf4, 0x4f, 0x01, 0xa9, // 4: 0xa9014ff4 stp x20, x19, [sp, #16]
+ 0xfd, 0x7b, 0x02, 0xa9, // 8: 0xa9027bfd stp x29, x30, [sp, #32]
+ 0xfd, 0x83, 0x00, 0x91, // 12: 0x910083fd add x29, sp, #32
+ 0xff, 0x43, 0x00, 0xd1, // 16: 0xd10043ff sub sp, sp, #16
+
+ // [... function body ...]
+ 0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop
+
+ 0xbf, 0x83, 0x00, 0xd1, // 24: 0xd10083bf sub sp, x29, #32
+ 0xfd, 0x7b, 0x42, 0xa9, // 28: 0xa9427bfd ldp x29, x30, [sp, #32]
+ 0xf4, 0x4f, 0x41, 0xa9, // 32: 0xa9414ff4 ldp x20, x19, [sp, #16]
+ 0xf6, 0x57, 0xc3, 0xa8, // 36: 0xa8c357f6 ldp x22, x21, [sp], #48
+ 0x01, 0x16, 0x09, 0x14, // 40: 0x14091601 b 0x18f640524 ; symbol stub
+ // for: CFStringCreateWithBytes
+ };
+
+ // UnwindPlan we expect:
+ // 0: CFA=sp +0 =>
+ // 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]
+ // 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // fp=[CFA-16] lr=[CFA-8]
+ // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // fp=[CFA-16] lr=[CFA-8]
+
+ // [... function body ...]
+
+ // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // fp=[CFA-16] lr=[CFA-8]
+ // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=
+ // <same> lr= <same>
+ // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=
+ // <same> lr= <same>
+ // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>
+ // lr= <same>
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ sample_range, data, sizeof(data), unwind_plan));
+
+ // 0: CFA=sp +0 =>
+ row_sp = unwind_plan.GetRowForFunctionOffset(0);
+ EXPECT_EQ(0ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+
+ // 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-40, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-48, regloc.GetOffset());
+
+ // 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ row_sp = unwind_plan.GetRowForFunctionOffset(8);
+ EXPECT_EQ(8ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-24, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-32, regloc.GetOffset());
+
+ // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // fp=[CFA-16] lr=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(12);
+ EXPECT_EQ(12ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // fp=[CFA-16] lr=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(16);
+ EXPECT_EQ(16ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // fp=[CFA-16] lr=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(28);
+ EXPECT_EQ(28ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
+
+ // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=
+ // <same> lr= <same>
+ row_sp = unwind_plan.GetRowForFunctionOffset(32);
+ EXPECT_EQ(32ull, row_sp->GetOffset());
+
+ // I'd prefer if these restored registers were cleared entirely instead of set
+ // to IsSame...
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
+ EXPECT_TRUE(regloc.IsSame());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
+ EXPECT_TRUE(regloc.IsSame());
+
+ // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=
+ // <same> lr= <same>
+ row_sp = unwind_plan.GetRowForFunctionOffset(36);
+ EXPECT_EQ(36ull, row_sp->GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
+ EXPECT_TRUE(regloc.IsSame());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
+ EXPECT_TRUE(regloc.IsSame());
+
+ // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>
+ // lr= <same>
+ row_sp = unwind_plan.GetRowForFunctionOffset(40);
+ EXPECT_EQ(40ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
+ EXPECT_TRUE(regloc.IsSame());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
+ EXPECT_TRUE(regloc.IsSame());
+}
+
+TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) {
+ ArchSpec arch("arm64-apple-ios10", nullptr);
+ UnwindAssemblyInstEmulation *engine =
+ static_cast<UnwindAssemblyInstEmulation *>(
+ UnwindAssemblyInstEmulation::CreateInstance(arch));
+ ASSERT_NE(nullptr, engine);
+
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // disassembly of JSC::ARM64LogicalImmediate::findBitRange<16u>
+ // from JavaScriptcore for iOS.
+ uint8_t data[] = {
+ 0x08, 0x3c, 0x0f, 0x53, // 0: 0x530f3c08 ubfx w8, w0, #15, #1
+ 0x68, 0x00, 0x00, 0x39, // 4: 0x39000068 strb w8, [x3]
+ 0x08, 0x3c, 0x40, 0xd2, // 8: 0xd2403c08 eor x8, x0, #0xffff
+ 0x1f, 0x00, 0x71, 0xf2, // 12: 0xf271001f tst x0, #0x8000
+
+ // [...]
+
+ 0x3f, 0x01, 0x0c, 0xeb, // 16: 0xeb0c013f cmp x9, x12
+ 0x81, 0x00, 0x00, 0x54, // 20: 0x54000081 b.ne +34
+ 0x5f, 0x00, 0x00, 0xb9, // 24: 0xb900005f str wzr, [x2]
+ 0xe0, 0x03, 0x00, 0x32, // 28: 0x320003e0 orr w0, wzr, #0x1
+ 0xc0, 0x03, 0x5f, 0xd6, // 32: 0xd65f03c0 ret
+ 0x89, 0x01, 0x09, 0xca, // 36: 0xca090189 eor x9, x12, x9
+
+ // [...]
+
+ 0x08, 0x05, 0x00, 0x11, // 40: 0x11000508 add w8, w8, #0x1
+ 0x48, 0x00, 0x00, 0xb9, // 44: 0xb9000048 str w8, [x2]
+ 0xe0, 0x03, 0x00, 0x32, // 48: 0x320003e0 orr w0, wzr, #0x1
+ 0xc0, 0x03, 0x5f, 0xd6, // 52: 0xd65f03c0 ret
+ 0x00, 0x00, 0x80, 0x52, // 56: 0x52800000 mov w0, #0x0
+ 0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret
+
+ };
+
+ // UnwindPlan we expect:
+ // 0: CFA=sp +0 =>
+ // (possibly with additional rows at offsets 36 and 56 saying the same thing)
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ sample_range, data, sizeof(data), unwind_plan));
+
+ // 0: CFA=sp +0 =>
+ row_sp = unwind_plan.GetRowForFunctionOffset(0);
+ EXPECT_EQ(0ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(32);
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x23_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x24_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x25_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x26_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x27_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x28_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(36);
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(52);
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(56);
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(60);
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) {
+ ArchSpec arch("arm64-apple-ios10", nullptr);
+ UnwindAssemblyInstEmulation *engine =
+ static_cast<UnwindAssemblyInstEmulation *>(
+ UnwindAssemblyInstEmulation::CreateInstance(arch));
+ ASSERT_NE(nullptr, engine);
+
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // disassembly of mach_msg_sever_once from libsystem_kernel.dylib for iOS.
+ uint8_t data[] = {
+
+ 0xfc, 0x6f, 0xba, 0xa9, // 0: 0xa9ba6ffc stp x28, x27, [sp, #-0x60]!
+ 0xfa, 0x67, 0x01, 0xa9, // 4: 0xa90167fa stp x26, x25, [sp, #0x10]
+ 0xf8, 0x5f, 0x02, 0xa9, // 8: 0xa9025ff8 stp x24, x23, [sp, #0x20]
+ 0xf6, 0x57, 0x03, 0xa9, // 12: 0xa90357f6 stp x22, x21, [sp, #0x30]
+ 0xf4, 0x4f, 0x04, 0xa9, // 16: 0xa9044ff4 stp x20, x19, [sp, #0x40]
+ 0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp x29, x30, [sp, #0x50]
+ 0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add x29, sp, #0x50
+ 0xff, 0xc3, 0x00, 0xd1, // 28: 0xd100c3ff sub sp, sp, #0x30
+
+ // mid-function, store x20 & x24 on the stack at a different location.
+ // this should not show up in the unwind plan; caller's values are not
+ // being saved to stack.
+ 0xf8, 0x53, 0x01, 0xa9, // 32: 0xa90153f8 stp x24, x20, [sp, #0x10]
+
+ // mid-function, copy x20 and x19 off of the stack -- but not from
+ // their original locations. unwind plan should ignore this.
+ 0xf4, 0x4f, 0x41, 0xa9, // 36: 0xa9414ff4 ldp x20, x19, [sp, #0x10]
+
+ // epilogue
+ 0xbf, 0x43, 0x01, 0xd1, // 40: 0xd10143bf sub sp, x29, #0x50
+ 0xfd, 0x7b, 0x45, 0xa9, // 44: 0xa9457bfd ldp x29, x30, [sp, #0x50]
+ 0xf4, 0x4f, 0x44, 0xa9, // 48: 0xa9444ff4 ldp x20, x19, [sp, #0x40]
+ 0xf6, 0x57, 0x43, 0xa9, // 52: 0xa94357f6 ldp x22, x21, [sp, #0x30]
+ 0xf8, 0x5f, 0x42, 0xa9, // 56: 0xa9425ff8 ldp x24, x23, [sp, #0x20]
+ 0xfa, 0x67, 0x41, 0xa9, // 60: 0xa94167fa ldp x26, x25, [sp, #0x10]
+ 0xfc, 0x6f, 0xc6, 0xa8, // 64: 0xa8c66ffc ldp x28, x27, [sp], #0x60
+ 0xc0, 0x03, 0x5f, 0xd6, // 68: 0xd65f03c0 ret
+ };
+
+ // UnwindPlan we expect:
+ // 0: CFA=sp +0 =>
+ // 4: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96]
+ // 8: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
+ // 12: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]
+ // x27=[CFA-88] x28=[CFA-96]
+ // 16: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]
+ // x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
+ // 20: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
+ // x28=[CFA-96]
+ // 24: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
+ // x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
+ // 28: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
+ // x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
+
+ // 44: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
+ // x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
+ // 48: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
+ // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
+ // x28=[CFA-96]
+ // 52: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]
+ // x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
+ // 56: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]
+ // x27=[CFA-88] x28=[CFA-96]
+ // 60: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
+ // 64: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96]
+ // 68: CFA=sp +0 =>
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ sample_range, data, sizeof(data), unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(36);
+ EXPECT_EQ(28ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-32, regloc.GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(40);
+ EXPECT_EQ(28ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-32, regloc.GetOffset());
+}
+
+TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) {
+ ArchSpec arch("arm64-apple-ios10", nullptr);
+ UnwindAssemblyInstEmulation *engine =
+ static_cast<UnwindAssemblyInstEmulation *>(
+ UnwindAssemblyInstEmulation::CreateInstance(arch));
+ ASSERT_NE(nullptr, engine);
+
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // this file built with clang for iOS arch arm64 optimization -Os
+ // #include <stdio.h>
+ // double foo(double in) {
+ // double arr[32];
+ // for (int i = 0; i < 32; i++)
+ // arr[i] = in + i;
+ // for (int i = 2; i < 30; i++)
+ // arr[i] = ((((arr[i - 1] * arr[i - 2] * 0.2) + (0.7 * arr[i])) /
+ // ((((arr[i] * 0.73) + 0.65) * (arr[i - 1] + 0.2)) - ((arr[i + 1] + (arr[i]
+ // * 0.32) + 0.52) / 0.3) + (0.531 * arr[i - 2]))) + ((arr[i - 1] + 5) /
+ // ((arr[i + 2] + 0.4) / arr[i])) + (arr[5] * (0.17 + arr[7] * arr[i])) +
+ // ((i > 5 ? (arr[i - 3]) : arr[i - 1]) * 0.263) + (((arr[i - 2] + arr[i -
+ // 1]) * 0.3252) + 3.56) - (arr[i + 1] * 0.852311)) * ((arr[i] * 85234.1345)
+ // + (77342.451324 / (arr[i - 2] + arr[i - 1] - 73425341.33455))) + (arr[i]
+ // * 875712013.55) - (arr[i - 1] * 0.5555) - ((arr[i] * (arr[i + 1] +
+ // 17342834.44) / 8688200123.555)) + (arr[i - 2] + 8888.888);
+ // return arr[16];
+ //}
+ // int main(int argc, char **argv) { printf("%g\n", foo(argc)); }
+
+ // so function foo() uses enough registers that it spills the callee-saved
+ // floating point registers.
+ uint8_t data[] = {
+ // prologue
+ 0xef, 0x3b, 0xba, 0x6d, // 0: 0x6dba3bef stp d15, d14, [sp, #-0x60]!
+ 0xed, 0x33, 0x01, 0x6d, // 4: 0x6d0133ed stp d13, d12, [sp, #0x10]
+ 0xeb, 0x2b, 0x02, 0x6d, // 8: 0x6d022beb stp d11, d10, [sp, #0x20]
+ 0xe9, 0x23, 0x03, 0x6d, // 12: 0x6d0323e9 stp d9, d8, [sp, #0x30]
+ 0xfc, 0x6f, 0x04, 0xa9, // 16: 0xa9046ffc stp x28, x27, [sp, #0x40]
+ 0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp x29, x30, [sp, #0x50]
+ 0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add x29, sp, #0x50
+ 0xff, 0x43, 0x04, 0xd1, // 28: 0xd10443ff sub sp, sp, #0x110
+
+ // epilogue
+ 0xbf, 0x43, 0x01, 0xd1, // 32: 0xd10143bf sub sp, x29, #0x50
+ 0xfd, 0x7b, 0x45, 0xa9, // 36: 0xa9457bfd ldp x29, x30, [sp, #0x50]
+ 0xfc, 0x6f, 0x44, 0xa9, // 40: 0xa9446ffc ldp x28, x27, [sp, #0x40]
+ 0xe9, 0x23, 0x43, 0x6d, // 44: 0x6d4323e9 ldp d9, d8, [sp, #0x30]
+ 0xeb, 0x2b, 0x42, 0x6d, // 48: 0x6d422beb ldp d11, d10, [sp, #0x20]
+ 0xed, 0x33, 0x41, 0x6d, // 52: 0x6d4133ed ldp d13, d12, [sp, #0x10]
+ 0xef, 0x3b, 0xc6, 0x6c, // 56: 0x6cc63bef ldp d15, d14, [sp], #0x60
+ 0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret
+ };
+
+ // UnwindPlan we expect:
+ // 0: CFA=sp +0 =>
+ // 4: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]
+ // 8: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
+ // 12: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]
+ // d14=[CFA-88] d15=[CFA-96]
+ // 16: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]
+ // d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
+ // 20: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]
+ // d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]
+ // d15=[CFA-96]
+ // 24: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
+ // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
+ // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
+ // 28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
+ // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
+ // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
+ // 36: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
+ // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
+ // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
+ // 40: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]
+ // d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]
+ // d15=[CFA-96]
+ // 44: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]
+ // d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
+ // 48: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]
+ // d14=[CFA-88] d15=[CFA-96]
+ // 52: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
+ // 56: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]
+ // 60: CFA=sp +0 =>
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ sample_range, data, sizeof(data), unwind_plan));
+
+ // 28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
+ // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
+ // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
+ row_sp = unwind_plan.GetRowForFunctionOffset(28);
+ EXPECT_EQ(28ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d15_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-96, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d14_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-88, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d13_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-80, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d12_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-72, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d11_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-64, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d10_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-56, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d9_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-48, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d8_arm64, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-40, regloc.GetOffset());
+
+ // 60: CFA=sp +0 =>
+ row_sp = unwind_plan.GetRowForFunctionOffset(60);
+ EXPECT_EQ(60ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
+
+ if (row_sp->GetRegisterInfo(fpu_d8_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+ if (row_sp->GetRegisterInfo(fpu_d9_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+ if (row_sp->GetRegisterInfo(fpu_d10_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+ if (row_sp->GetRegisterInfo(fpu_d11_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+ if (row_sp->GetRegisterInfo(fpu_d12_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+ if (row_sp->GetRegisterInfo(fpu_d13_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+ if (row_sp->GetRegisterInfo(fpu_d14_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+ if (row_sp->GetRegisterInfo(fpu_d15_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+ if (row_sp->GetRegisterInfo(gpr_x27_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+ if (row_sp->GetRegisterInfo(gpr_x28_arm64, regloc))
+ EXPECT_TRUE(regloc.IsSame());
+}
diff --git a/unittests/UnwindAssembly/x86/CMakeLists.txt b/unittests/UnwindAssembly/x86/CMakeLists.txt
new file mode 100644
index 000000000000..7112467b3975
--- /dev/null
+++ b/unittests/UnwindAssembly/x86/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_lldb_unittest(UnwindAssemblyx86Tests
+ Testx86AssemblyInspectionEngine.cpp
+ )
diff --git a/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp b/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
new file mode 100644
index 000000000000..e216d4be16fd
--- /dev/null
+++ b/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
@@ -0,0 +1,2339 @@
+//===-- Testx86AssemblyInspectionEngine.cpp ---------------------------*- C++
+//-*-===//
+
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include <vector>
+
+#include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Symbol/UnwindPlan.h"
+
+#include "llvm/Support/TargetSelect.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class Testx86AssemblyInspectionEngine : public testing::Test {
+public:
+ static void SetUpTestCase();
+
+ // static void TearDownTestCase() { }
+
+ // virtual void SetUp() override { }
+
+ // virtual void TearDown() override { }
+
+protected:
+};
+
+void Testx86AssemblyInspectionEngine::SetUpTestCase() {
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllDisassemblers();
+}
+
+// only defining the register names / numbers that the unwinder is actually
+// using today
+
+// names should match the constants below. These will be the eRegisterKindLLDB
+// register numbers.
+
+const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp",
+ "rsi", "rdi", "r8", "r9", "r10", "r11",
+ "r12", "r13", "r14", "r15", "rip"};
+
+enum x86_64_regs {
+ k_rax = 0,
+ k_rbx = 1,
+ k_rcx = 2,
+ k_rdx = 3,
+ k_rsp = 4,
+ k_rbp = 5,
+ k_rsi = 6,
+ k_rdi = 7,
+ k_r8 = 8,
+ k_r9 = 9,
+ k_r10 = 10,
+ k_r11 = 11,
+ k_r12 = 12,
+ k_r13 = 13,
+ k_r14 = 14,
+ k_r15 = 15,
+ k_rip = 16
+};
+
+// names should match the constants below. These will be the eRegisterKindLLDB
+// register numbers.
+
+const char *i386_reg_names[] = {"eax", "ecx", "edx", "ebx", "esp",
+ "ebp", "esi", "edi", "eip"};
+
+enum i386_regs {
+ k_eax = 0,
+ k_ecx = 1,
+ k_edx = 2,
+ k_ebx = 3,
+ k_esp = 4,
+ k_ebp = 5,
+ k_esi = 6,
+ k_edi = 7,
+ k_eip = 8
+};
+
+std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() {
+
+ ArchSpec arch("x86_64-apple-macosx", nullptr);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine(
+ new x86AssemblyInspectionEngine(arch));
+
+ std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
+ int i = 0;
+ for (const auto &name : x86_64_reg_names) {
+ x86AssemblyInspectionEngine::lldb_reg_info ri;
+ ri.name = name;
+ ri.lldb_regnum = i++;
+ lldb_regnums.push_back(ri);
+ }
+
+ engine->Initialize(lldb_regnums);
+ return engine;
+}
+
+std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() {
+
+ ArchSpec arch("i386-apple-macosx", nullptr);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine(
+ new x86AssemblyInspectionEngine(arch));
+
+ std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
+ int i = 0;
+ for (const auto &name : i386_reg_names) {
+ x86AssemblyInspectionEngine::lldb_reg_info ri;
+ ri.name = name;
+ ri.lldb_regnum = i++;
+ lldb_regnums.push_back(ri);
+ }
+
+ engine->Initialize(lldb_regnums);
+ return engine;
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ // 'int main() { }' compiled for x86_64-apple-macosx with clang
+ uint8_t data[] = {
+ 0x55, // offset 0 -- pushq %rbp
+ 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
+ 0x31, 0xc0, // offset 4 -- xorl %eax, %eax
+ 0x5d, // offset 6 -- popq %rbp
+ 0xc3 // offset 7 -- retq
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ // Expect four unwind rows:
+ // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+ // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
+ // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
+ // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+
+ EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
+ EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
+ eLazyBoolYes);
+ EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
+
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+ UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
+ EXPECT_EQ(0ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(7);
+ EXPECT_EQ(7ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) {
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+ // 'int main() { }' compiled for i386-apple-macosx with clang
+ uint8_t data[] = {
+ 0x55, // offset 0 -- pushl %ebp
+ 0x89, 0xe5, // offset 1 -- movl %esp, %ebp
+ 0x31, 0xc0, // offset 3 -- xorl %eax, %eax
+ 0x5d, // offset 5 -- popl %ebp
+ 0xc3 // offset 6 -- retl
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ // Expect four unwind rows:
+ // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+ // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
+ // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
+ // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+
+ EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_esp);
+ EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
+ eLazyBoolYes);
+ EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
+
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // offset 0 -- pushl %ebp
+ UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
+ EXPECT_EQ(0ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_TRUE(regloc.GetOffset() == -4);
+
+ // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-4, regloc.GetOffset());
+
+ // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(3);
+ EXPECT_EQ(3ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-4, regloc.GetOffset());
+
+ // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(6);
+ EXPECT_EQ(6ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-4, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessBigStackFrame) {
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ // this source file:
+ //
+ // #include <stdio.h>
+ // int main (int argc, char **argv)
+ // {
+ //
+ // const int arrsize = 60;
+ // int buf[arrsize * arrsize];
+ // int accum = argc;
+ // for (int i = 0; i < arrsize; i++)
+ // for (int j = 0; j < arrsize; j++)
+ // {
+ // if (i > 0 && j > 0)
+ // {
+ // int n = buf[(i-1) * (j-1)] * 2;
+ // int m = buf[(i-1) * (j-1)] / 2;
+ // int j = buf[(i-1) * (j-1)] + 2;
+ // int k = buf[(i-1) * (j-1)] - 2;
+ // printf ("%d ", n + m + j + k);
+ // buf[(i-1) * (j-1)] += n - m + j - k;
+ // }
+ // buf[i*j] = accum++;
+ // }
+ //
+ // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
+ // arrsize) - 3]);
+ // }
+ //
+ // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx
+
+ uint8_t data[] = {
+ 0x55, // offset 0 -- pushq %rbp
+ 0x41, 0x57, // offset 1 -- pushq %r15
+ 0x41, 0x56, // offset 3 -- pushq %r14
+ 0x41, 0x55, // offset 5 -- pushq %r13
+ 0x41, 0x54, // offset 7 -- pushq %r12
+ 0x53, // offset 9 -- pushq %rbx
+ 0x48, 0x81, 0xec, 0x68, 0x38, 0x00,
+ 0x00, // offset 10 -- subq $0x3868, %rsp
+
+ // ....
+
+ 0x48, 0x81, 0xc4, 0x68, 0x38, 0x00,
+ 0x00, // offset 17 -- addq $0x3868, %rsp
+ 0x5b, // offset 24 -- popq %rbx
+ 0x41, 0x5c, // offset 25 -- popq %r12
+ 0x41, 0x5d, // offset 27 -- popq %r13
+ 0x41, 0x5e, // offset 29 -- popq %r14
+ 0x41, 0x5f, // offset 31 -- popq %r15
+ 0x5d, // offset 33 -- popq %rbp
+ 0xc3, // offset 34 -- retq
+ 0xe8, 0x12, 0x34, 0x56, 0x78 // offset 35 -- callq whatever
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ // Unwind rules should look like
+ // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+ // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
+ // 3: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
+ // 5: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
+ // rip=[CFA-8
+ // 7: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
+ // r15=[CFA-24] rip=[CFA-8]
+ // 9: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
+ // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
+ // 10: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
+ // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
+ // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
+ // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
+
+ // 24: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
+ // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
+ // 25: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
+ // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
+ // 27: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
+ // r15=[CFA-24] rip=[CFA-8]
+ // 29: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
+ // rip=[CFA-8]
+ // 31: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
+ // 33: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
+ // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // grab the Row for when the prologue has finished executing:
+ // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
+ // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
+
+ UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(17);
+
+ EXPECT_EQ(17ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(14496, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-24, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-32, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-40, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-48, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-56, regloc.GetOffset());
+
+ // grab the Row for when the epilogue has finished executing:
+ // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(34);
+
+ EXPECT_EQ(34ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ // these could be set to IsSame and be valid -- meaning that the
+ // register value is the same as the caller's -- but I'd rather
+ // they not be mentioned at all.
+
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessBigStackFrame) {
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+ // this source file:
+ //
+ // #include <stdio.h>
+ // int main (int argc, char **argv)
+ // {
+ //
+ // const int arrsize = 60;
+ // int buf[arrsize * arrsize];
+ // int accum = argc;
+ // for (int i = 0; i < arrsize; i++)
+ // for (int j = 0; j < arrsize; j++)
+ // {
+ // if (i > 0 && j > 0)
+ // {
+ // int n = buf[(i-1) * (j-1)] * 2;
+ // int m = buf[(i-1) * (j-1)] / 2;
+ // int j = buf[(i-1) * (j-1)] + 2;
+ // int k = buf[(i-1) * (j-1)] - 2;
+ // printf ("%d ", n + m + j + k);
+ // buf[(i-1) * (j-1)] += n - m + j - k;
+ // }
+ // buf[i*j] = accum++;
+ // }
+ //
+ // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
+ // arrsize) - 3]);
+ // }
+ //
+ // compiled 'clang -arch i386 -fomit-frame-pointer -Os' for i386-apple-macosx
+
+ // simplified assembly version of the above function, which is used as the
+ // input
+ // data:
+ //
+ // .section __TEXT,__text,regular,pure_instructions
+ // .macosx_version_min 10, 12
+ // .globl _main
+ // .align 4, 0x90
+ // _main: ## @main
+ // ## BB#0:
+ // pushl %ebp
+ // pushl %ebx
+ // pushl %edi
+ // pushl %esi
+ // L0$pb:
+ // subl $0x386c, %esp
+ // calll L1
+ // L1:
+ // popl %ecx
+ // movl %ecx, 0x8(%esp)
+ // subl $0x8, %esp
+ // pushl %eax
+ // pushl 0x20(%esp)
+ // calll _puts
+ // addl $0x10, %esp
+ // incl %ebx
+ // addl $0x386c, %esp
+ // popl %esi
+ // popl %edi
+ // popl %ebx
+ // popl %ebp
+ // retl
+ //
+ // .section __TEXT,__cstring,cstring_literals
+ // L_.str: ## @.str
+ // .asciz "HI"
+ //
+ //
+ // .subsections_via_symbols
+
+ uint8_t data[] = {
+ 0x55,
+ // offset 0 -- pushl %ebp
+
+ 0x53,
+ // offset 1 -- pushl %ebx
+
+ 0x57,
+ // offset 2 -- pushl %edi
+
+ 0x56,
+ // offset 3 -- pushl %esi
+
+ 0x81, 0xec, 0x6c, 0x38, 0x00, 0x00,
+ // offset 4 -- subl $0x386c, %esp
+
+ 0xe8, 0x00, 0x00, 0x00, 0x00,
+ // offset 10 -- calll 0
+ // call the next instruction, to put the pc on the stack
+
+ 0x59,
+ // offset 15 -- popl %ecx
+ // pop the saved pc address into ecx
+
+ 0x89, 0x4c, 0x24, 0x08,
+ // offset 16 -- movl %ecx, 0x8(%esp)
+
+ // ....
+
+ 0x83, 0xec, 0x08,
+ // offset 20 -- subl $0x8, %esp
+
+ 0x50,
+ // offset 23 -- pushl %eax
+
+ 0xff, 0x74, 0x24, 0x20,
+ // offset 24 -- pushl 0x20(%esp)
+
+ 0xe8, 0x8c, 0x00, 0x00, 0x00,
+ // offset 28 -- calll puts
+
+ 0x83, 0xc4, 0x10,
+ // offset 33 -- addl $0x10, %esp
+ // get esp back to the value it was before the
+ // alignment & argument saves for the puts call
+
+ 0x43,
+ // offset 36 -- incl %ebx
+
+ // ....
+
+ 0x81, 0xc4, 0x6c, 0x38, 0x00, 0x00,
+ // offset 37 -- addl $0x386c, %esp
+
+ 0x5e,
+ // offset 43 -- popl %esi
+
+ 0x5f,
+ // offset 44 -- popl %edi
+
+ 0x5b,
+ // offset 45 -- popl %ebx
+
+ 0x5d,
+ // offset 46 -- popl %ebp
+
+ 0xc3,
+ // offset 47 -- retl
+
+ 0xe8, 0x12, 0x34, 0x56, 0x78,
+ // offset 48 -- calll __stack_chk_fail
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ // Unwind rules should look like
+ //
+ // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+ // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
+ // 2: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
+ // 3: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
+ // eip=[CFA-4]
+ // 4: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ // 10: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ //
+ // ....
+ //
+ // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ //
+ // .....
+ //
+ // 37: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ // 43: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ // 44: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
+ // eip=[CFA-4]
+ // 45: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
+ // 46: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
+ // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+ // 48: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ // Check that we get the CFA correct for the pic base setup sequence
+
+ // CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(10);
+ EXPECT_EQ(10ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
+
+ // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(15);
+ EXPECT_EQ(15ull, row_sp->GetOffset());
+ EXPECT_EQ(14468, row_sp->GetCFAValue().GetOffset());
+
+ // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(16);
+ EXPECT_EQ(16ull, row_sp->GetOffset());
+ EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
+
+ // Check that the row for offset 16 has the registers saved that we expect
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-4, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-12, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-20, regloc.GetOffset());
+
+ //
+ // Check the pushing & popping around the call printf instruction
+
+ // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(23);
+ EXPECT_EQ(23ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(14472, row_sp->GetCFAValue().GetOffset());
+
+ // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(24);
+ EXPECT_EQ(24ull, row_sp->GetOffset());
+ EXPECT_EQ(14476, row_sp->GetCFAValue().GetOffset());
+
+ // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(28);
+ EXPECT_EQ(28ull, row_sp->GetOffset());
+ EXPECT_EQ(14480, row_sp->GetCFAValue().GetOffset());
+
+ // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
+ // esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(36);
+ EXPECT_EQ(36ull, row_sp->GetOffset());
+ EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
+
+ // Check that the epilogue gets us back to the original unwind state
+
+ // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(47);
+ EXPECT_EQ(47ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-4, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_esp, regloc));
+ EXPECT_TRUE(regloc.IsCFAPlusOffset());
+ EXPECT_EQ(0, regloc.GetOffset());
+
+ // Check that no unexpected registers were saved
+
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessSmallStackFrame) {
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ // this source file:
+ // #include <stdio.h>
+ // int main () {
+ // puts ("HI");
+ // }
+ //
+ // compiled 'clang -fomit-frame-pointer' for x86_64-apple-macosx
+
+ uint8_t data[] = {
+ 0x50,
+ // offset 0 -- pushq %rax
+
+ 0x48, 0x8d, 0x3d, 0x32, 0x00, 0x00, 0x00,
+ // offset 1 -- leaq 0x32(%rip), %rdi ; "HI"
+
+ 0xe8, 0x0b, 0x00, 0x00, 0x00,
+ // offset 8 -- callq 0x100000f58 ; puts
+
+ 0x31, 0xc9,
+ // offset 13 -- xorl %ecx, %ecx
+
+ 0x89, 0x44, 0x24, 0x04,
+ // offset 15 -- movl %eax, 0x4(%rsp)
+
+ 0x89, 0xc8,
+ // offset 19 -- movl %ecx, %eax
+
+ 0x59,
+ // offset 21 -- popq %rcx
+
+ 0xc3
+ // offset 22 -- retq
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ // Unwind rules should look like
+ // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+ // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
+ // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // grab the Row for when the prologue has finished executing:
+ // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
+
+ UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(13);
+
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ // none of these were spilled
+
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
+
+ // grab the Row for when the epilogue has finished executing:
+ // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(22);
+
+ EXPECT_EQ(22ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessSmallStackFrame) {
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+ // this source file:
+ // #include <stdio.h>
+ // int main () {
+ // puts ("HI");
+ // }
+ //
+ // compiled 'clang -arch i386 -fomit-frame-pointer' for i386-apple-macosx
+
+ uint8_t data[] = {
+ 0x83, 0xec, 0x0c,
+ // offset 0 -- subl $0xc, %esp
+
+ 0xe8, 0x00, 0x00, 0x00, 0x00,
+ // offset 3 -- calll 0 {call the next instruction, to put the pc on
+ // the stack}
+
+ 0x58,
+ // offset 8 -- popl %eax {pop the saved pc value off stack, into eax}
+
+ 0x8d, 0x80, 0x3a, 0x00, 0x00, 0x00,
+ // offset 9 -- leal 0x3a(%eax),%eax
+
+ 0x89, 0x04, 0x24,
+ // offset 15 -- movl %eax, (%esp)
+
+ 0xe8, 0x0d, 0x00, 0x00, 0x00,
+ // offset 18 -- calll 0x1f94 (puts)
+
+ 0x31, 0xc9,
+ // offset 23 -- xorl %ecx, %ecx
+
+ 0x89, 0x44, 0x24, 0x08,
+ // offset 25 -- movl %eax, 0x8(%esp)
+
+ 0x89, 0xc8,
+ // offset 29 -- movl %ecx, %eax
+
+ 0x83, 0xc4, 0x0c,
+ // offset 31 -- addl $0xc, %esp
+
+ 0xc3
+ // offset 34 -- retl
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ // Unwind rules should look like
+ // row[0]: 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+ // row[1]: 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
+ // row[2]: 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
+ // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
+ // row[4]: 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+
+ UnwindPlan::Row::RegisterLocation regloc;
+
+ // Check unwind state before we set up the picbase register
+ // 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
+
+ UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(3);
+
+ EXPECT_EQ(3ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ // Check unwind state after we call the next instruction
+ // 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(8);
+ EXPECT_EQ(8ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
+
+ // Check unwind state after we pop the pic base value off the stack
+ // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(9);
+ EXPECT_EQ(9ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ // Check that no unexpected registers were saved
+
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
+
+ // verify that we get back to the original unwind state before the ret
+ // 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(34);
+ EXPECT_EQ(34ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data[] = {
+ 0x55, // pushq %rbp
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data[] = {
+ 0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
+ 0x6a, 0x7d, // pushl $0x7d
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(5);
+ EXPECT_EQ(5ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(7);
+ EXPECT_EQ(7ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(5);
+ EXPECT_EQ(5ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(7);
+ EXPECT_EQ(7ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
+}
+
+// We treat 'pushq $0' / 'pushl $0' specially - this shows up
+// in the first function called in a new thread and it needs to
+// put a 0 as the saved pc. We pretend it didn't change the CFA.
+TEST_F(Testx86AssemblyInspectionEngine, TestPush0) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data[] = {
+ 0x6a, 0x00, // pushq $0
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+
+ // We're verifying that no row was created for the 'pushq $0'
+ EXPECT_EQ(0ull, row_sp->GetOffset());
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+
+ // We're verifying that no row was created for the 'pushq $0'
+ EXPECT_EQ(0ull, row_sp->GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data[] = {
+ 0xff, 0x74, 0x24, 0x20, // pushl 0x20(%esp)
+ 0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl 0xf001ce(%esi)
+ 0xff, 0x30, // pushl (%eax)
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(10);
+ EXPECT_EQ(10ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(12);
+ EXPECT_EQ(12ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data[] = {
+ 0x41, 0x57, // pushq %r15
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data[] = {
+ 0x41, 0x56, // pushq %r14
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data[] = {
+ 0x41, 0x55, // pushq %r13
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data[] = {
+ 0x41, 0x54, // pushq %r13
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data[] = {
+ 0x53, // pushq %rbx
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-16, regloc.GetOffset());
+}
+
+// The ABI is hardcoded in x86AssemblyInspectionEngine such that
+// eax, ecx, edx are all considered volatile and push/pops of them are
+// not tracked (except to keep track of stack pointer movement)
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEAX) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x50, // pushl %eax
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
+}
+
+// The ABI is hardcoded in x86AssemblyInspectionEngine such that
+// eax, ecx, edx are all considered volatile and push/pops of them are
+// not tracked (except to keep track of stack pointer movement)
+TEST_F(Testx86AssemblyInspectionEngine, TestPushECX) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x51, // pushl %ecx
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
+}
+
+// The ABI is hardcoded in x86AssemblyInspectionEngine such that
+// eax, ecx, edx are all considered volatile and push/pops of them are
+// not tracked (except to keep track of stack pointer movement)
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEDX) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x52, // pushl %edx
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x53, // pushl %ebx
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x55, // pushl %ebp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x56, // pushl %esi
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x57, // pushl %edi
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(1);
+ EXPECT_EQ(1ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+
+ uint8_t data64_1[] = {
+ 0x48, 0x8b, 0xec, // movq %rsp, %rbp
+ 0x90 // nop
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data64_1));
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data64_1, sizeof(data64_1), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(3);
+
+ EXPECT_EQ(3ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ uint8_t data64_2[] = {
+ 0x48, 0x89, 0xe5, // movq %rsp, %rbp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data64_2));
+ unwind_plan.Clear();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data64_2, sizeof(data64_2), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(3);
+ EXPECT_EQ(3ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ uint8_t data32_1[] = {
+ 0x8b, 0xec, // movl %rsp, %rbp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data32_1));
+ unwind_plan.Clear();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data32_1, sizeof(data32_1), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ uint8_t data32_2[] = {
+ 0x89, 0xe5, // movl %rsp, %rbp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data32_2));
+ unwind_plan.Clear();
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data32_2, sizeof(data32_2), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+
+ uint8_t data1[] = {
+ 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data1));
+
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data1, sizeof(data1), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(7);
+ EXPECT_EQ(7ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(264, row_sp->GetCFAValue().GetOffset());
+
+ uint8_t data2[] = {
+ 0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data2));
+
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data2, sizeof(data2), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data1[] = {
+ 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data1));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data1, sizeof(data1), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(6);
+ EXPECT_EQ(6ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(260, row_sp->GetCFAValue().GetOffset());
+
+ uint8_t data2[] = {
+ 0x83, 0xec, 0x10, // subq $0x10, %esp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data2));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data2, sizeof(data2), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(3);
+ EXPECT_EQ(3ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+
+ uint8_t data1[] = {
+ 0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data1));
+
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data1, sizeof(data1), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(7);
+ EXPECT_EQ(7ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8 - 256, row_sp->GetCFAValue().GetOffset());
+
+ uint8_t data2[] = {
+ 0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data2));
+
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data2, sizeof(data2), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8 - 16, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data1[] = {
+ 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data1));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data1, sizeof(data1), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(6);
+ EXPECT_EQ(6ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4 - 256, row_sp->GetCFAValue().GetOffset());
+
+ uint8_t data2[] = {
+ 0x83, 0xc4, 0x10, // addq $0x10, %esp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data2));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data2, sizeof(data2), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(3);
+ EXPECT_EQ(3ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset());
+}
+
+// FIXME add test for lea_rsp_pattern_p
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x53, // pushq %rbx
+ 0x5b, // popq %rbx
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x55, // pushq %rbp
+ 0x5d, // popq %rbp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x41, 0x54, // pushq %r12
+ 0x41, 0x5c, // popq %r12
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x41, 0x55, // pushq %r13
+ 0x41, 0x5d, // popq %r13
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x41, 0x56, // pushq %r14
+ 0x41, 0x5e, // popq %r14
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x41, 0x57, // pushq %r15
+ 0x41, 0x5f, // popq %r15
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x53, // pushl %ebx
+ 0x5b, // popl %ebx
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x55, // pushl %ebp
+ 0x5d, // popl %ebp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x56, // pushl %esi
+ 0x5e, // popl %esi
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x57, // pushl %edi
+ 0x5f, // popl %edi
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
+}
+
+// We don't track these registers, but make sure the CFA address is updated
+// if we're defining the CFA in term of esp.
+TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x0e, // push cs
+ 0x16, // push ss
+ 0x1e, // push ds
+ 0x06, // push es
+
+ 0x07, // pop es
+ 0x1f, // pop ds
+ 0x17, // pop ss
+
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(4);
+ EXPECT_EQ(4ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(7);
+ EXPECT_EQ(7ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x55, // push %rbp/ebp
+ 0xc9, // leave
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
+}
+
+// In i386, which lacks pc-relative addressing, a common code sequence
+// is to call the next instruction (i.e. call imm32, value of 0) which
+// pushes the addr of the next insn on the stack, and then pop that value
+// into a register (the "pic base" register).
+TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0xe8, 0x00, 0x00, 0x00, 0x00, // call 0
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(5);
+ EXPECT_EQ(5ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x55, // pushq %rbp
+ 0x48, 0x89, 0xe5, // movq %rsp, %rbp
+ 0x4c, 0x89, 0x75, 0xc0, // movq %r14, -0x40(%rbp)
+ 0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq %r15, -0x5d8(%rbp)
+ 0x48, 0x89, 0x5d, 0xb8, // movq %rbx, -0x48(%rbp)
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(19);
+ EXPECT_EQ(19ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
+ EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-80, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-1512, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-88, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x55, // pushl %ebp
+ 0x89, 0xe5, // movl %esp, %ebp
+ 0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)
+ 0x89, 0x75, 0xe0, // movl %esi, -0x20(%ebp)
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(12);
+ EXPECT_EQ(12ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-344, regloc.GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-40, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x55, // pushq %rbp
+ 0x48, 0x89, 0xe5, // movq %rsp, %rbp
+
+ // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
+ // has a bug where it can't augment a function that is just
+ // prologue+epilogue - it needs at least one other instruction
+ // in between.
+ 0x90, // nop
+
+ 0x5d, // popq %rbp
+ 0xc3 // retq
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ unwind_plan.SetSourceName("unit testing hand-created unwind plan");
+ unwind_plan.SetPlanValidAddressRange(sample_range);
+ unwind_plan.SetRegisterKind(eRegisterKindLLDB);
+
+ row_sp.reset(new UnwindPlan::Row);
+
+ // Describe offset 0
+ row_sp->SetOffset(0);
+ row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);
+
+ regloc.SetAtCFAPlusOffset(-8);
+ row_sp->SetRegisterInfo(k_rip, regloc);
+
+ unwind_plan.AppendRow(row_sp);
+
+ // Allocate a new Row, populate it with the existing Row contents.
+ UnwindPlan::Row *new_row = new UnwindPlan::Row;
+ *new_row = *row_sp.get();
+ row_sp.reset(new_row);
+
+ // Describe offset 1
+ row_sp->SetOffset(1);
+ row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
+ regloc.SetAtCFAPlusOffset(-16);
+ row_sp->SetRegisterInfo(k_rbp, regloc);
+ unwind_plan.AppendRow(row_sp);
+
+ // Allocate a new Row, populate it with the existing Row contents.
+ new_row = new UnwindPlan::Row;
+ *new_row = *row_sp.get();
+ row_sp.reset(new_row);
+
+ // Describe offset 4
+ row_sp->SetOffset(4);
+ row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rbp, 16);
+ unwind_plan.AppendRow(row_sp);
+
+ RegisterContextSP reg_ctx_sp;
+ EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
+ data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(6);
+ EXPECT_EQ(6ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
+ // doesn't track register restores (pop'ing a reg value back from
+ // the stack) - it was just written to make stepping work correctly.
+ // Technically we should be able to do the following test, but it
+ // won't work today - the unwind plan will still say that the caller's
+ // rbp is on the stack.
+ // EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x55, // pushl %ebp
+ 0x89, 0xe5, // movl %esp, %ebp
+
+ // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
+ // has a bug where it can't augment a function that is just
+ // prologue+epilogue - it needs at least one other instruction
+ // in between.
+ 0x90, // nop
+
+ 0x5d, // popl %ebp
+ 0xc3 // retl
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ unwind_plan.SetSourceName("unit testing hand-created unwind plan");
+ unwind_plan.SetPlanValidAddressRange(sample_range);
+ unwind_plan.SetRegisterKind(eRegisterKindLLDB);
+
+ row_sp.reset(new UnwindPlan::Row);
+
+ // Describe offset 0
+ row_sp->SetOffset(0);
+ row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 4);
+
+ regloc.SetAtCFAPlusOffset(-4);
+ row_sp->SetRegisterInfo(k_eip, regloc);
+
+ unwind_plan.AppendRow(row_sp);
+
+ // Allocate a new Row, populate it with the existing Row contents.
+ UnwindPlan::Row *new_row = new UnwindPlan::Row;
+ *new_row = *row_sp.get();
+ row_sp.reset(new_row);
+
+ // Describe offset 1
+ row_sp->SetOffset(1);
+ row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 8);
+ regloc.SetAtCFAPlusOffset(-8);
+ row_sp->SetRegisterInfo(k_ebp, regloc);
+ unwind_plan.AppendRow(row_sp);
+
+ // Allocate a new Row, populate it with the existing Row contents.
+ new_row = new UnwindPlan::Row;
+ *new_row = *row_sp.get();
+ row_sp.reset(new_row);
+
+ // Describe offset 3
+ row_sp->SetOffset(3);
+ row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_ebp, 8);
+ unwind_plan.AppendRow(row_sp);
+
+ RegisterContextSP reg_ctx_sp;
+ EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite(
+ data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(5);
+ EXPECT_EQ(5ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+
+ // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
+ // doesn't track register restores (pop'ing a reg value back from
+ // the stack) - it was just written to make stepping work correctly.
+ // Technically we should be able to do the following test, but it
+ // won't work today - the unwind plan will still say that the caller's
+ // ebp is on the stack.
+ // EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
+}
+
+// Check that the i386 disassembler disassembles past an opcode that
+// is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler
+// stops
+// disassembling at that point (long-mode).
+TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) {
+ UnwindPlan::Row::RegisterLocation regloc;
+ UnwindPlan::RowSP row_sp;
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x43, // incl $ebx --- an invalid opcode in 64-bit mode
+ 0x55, // pushl %ebp
+ 0x90 // nop
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(2ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
+ EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+ EXPECT_EQ(-8, regloc.GetOffset());
+
+ unwind_plan.Clear();
+
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ row_sp = unwind_plan.GetRowForFunctionOffset(2);
+ EXPECT_EQ(0ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
+}
diff --git a/unittests/Utility/CMakeLists.txt b/unittests/Utility/CMakeLists.txt
index 99677a47d7cc..15a29825f1da 100644
--- a/unittests/Utility/CMakeLists.txt
+++ b/unittests/Utility/CMakeLists.txt
@@ -2,6 +2,7 @@ add_lldb_unittest(UtilityTests
ModuleCacheTest.cpp
StringExtractorTest.cpp
TaskPoolTest.cpp
+ TimeoutTest.cpp
UriParserTest.cpp
)
diff --git a/unittests/Utility/Inputs/TestModule.c b/unittests/Utility/Inputs/TestModule.c
index 12374e1f7c65..6347f7264944 100644
--- a/unittests/Utility/Inputs/TestModule.c
+++ b/unittests/Utility/Inputs/TestModule.c
@@ -1,10 +1,9 @@
// Compile with $CC -nostdlib -shared TestModule.c -o TestModule.so
-// The actual contents of the test module is not important here. I am using this because it
+// The actual contents of the test module is not important here. I am using this
+// because it
// produces an extremely tiny (but still perfectly valid) module.
-void
-boom(void)
-{
- char *BOOM;
- *BOOM = 47;
+void boom(void) {
+ char *BOOM;
+ *BOOM = 47;
}
diff --git a/unittests/Utility/ModuleCacheTest.cpp b/unittests/Utility/ModuleCacheTest.cpp
index 53bfc882f232..911c278c1626 100644
--- a/unittests/Utility/ModuleCacheTest.cpp
+++ b/unittests/Utility/ModuleCacheTest.cpp
@@ -16,24 +16,20 @@ extern const char *TestMainArgv0;
using namespace lldb_private;
using namespace lldb;
-namespace
-{
+namespace {
-class ModuleCacheTest : public testing::Test
-{
+class ModuleCacheTest : public testing::Test {
public:
- static void
- SetUpTestCase();
+ static void SetUpTestCase();
- static void
- TearDownTestCase();
+ static void TearDownTestCase();
protected:
- static FileSpec s_cache_dir;
- static llvm::SmallString<128> s_test_executable;
+ static FileSpec s_cache_dir;
+ static llvm::SmallString<128> s_test_executable;
- void
- TryGetAndPut(const FileSpec &cache_dir, const char *hostname, bool expect_download);
+ void TryGetAndPut(const FileSpec &cache_dir, const char *hostname,
+ bool expect_download);
};
}
@@ -43,137 +39,131 @@ llvm::SmallString<128> ModuleCacheTest::s_test_executable;
static const char dummy_hostname[] = "dummy_hostname";
static const char dummy_remote_dir[] = "bin";
static const char module_name[] = "TestModule.so";
-static const char module_uuid[] = "F4E7E991-9B61-6AD4-0073-561AC3D9FA10-C043A476";
+static const char module_uuid[] =
+ "F4E7E991-9B61-6AD4-0073-561AC3D9FA10-C043A476";
static const uint32_t uuid_bytes = 20;
static const size_t module_size = 5602;
-static FileSpec
-GetDummyRemotePath()
-{
- FileSpec fs("/", false, FileSpec::ePathSyntaxPosix);
- fs.AppendPathComponent(dummy_remote_dir);
- fs.AppendPathComponent(module_name);
- return fs;
+static FileSpec GetDummyRemotePath() {
+ FileSpec fs("/", false, FileSpec::ePathSyntaxPosix);
+ fs.AppendPathComponent(dummy_remote_dir);
+ fs.AppendPathComponent(module_name);
+ return fs;
}
-static FileSpec
-GetUuidView(FileSpec spec)
-{
- spec.AppendPathComponent(".cache");
- spec.AppendPathComponent(module_uuid);
- spec.AppendPathComponent(module_name);
- return spec;
+static FileSpec GetUuidView(FileSpec spec) {
+ spec.AppendPathComponent(".cache");
+ spec.AppendPathComponent(module_uuid);
+ spec.AppendPathComponent(module_name);
+ return spec;
}
-static FileSpec
-GetSysrootView(FileSpec spec, const char *hostname)
-{
- spec.AppendPathComponent(hostname);
- spec.AppendPathComponent(dummy_remote_dir);
- spec.AppendPathComponent(module_name);
- return spec;
+static FileSpec GetSysrootView(FileSpec spec, const char *hostname) {
+ spec.AppendPathComponent(hostname);
+ spec.AppendPathComponent(dummy_remote_dir);
+ spec.AppendPathComponent(module_name);
+ return spec;
}
-void
-ModuleCacheTest::SetUpTestCase()
-{
- HostInfo::Initialize();
- ObjectFileELF::Initialize();
+void ModuleCacheTest::SetUpTestCase() {
+ HostInfo::Initialize();
+ ObjectFileELF::Initialize();
- FileSpec tmpdir_spec;
- HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, s_cache_dir);
+ FileSpec tmpdir_spec;
+ HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, s_cache_dir);
- llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0);
- s_test_executable = exe_folder;
- llvm::sys::path::append(s_test_executable, "Inputs", module_name);
+ llvm::StringRef exe_folder = llvm::sys::path::parent_path(TestMainArgv0);
+ s_test_executable = exe_folder;
+ llvm::sys::path::append(s_test_executable, "Inputs", module_name);
}
-void
-ModuleCacheTest::TearDownTestCase()
-{
- ObjectFileELF::Terminate();
- HostInfo::Terminate();
+void ModuleCacheTest::TearDownTestCase() {
+ ObjectFileELF::Terminate();
+ HostInfo::Terminate();
}
-static void
-VerifyDiskState(const FileSpec &cache_dir, const char *hostname)
-{
- FileSpec uuid_view = GetUuidView(cache_dir);
- EXPECT_TRUE(uuid_view.Exists()) << "uuid_view is: " << uuid_view.GetCString();
- EXPECT_EQ(module_size, uuid_view.GetByteSize());
+static void VerifyDiskState(const FileSpec &cache_dir, const char *hostname) {
+ FileSpec uuid_view = GetUuidView(cache_dir);
+ EXPECT_TRUE(uuid_view.Exists()) << "uuid_view is: " << uuid_view.GetCString();
+ EXPECT_EQ(module_size, uuid_view.GetByteSize());
- FileSpec sysroot_view = GetSysrootView(cache_dir, hostname);
- EXPECT_TRUE(sysroot_view.Exists()) << "sysroot_view is: " << sysroot_view.GetCString();
- EXPECT_EQ(module_size, sysroot_view.GetByteSize());
+ FileSpec sysroot_view = GetSysrootView(cache_dir, hostname);
+ EXPECT_TRUE(sysroot_view.Exists()) << "sysroot_view is: "
+ << sysroot_view.GetCString();
+ EXPECT_EQ(module_size, sysroot_view.GetByteSize());
}
-void
-ModuleCacheTest::TryGetAndPut(const FileSpec &cache_dir, const char *hostname, bool expect_download)
-{
- ModuleCache mc;
- ModuleSpec module_spec;
- module_spec.GetFileSpec() = GetDummyRemotePath();
- module_spec.GetUUID().SetFromCString(module_uuid, uuid_bytes);
- module_spec.SetObjectSize(module_size);
- ModuleSP module_sp;
- bool did_create;
- bool download_called = false;
-
- Error error = mc.GetAndPut(
- cache_dir, hostname, module_spec,
- [this, &download_called](const ModuleSpec &module_spec, const FileSpec &tmp_download_file_spec) {
- download_called = true;
- EXPECT_STREQ(GetDummyRemotePath().GetCString(), module_spec.GetFileSpec().GetCString());
- std::error_code ec = llvm::sys::fs::copy_file(s_test_executable, tmp_download_file_spec.GetCString());
- EXPECT_FALSE(ec);
- return Error();
- },
- [](const ModuleSP &module_sp, const FileSpec &tmp_download_file_spec) { return Error("Not supported."); },
- module_sp, &did_create);
- EXPECT_EQ(expect_download, download_called);
-
- EXPECT_TRUE(error.Success()) << "Error was: " << error.AsCString();
- EXPECT_TRUE(did_create);
- ASSERT_TRUE(bool(module_sp));
-
- SymbolContextList sc_list;
- EXPECT_EQ(1u, module_sp->FindFunctionSymbols(ConstString("boom"), eFunctionNameTypeFull, sc_list));
- EXPECT_STREQ(GetDummyRemotePath().GetCString(), module_sp->GetPlatformFileSpec().GetCString());
- EXPECT_STREQ(module_uuid, module_sp->GetUUID().GetAsString().c_str());
+void ModuleCacheTest::TryGetAndPut(const FileSpec &cache_dir,
+ const char *hostname, bool expect_download) {
+ ModuleCache mc;
+ ModuleSpec module_spec;
+ module_spec.GetFileSpec() = GetDummyRemotePath();
+ module_spec.GetUUID().SetFromCString(module_uuid, uuid_bytes);
+ module_spec.SetObjectSize(module_size);
+ ModuleSP module_sp;
+ bool did_create;
+ bool download_called = false;
+
+ Error error = mc.GetAndPut(
+ cache_dir, hostname, module_spec,
+ [this, &download_called](const ModuleSpec &module_spec,
+ const FileSpec &tmp_download_file_spec) {
+ download_called = true;
+ EXPECT_STREQ(GetDummyRemotePath().GetCString(),
+ module_spec.GetFileSpec().GetCString());
+ std::error_code ec = llvm::sys::fs::copy_file(
+ s_test_executable, tmp_download_file_spec.GetCString());
+ EXPECT_FALSE(ec);
+ return Error();
+ },
+ [](const ModuleSP &module_sp, const FileSpec &tmp_download_file_spec) {
+ return Error("Not supported.");
+ },
+ module_sp, &did_create);
+ EXPECT_EQ(expect_download, download_called);
+
+ EXPECT_TRUE(error.Success()) << "Error was: " << error.AsCString();
+ EXPECT_TRUE(did_create);
+ ASSERT_TRUE(bool(module_sp));
+
+ SymbolContextList sc_list;
+ EXPECT_EQ(1u, module_sp->FindFunctionSymbols(ConstString("boom"),
+ eFunctionNameTypeFull, sc_list));
+ EXPECT_STREQ(GetDummyRemotePath().GetCString(),
+ module_sp->GetPlatformFileSpec().GetCString());
+ EXPECT_STREQ(module_uuid, module_sp->GetUUID().GetAsString().c_str());
}
-TEST_F(ModuleCacheTest, GetAndPut)
-{
- FileSpec test_cache_dir = s_cache_dir;
- test_cache_dir.AppendPathComponent("GetAndPut");
+TEST_F(ModuleCacheTest, GetAndPut) {
+ FileSpec test_cache_dir = s_cache_dir;
+ test_cache_dir.AppendPathComponent("GetAndPut");
- const bool expect_download = true;
- TryGetAndPut(test_cache_dir, dummy_hostname, expect_download);
- VerifyDiskState(test_cache_dir, dummy_hostname);
+ const bool expect_download = true;
+ TryGetAndPut(test_cache_dir, dummy_hostname, expect_download);
+ VerifyDiskState(test_cache_dir, dummy_hostname);
}
-TEST_F(ModuleCacheTest, GetAndPutUuidExists)
-{
- FileSpec test_cache_dir = s_cache_dir;
- test_cache_dir.AppendPathComponent("GetAndPutUuidExists");
+TEST_F(ModuleCacheTest, GetAndPutUuidExists) {
+ FileSpec test_cache_dir = s_cache_dir;
+ test_cache_dir.AppendPathComponent("GetAndPutUuidExists");
- FileSpec uuid_view = GetUuidView(test_cache_dir);
- std::error_code ec = llvm::sys::fs::create_directories(uuid_view.GetDirectory().GetCString());
- ASSERT_FALSE(ec);
- ec = llvm::sys::fs::copy_file(s_test_executable, uuid_view.GetCString());
- ASSERT_FALSE(ec);
+ FileSpec uuid_view = GetUuidView(test_cache_dir);
+ std::error_code ec =
+ llvm::sys::fs::create_directories(uuid_view.GetDirectory().GetCString());
+ ASSERT_FALSE(ec);
+ ec = llvm::sys::fs::copy_file(s_test_executable, uuid_view.GetCString());
+ ASSERT_FALSE(ec);
- const bool expect_download = false;
- TryGetAndPut(test_cache_dir, dummy_hostname, expect_download);
- VerifyDiskState(test_cache_dir, dummy_hostname);
+ const bool expect_download = false;
+ TryGetAndPut(test_cache_dir, dummy_hostname, expect_download);
+ VerifyDiskState(test_cache_dir, dummy_hostname);
}
-TEST_F(ModuleCacheTest, GetAndPutStrangeHostname)
-{
- FileSpec test_cache_dir = s_cache_dir;
- test_cache_dir.AppendPathComponent("GetAndPutStrangeHostname");
+TEST_F(ModuleCacheTest, GetAndPutStrangeHostname) {
+ FileSpec test_cache_dir = s_cache_dir;
+ test_cache_dir.AppendPathComponent("GetAndPutStrangeHostname");
- const bool expect_download = true;
- TryGetAndPut(test_cache_dir, "tab\tcolon:asterisk*", expect_download);
- VerifyDiskState(test_cache_dir, "tab_colon_asterisk_");
+ const bool expect_download = true;
+ TryGetAndPut(test_cache_dir, "tab\tcolon:asterisk*", expect_download);
+ VerifyDiskState(test_cache_dir, "tab_colon_asterisk_");
}
diff --git a/unittests/Utility/StringExtractorTest.cpp b/unittests/Utility/StringExtractorTest.cpp
index 0eb6d1bda8bb..6a67a8c3a150 100644
--- a/unittests/Utility/StringExtractorTest.cpp
+++ b/unittests/Utility/StringExtractorTest.cpp
@@ -1,406 +1,698 @@
-#include <limits.h>
#include "gtest/gtest.h"
+#include <limits.h>
#include "lldb/Utility/StringExtractor.h"
-namespace
-{
- class StringExtractorTest: public ::testing::Test
- {
- };
+namespace {
+class StringExtractorTest : public ::testing::Test {};
+}
+
+TEST_F(StringExtractorTest, InitEmpty) {
+ const char kEmptyString[] = "";
+ StringExtractor ex(kEmptyString);
+
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(0u, ex.GetFilePos());
+ ASSERT_STREQ(kEmptyString, ex.GetStringRef().c_str());
+ ASSERT_EQ(true, ex.Empty());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(nullptr, ex.Peek());
+}
+
+TEST_F(StringExtractorTest, InitMisc) {
+ const char kInitMiscString[] = "Hello, StringExtractor!";
+ StringExtractor ex(kInitMiscString);
+
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(0u, ex.GetFilePos());
+ ASSERT_STREQ(kInitMiscString, ex.GetStringRef().c_str());
+ ASSERT_EQ(false, ex.Empty());
+ ASSERT_EQ(sizeof(kInitMiscString) - 1, ex.GetBytesLeft());
+ ASSERT_EQ(kInitMiscString[0], *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, DecodeHexU8_Underflow) {
+ const char kEmptyString[] = "";
+ StringExtractor ex(kEmptyString);
+
+ ASSERT_EQ(-1, ex.DecodeHexU8());
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(0u, ex.GetFilePos());
+ ASSERT_EQ(true, ex.Empty());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(nullptr, ex.Peek());
+}
+
+TEST_F(StringExtractorTest, DecodeHexU8_Underflow2) {
+ const char kEmptyString[] = "1";
+ StringExtractor ex(kEmptyString);
+
+ ASSERT_EQ(-1, ex.DecodeHexU8());
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(0u, ex.GetFilePos());
+ ASSERT_EQ(1u, ex.GetBytesLeft());
+ ASSERT_EQ('1', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, DecodeHexU8_InvalidHex) {
+ const char kInvalidHex[] = "xa";
+ StringExtractor ex(kInvalidHex);
+
+ ASSERT_EQ(-1, ex.DecodeHexU8());
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(0u, ex.GetFilePos());
+ ASSERT_EQ(2u, ex.GetBytesLeft());
+ ASSERT_EQ('x', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, DecodeHexU8_InvalidHex2) {
+ const char kInvalidHex[] = "ax";
+ StringExtractor ex(kInvalidHex);
+
+ ASSERT_EQ(-1, ex.DecodeHexU8());
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(0u, ex.GetFilePos());
+ ASSERT_EQ(2u, ex.GetBytesLeft());
+ ASSERT_EQ('a', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, DecodeHexU8_Exact) {
+ const char kValidHexPair[] = "12";
+ StringExtractor ex(kValidHexPair);
+
+ ASSERT_EQ(0x12, ex.DecodeHexU8());
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(2u, ex.GetFilePos());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(nullptr, ex.Peek());
+}
+
+TEST_F(StringExtractorTest, DecodeHexU8_Extra) {
+ const char kValidHexPair[] = "1234";
+ StringExtractor ex(kValidHexPair);
+
+ ASSERT_EQ(0x12, ex.DecodeHexU8());
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(2u, ex.GetFilePos());
+ ASSERT_EQ(2u, ex.GetBytesLeft());
+ ASSERT_EQ('3', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, GetHexU8_Underflow) {
+ const char kEmptyString[] = "";
+ StringExtractor ex(kEmptyString);
+
+ ASSERT_EQ(0xab, ex.GetHexU8(0xab));
+ ASSERT_EQ(false, ex.IsGood());
+ ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
+ ASSERT_EQ(true, ex.Empty());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(nullptr, ex.Peek());
}
-TEST_F (StringExtractorTest, InitEmpty)
-{
- const char kEmptyString[] = "";
- StringExtractor ex (kEmptyString);
+TEST_F(StringExtractorTest, GetHexU8_Underflow2) {
+ const char kOneNibble[] = "1";
+ StringExtractor ex(kOneNibble);
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (0u, ex.GetFilePos());
- ASSERT_STREQ (kEmptyString, ex.GetStringRef().c_str());
- ASSERT_EQ (true, ex.Empty());
- ASSERT_EQ (0u, ex.GetBytesLeft());
- ASSERT_EQ (nullptr, ex.Peek());
+ ASSERT_EQ(0xbc, ex.GetHexU8(0xbc));
+ ASSERT_EQ(false, ex.IsGood());
+ ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(nullptr, ex.Peek());
}
-TEST_F (StringExtractorTest, InitMisc)
-{
- const char kInitMiscString[] = "Hello, StringExtractor!";
- StringExtractor ex (kInitMiscString);
+TEST_F(StringExtractorTest, GetHexU8_InvalidHex) {
+ const char kInvalidHex[] = "xx";
+ StringExtractor ex(kInvalidHex);
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (0u, ex.GetFilePos());
- ASSERT_STREQ (kInitMiscString, ex.GetStringRef().c_str());
- ASSERT_EQ (false, ex.Empty());
- ASSERT_EQ (sizeof(kInitMiscString)-1, ex.GetBytesLeft());
- ASSERT_EQ (kInitMiscString[0], *ex.Peek());
+ ASSERT_EQ(0xcd, ex.GetHexU8(0xcd));
+ ASSERT_EQ(false, ex.IsGood());
+ ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(nullptr, ex.Peek());
}
-TEST_F (StringExtractorTest, DecodeHexU8_Underflow)
-{
- const char kEmptyString[] = "";
- StringExtractor ex (kEmptyString);
+TEST_F(StringExtractorTest, GetHexU8_Exact) {
+ const char kValidHexPair[] = "12";
+ StringExtractor ex(kValidHexPair);
- ASSERT_EQ (-1, ex.DecodeHexU8());
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (0u, ex.GetFilePos());
- ASSERT_EQ (true, ex.Empty());
- ASSERT_EQ (0u, ex.GetBytesLeft());
- ASSERT_EQ (nullptr, ex.Peek());
+ ASSERT_EQ(0x12, ex.GetHexU8(0x12));
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(2u, ex.GetFilePos());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(nullptr, ex.Peek());
}
-TEST_F (StringExtractorTest, DecodeHexU8_Underflow2)
-{
- const char kEmptyString[] = "1";
- StringExtractor ex (kEmptyString);
-
- ASSERT_EQ (-1, ex.DecodeHexU8());
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (0u, ex.GetFilePos());
- ASSERT_EQ (1u, ex.GetBytesLeft());
- ASSERT_EQ ('1', *ex.Peek());
+TEST_F(StringExtractorTest, GetHexU8_Extra) {
+ const char kValidHexPair[] = "1234";
+ StringExtractor ex(kValidHexPair);
+
+ ASSERT_EQ(0x12, ex.GetHexU8(0x12));
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(2u, ex.GetFilePos());
+ ASSERT_EQ(2u, ex.GetBytesLeft());
+ ASSERT_EQ('3', *ex.Peek());
}
-TEST_F (StringExtractorTest, DecodeHexU8_InvalidHex)
-{
- const char kInvalidHex[] = "xa";
- StringExtractor ex (kInvalidHex);
-
- ASSERT_EQ (-1, ex.DecodeHexU8());
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (0u, ex.GetFilePos());
- ASSERT_EQ (2u, ex.GetBytesLeft());
- ASSERT_EQ ('x', *ex.Peek());
+TEST_F(StringExtractorTest, GetHexU8_Underflow_NoEof) {
+ const char kEmptyString[] = "";
+ StringExtractor ex(kEmptyString);
+ const bool kSetEofOnFail = false;
+
+ ASSERT_EQ(0xab, ex.GetHexU8(0xab, kSetEofOnFail));
+ ASSERT_EQ(false, ex.IsGood()); // this result seems inconsistent with
+ // kSetEofOnFail == false
+ ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
+ ASSERT_EQ(true, ex.Empty());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(nullptr, ex.Peek());
}
-TEST_F (StringExtractorTest, DecodeHexU8_InvalidHex2)
-{
- const char kInvalidHex[] = "ax";
- StringExtractor ex (kInvalidHex);
-
- ASSERT_EQ (-1, ex.DecodeHexU8());
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (0u, ex.GetFilePos());
- ASSERT_EQ (2u, ex.GetBytesLeft());
- ASSERT_EQ ('a', *ex.Peek());
+TEST_F(StringExtractorTest, GetHexU8_Underflow2_NoEof) {
+ const char kOneNibble[] = "1";
+ StringExtractor ex(kOneNibble);
+ const bool kSetEofOnFail = false;
+
+ ASSERT_EQ(0xbc, ex.GetHexU8(0xbc, kSetEofOnFail));
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(0u, ex.GetFilePos());
+ ASSERT_EQ(1u, ex.GetBytesLeft());
+ ASSERT_EQ('1', *ex.Peek());
}
-TEST_F (StringExtractorTest, DecodeHexU8_Exact)
-{
- const char kValidHexPair[] = "12";
- StringExtractor ex (kValidHexPair);
-
- ASSERT_EQ (0x12, ex.DecodeHexU8());
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (2u, ex.GetFilePos());
- ASSERT_EQ (0u, ex.GetBytesLeft());
- ASSERT_EQ (nullptr, ex.Peek());
-}
+TEST_F(StringExtractorTest, GetHexU8_InvalidHex_NoEof) {
+ const char kInvalidHex[] = "xx";
+ StringExtractor ex(kInvalidHex);
+ const bool kSetEofOnFail = false;
-TEST_F (StringExtractorTest, DecodeHexU8_Extra)
-{
- const char kValidHexPair[] = "1234";
- StringExtractor ex (kValidHexPair);
-
- ASSERT_EQ (0x12, ex.DecodeHexU8());
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (2u, ex.GetFilePos());
- ASSERT_EQ (2u, ex.GetBytesLeft());
- ASSERT_EQ ('3', *ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_Underflow)
-{
- const char kEmptyString[] = "";
- StringExtractor ex (kEmptyString);
-
- ASSERT_EQ (0xab, ex.GetHexU8(0xab));
- ASSERT_EQ (false, ex.IsGood());
- ASSERT_EQ (UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ (true, ex.Empty());
- ASSERT_EQ (0u, ex.GetBytesLeft());
- ASSERT_EQ (nullptr, ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_Underflow2)
-{
- const char kOneNibble[] = "1";
- StringExtractor ex (kOneNibble);
-
- ASSERT_EQ (0xbc, ex.GetHexU8(0xbc));
- ASSERT_EQ (false, ex.IsGood());
- ASSERT_EQ (UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ (0u, ex.GetBytesLeft());
- ASSERT_EQ (nullptr, ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_InvalidHex)
-{
- const char kInvalidHex[] = "xx";
- StringExtractor ex (kInvalidHex);
-
- ASSERT_EQ (0xcd, ex.GetHexU8(0xcd));
- ASSERT_EQ (false, ex.IsGood());
- ASSERT_EQ (UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ (0u, ex.GetBytesLeft());
- ASSERT_EQ (nullptr, ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_Exact)
-{
- const char kValidHexPair[] = "12";
- StringExtractor ex (kValidHexPair);
-
- ASSERT_EQ (0x12, ex.GetHexU8(0x12));
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (2u, ex.GetFilePos());
- ASSERT_EQ (0u, ex.GetBytesLeft());
- ASSERT_EQ (nullptr, ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_Extra)
-{
- const char kValidHexPair[] = "1234";
- StringExtractor ex (kValidHexPair);
-
- ASSERT_EQ (0x12, ex.GetHexU8(0x12));
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (2u, ex.GetFilePos());
- ASSERT_EQ (2u, ex.GetBytesLeft());
- ASSERT_EQ ('3', *ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_Underflow_NoEof)
-{
- const char kEmptyString[] = "";
- StringExtractor ex (kEmptyString);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ (0xab, ex.GetHexU8(0xab, kSetEofOnFail));
- ASSERT_EQ (false, ex.IsGood()); // this result seems inconsistent with kSetEofOnFail == false
- ASSERT_EQ (UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ (true, ex.Empty());
- ASSERT_EQ (0u, ex.GetBytesLeft());
- ASSERT_EQ (nullptr, ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_Underflow2_NoEof)
-{
- const char kOneNibble[] = "1";
- StringExtractor ex (kOneNibble);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ (0xbc, ex.GetHexU8(0xbc, kSetEofOnFail));
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (0u, ex.GetFilePos());
- ASSERT_EQ (1u, ex.GetBytesLeft());
- ASSERT_EQ ('1', *ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_InvalidHex_NoEof)
-{
- const char kInvalidHex[] = "xx";
- StringExtractor ex (kInvalidHex);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ (0xcd, ex.GetHexU8(0xcd, kSetEofOnFail));
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (0u, ex.GetFilePos());
- ASSERT_EQ (2u, ex.GetBytesLeft());
- ASSERT_EQ ('x', *ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_Exact_NoEof)
-{
- const char kValidHexPair[] = "12";
- StringExtractor ex (kValidHexPair);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ (0x12, ex.GetHexU8(0x12, kSetEofOnFail));
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (2u, ex.GetFilePos());
- ASSERT_EQ (0u, ex.GetBytesLeft());
- ASSERT_EQ (nullptr, ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexU8_Extra_NoEof)
-{
- const char kValidHexPair[] = "1234";
- StringExtractor ex (kValidHexPair);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ (0x12, ex.GetHexU8(0x12, kSetEofOnFail));
- ASSERT_EQ (true, ex.IsGood());
- ASSERT_EQ (2u, ex.GetFilePos());
- ASSERT_EQ (2u, ex.GetBytesLeft());
- ASSERT_EQ ('3', *ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexBytes)
-{
- const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[kValidHexPairs];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytes (dst, kValidHexPairs, 0xde));
- EXPECT_EQ(0xab,dst[0]);
- EXPECT_EQ(0xcd,dst[1]);
- EXPECT_EQ(0xef,dst[2]);
- EXPECT_EQ(0x01,dst[3]);
- EXPECT_EQ(0x23,dst[4]);
- EXPECT_EQ(0x45,dst[5]);
- EXPECT_EQ(0x67,dst[6]);
- EXPECT_EQ(0x89,dst[7]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2*kValidHexPairs, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(4u, ex.GetBytesLeft());
- ASSERT_EQ('x', *ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexBytes_Underflow)
-{
- const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[12];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytes (dst, sizeof(dst), 0xde));
- EXPECT_EQ(0xab,dst[0]);
- EXPECT_EQ(0xcd,dst[1]);
- EXPECT_EQ(0xef,dst[2]);
- EXPECT_EQ(0x01,dst[3]);
- EXPECT_EQ(0x23,dst[4]);
- EXPECT_EQ(0x45,dst[5]);
- EXPECT_EQ(0x67,dst[6]);
- EXPECT_EQ(0x89,dst[7]);
- // these bytes should be filled with fail_fill_value 0xde
- EXPECT_EQ(0xde,dst[8]);
- EXPECT_EQ(0xde,dst[9]);
- EXPECT_EQ(0xde,dst[10]);
- EXPECT_EQ(0xde,dst[11]);
-
- ASSERT_EQ(false, ex.IsGood());
- ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(0, ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexBytes_Partial)
-{
- const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
- const size_t kReadBytes = 4;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[12];
- memset(dst, 0xab, sizeof(dst));
- ASSERT_EQ(kReadBytes, ex.GetHexBytes (dst, kReadBytes, 0xde));
- EXPECT_EQ(0xab,dst[0]);
- EXPECT_EQ(0xcd,dst[1]);
- EXPECT_EQ(0xef,dst[2]);
- EXPECT_EQ(0x01,dst[3]);
- // these bytes should be unchanged
- EXPECT_EQ(0xab,dst[4]);
- EXPECT_EQ(0xab,dst[5]);
- EXPECT_EQ(0xab,dst[6]);
- EXPECT_EQ(0xab,dst[7]);
- EXPECT_EQ(0xab,dst[8]);
- EXPECT_EQ(0xab,dst[9]);
- EXPECT_EQ(0xab,dst[10]);
- EXPECT_EQ(0xab,dst[11]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(kReadBytes*2, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(12u, ex.GetBytesLeft());
- ASSERT_EQ('2', *ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexBytesAvail)
-{
- const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[kValidHexPairs];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail (dst, kValidHexPairs));
- EXPECT_EQ(0xab,dst[0]);
- EXPECT_EQ(0xcd,dst[1]);
- EXPECT_EQ(0xef,dst[2]);
- EXPECT_EQ(0x01,dst[3]);
- EXPECT_EQ(0x23,dst[4]);
- EXPECT_EQ(0x45,dst[5]);
- EXPECT_EQ(0x67,dst[6]);
- EXPECT_EQ(0x89,dst[7]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2*kValidHexPairs, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(4u, ex.GetBytesLeft());
- ASSERT_EQ('x', *ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexBytesAvail_Underflow)
-{
- const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[12];
- memset(dst, 0xef, sizeof(dst));
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail (dst, sizeof(dst)));
- EXPECT_EQ(0xab,dst[0]);
- EXPECT_EQ(0xcd,dst[1]);
- EXPECT_EQ(0xef,dst[2]);
- EXPECT_EQ(0x01,dst[3]);
- EXPECT_EQ(0x23,dst[4]);
- EXPECT_EQ(0x45,dst[5]);
- EXPECT_EQ(0x67,dst[6]);
- EXPECT_EQ(0x89,dst[7]);
- // these bytes should be unchanged
- EXPECT_EQ(0xef,dst[8]);
- EXPECT_EQ(0xef,dst[9]);
- EXPECT_EQ(0xef,dst[10]);
- EXPECT_EQ(0xef,dst[11]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(kValidHexPairs*2, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(4u, ex.GetBytesLeft());
- ASSERT_EQ('x', *ex.Peek());
-}
-
-TEST_F (StringExtractorTest, GetHexBytesAvail_Partial)
-{
- const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
- const size_t kReadBytes = 4;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[12];
- memset(dst, 0xab, sizeof(dst));
- ASSERT_EQ(kReadBytes, ex.GetHexBytesAvail (dst, kReadBytes));
- EXPECT_EQ(0xab,dst[0]);
- EXPECT_EQ(0xcd,dst[1]);
- EXPECT_EQ(0xef,dst[2]);
- EXPECT_EQ(0x01,dst[3]);
- // these bytes should be unchanged
- EXPECT_EQ(0xab,dst[4]);
- EXPECT_EQ(0xab,dst[5]);
- EXPECT_EQ(0xab,dst[6]);
- EXPECT_EQ(0xab,dst[7]);
- EXPECT_EQ(0xab,dst[8]);
- EXPECT_EQ(0xab,dst[9]);
- EXPECT_EQ(0xab,dst[10]);
- EXPECT_EQ(0xab,dst[11]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(kReadBytes*2, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(12u, ex.GetBytesLeft());
- ASSERT_EQ('2', *ex.Peek());
+ ASSERT_EQ(0xcd, ex.GetHexU8(0xcd, kSetEofOnFail));
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(0u, ex.GetFilePos());
+ ASSERT_EQ(2u, ex.GetBytesLeft());
+ ASSERT_EQ('x', *ex.Peek());
}
+TEST_F(StringExtractorTest, GetHexU8_Exact_NoEof) {
+ const char kValidHexPair[] = "12";
+ StringExtractor ex(kValidHexPair);
+ const bool kSetEofOnFail = false;
+ ASSERT_EQ(0x12, ex.GetHexU8(0x12, kSetEofOnFail));
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(2u, ex.GetFilePos());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(nullptr, ex.Peek());
+}
+
+TEST_F(StringExtractorTest, GetHexU8_Extra_NoEof) {
+ const char kValidHexPair[] = "1234";
+ StringExtractor ex(kValidHexPair);
+ const bool kSetEofOnFail = false;
+
+ ASSERT_EQ(0x12, ex.GetHexU8(0x12, kSetEofOnFail));
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(2u, ex.GetFilePos());
+ ASSERT_EQ(2u, ex.GetBytesLeft());
+ ASSERT_EQ('3', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, GetHexBytes) {
+ const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
+ const size_t kValidHexPairs = 8;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[kValidHexPairs];
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+ EXPECT_EQ(0x89, dst[7]);
+
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(2 * kValidHexPairs, ex.GetFilePos());
+ ASSERT_EQ(false, ex.Empty());
+ ASSERT_EQ(4u, ex.GetBytesLeft());
+ ASSERT_EQ('x', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, GetHexBytes_FullString) {
+ const char kHexEncodedBytes[] = "abcdef0123456789";
+ const size_t kValidHexPairs = 8;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[kValidHexPairs];
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+ EXPECT_EQ(0x89, dst[7]);
+}
+
+TEST_F(StringExtractorTest, GetHexBytes_OddPair) {
+ const char kHexEncodedBytes[] = "abcdef012345678w";
+ const size_t kValidHexPairs = 7;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[8];
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+
+ // This one should be invalid
+ EXPECT_EQ(0xde, dst[7]);
+}
+
+TEST_F(StringExtractorTest, GetHexBytes_OddPair2) {
+ const char kHexEncodedBytes[] = "abcdef012345678";
+ const size_t kValidHexPairs = 7;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[8];
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+
+ EXPECT_EQ(0xde, dst[7]);
+}
+
+TEST_F(StringExtractorTest, GetHexBytes_Underflow) {
+ const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
+ const size_t kValidHexPairs = 8;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[12];
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+ EXPECT_EQ(0x89, dst[7]);
+ // these bytes should be filled with fail_fill_value 0xde
+ EXPECT_EQ(0xde, dst[8]);
+ EXPECT_EQ(0xde, dst[9]);
+ EXPECT_EQ(0xde, dst[10]);
+ EXPECT_EQ(0xde, dst[11]);
+
+ ASSERT_EQ(false, ex.IsGood());
+ ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
+ ASSERT_EQ(false, ex.Empty());
+ ASSERT_EQ(0u, ex.GetBytesLeft());
+ ASSERT_EQ(0, ex.Peek());
+}
+
+TEST_F(StringExtractorTest, GetHexBytes_Partial) {
+ const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
+ const size_t kReadBytes = 4;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[12];
+ memset(dst, 0xab, sizeof(dst));
+ ASSERT_EQ(
+ kReadBytes,
+ ex.GetHexBytes(llvm::MutableArrayRef<uint8_t>(dst, kReadBytes), 0xde));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ // these bytes should be unchanged
+ EXPECT_EQ(0xab, dst[4]);
+ EXPECT_EQ(0xab, dst[5]);
+ EXPECT_EQ(0xab, dst[6]);
+ EXPECT_EQ(0xab, dst[7]);
+ EXPECT_EQ(0xab, dst[8]);
+ EXPECT_EQ(0xab, dst[9]);
+ EXPECT_EQ(0xab, dst[10]);
+ EXPECT_EQ(0xab, dst[11]);
+
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(kReadBytes * 2, ex.GetFilePos());
+ ASSERT_EQ(false, ex.Empty());
+ ASSERT_EQ(12u, ex.GetBytesLeft());
+ ASSERT_EQ('2', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, GetHexBytesAvail) {
+ const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
+ const size_t kValidHexPairs = 8;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[kValidHexPairs];
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+ EXPECT_EQ(0x89, dst[7]);
+
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(2 * kValidHexPairs, ex.GetFilePos());
+ ASSERT_EQ(false, ex.Empty());
+ ASSERT_EQ(4u, ex.GetBytesLeft());
+ ASSERT_EQ('x', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, GetHexBytesAvail_FullString) {
+ const char kHexEncodedBytes[] = "abcdef0123456789";
+ const size_t kValidHexPairs = 8;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[kValidHexPairs];
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+ EXPECT_EQ(0x89, dst[7]);
+}
+
+TEST_F(StringExtractorTest, GetHexBytesAvail_OddPair) {
+ const char kHexEncodedBytes[] = "abcdef012345678w";
+ const size_t kValidHexPairs = 7;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[8];
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+}
+
+TEST_F(StringExtractorTest, GetHexBytesAvail_OddPair2) {
+ const char kHexEncodedBytes[] = "abcdef012345678";
+ const size_t kValidHexPairs = 7;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[8];
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+}
+
+TEST_F(StringExtractorTest, GetHexBytesAvail_Underflow) {
+ const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
+ const size_t kValidHexPairs = 8;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[12];
+ memset(dst, 0xef, sizeof(dst));
+ ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ EXPECT_EQ(0x23, dst[4]);
+ EXPECT_EQ(0x45, dst[5]);
+ EXPECT_EQ(0x67, dst[6]);
+ EXPECT_EQ(0x89, dst[7]);
+ // these bytes should be unchanged
+ EXPECT_EQ(0xef, dst[8]);
+ EXPECT_EQ(0xef, dst[9]);
+ EXPECT_EQ(0xef, dst[10]);
+ EXPECT_EQ(0xef, dst[11]);
+
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(kValidHexPairs * 2, ex.GetFilePos());
+ ASSERT_EQ(false, ex.Empty());
+ ASSERT_EQ(4u, ex.GetBytesLeft());
+ ASSERT_EQ('x', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, GetHexBytesAvail_Partial) {
+ const char kHexEncodedBytes[] = "abcdef0123456789xyzw";
+ const size_t kReadBytes = 4;
+ StringExtractor ex(kHexEncodedBytes);
+
+ uint8_t dst[12];
+ memset(dst, 0xab, sizeof(dst));
+ ASSERT_EQ(kReadBytes, ex.GetHexBytesAvail(
+ llvm::MutableArrayRef<uint8_t>(dst, kReadBytes)));
+ EXPECT_EQ(0xab, dst[0]);
+ EXPECT_EQ(0xcd, dst[1]);
+ EXPECT_EQ(0xef, dst[2]);
+ EXPECT_EQ(0x01, dst[3]);
+ // these bytes should be unchanged
+ EXPECT_EQ(0xab, dst[4]);
+ EXPECT_EQ(0xab, dst[5]);
+ EXPECT_EQ(0xab, dst[6]);
+ EXPECT_EQ(0xab, dst[7]);
+ EXPECT_EQ(0xab, dst[8]);
+ EXPECT_EQ(0xab, dst[9]);
+ EXPECT_EQ(0xab, dst[10]);
+ EXPECT_EQ(0xab, dst[11]);
+
+ ASSERT_EQ(true, ex.IsGood());
+ ASSERT_EQ(kReadBytes * 2, ex.GetFilePos());
+ ASSERT_EQ(false, ex.Empty());
+ ASSERT_EQ(12u, ex.GetBytesLeft());
+ ASSERT_EQ('2', *ex.Peek());
+}
+
+TEST_F(StringExtractorTest, GetNameColonValueSuccess) {
+ const char kNameColonPairs[] = "key1:value1;key2:value2;";
+ StringExtractor ex(kNameColonPairs);
+
+ llvm::StringRef name;
+ llvm::StringRef value;
+ EXPECT_TRUE(ex.GetNameColonValue(name, value));
+ EXPECT_EQ("key1", name);
+ EXPECT_EQ("value1", value);
+ EXPECT_TRUE(ex.GetNameColonValue(name, value));
+ EXPECT_EQ("key2", name);
+ EXPECT_EQ("value2", value);
+ EXPECT_EQ(0u, ex.GetBytesLeft());
+}
+
+TEST_F(StringExtractorTest, GetNameColonValueContainsColon) {
+ const char kNameColonPairs[] = "key1:value1:value2;key2:value3;";
+ StringExtractor ex(kNameColonPairs);
+
+ llvm::StringRef name;
+ llvm::StringRef value;
+ EXPECT_TRUE(ex.GetNameColonValue(name, value));
+ EXPECT_EQ("key1", name);
+ EXPECT_EQ("value1:value2", value);
+ EXPECT_TRUE(ex.GetNameColonValue(name, value));
+ EXPECT_EQ("key2", name);
+ EXPECT_EQ("value3", value);
+ EXPECT_EQ(0u, ex.GetBytesLeft());
+}
+
+TEST_F(StringExtractorTest, GetNameColonValueNoSemicolon) {
+ const char kNameColonPairs[] = "key1:value1";
+ StringExtractor ex(kNameColonPairs);
+
+ llvm::StringRef name;
+ llvm::StringRef value;
+ EXPECT_FALSE(ex.GetNameColonValue(name, value));
+ EXPECT_EQ(0u, ex.GetBytesLeft());
+}
+
+TEST_F(StringExtractorTest, GetNameColonValueNoColon) {
+ const char kNameColonPairs[] = "key1value1;";
+ StringExtractor ex(kNameColonPairs);
+
+ llvm::StringRef name;
+ llvm::StringRef value;
+ EXPECT_FALSE(ex.GetNameColonValue(name, value));
+ EXPECT_EQ(0u, ex.GetBytesLeft());
+}
+
+TEST_F(StringExtractorTest, GetU32LittleEndian) {
+ StringExtractor ex("");
+ EXPECT_EQ(0x0ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("0");
+ EXPECT_EQ(0x0ull, ex.GetHexMaxU32(true, 1));
+
+ ex.Reset("1");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("01");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("001");
+ EXPECT_EQ(0x100ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("12");
+ EXPECT_EQ(0x12ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("123");
+ EXPECT_EQ(0x312ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("1203");
+ EXPECT_EQ(0x312ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("1234");
+ EXPECT_EQ(0x3412ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("12340");
+ EXPECT_EQ(0x3412ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("123400");
+ EXPECT_EQ(0x3412ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("12345670");
+ EXPECT_EQ(0x70563412ull, ex.GetHexMaxU32(true, 0));
+
+ ex.Reset("123456701");
+ EXPECT_EQ(0ull, ex.GetHexMaxU32(true, 0));
+}
+
+TEST_F(StringExtractorTest, GetU32BigEndian) {
+ StringExtractor ex("");
+ EXPECT_EQ(0x0ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("0");
+ EXPECT_EQ(0x0ull, ex.GetHexMaxU32(false, 1));
+
+ ex.Reset("1");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("01");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("001");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("12");
+ EXPECT_EQ(0x12ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("123");
+ EXPECT_EQ(0x123ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("1203");
+ EXPECT_EQ(0x1203ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("1234");
+ EXPECT_EQ(0x1234ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("12340");
+ EXPECT_EQ(0x12340ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("123400");
+ EXPECT_EQ(0x123400ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("12345670");
+ EXPECT_EQ(0x12345670ull, ex.GetHexMaxU32(false, 0));
+
+ ex.Reset("123456700");
+ EXPECT_EQ(0ull, ex.GetHexMaxU32(false, 0));
+}
+
+TEST_F(StringExtractorTest, GetU64LittleEndian) {
+ StringExtractor ex("");
+ EXPECT_EQ(0x0ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("0");
+ EXPECT_EQ(0x0ull, ex.GetHexMaxU64(true, 1));
+
+ ex.Reset("1");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("01");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("001");
+ EXPECT_EQ(0x100ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("12");
+ EXPECT_EQ(0x12ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("123");
+ EXPECT_EQ(0x312ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("1203");
+ EXPECT_EQ(0x312ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("1234");
+ EXPECT_EQ(0x3412ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("12340");
+ EXPECT_EQ(0x3412ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("123400");
+ EXPECT_EQ(0x3412ull, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("123456789ABCDEF0");
+ EXPECT_EQ(0xF0DEBC9A78563412ULL, ex.GetHexMaxU64(true, 0));
+
+ ex.Reset("123456789ABCDEF01");
+ EXPECT_EQ(0ull, ex.GetHexMaxU64(true, 0));
+}
+
+TEST_F(StringExtractorTest, GetU64BigEndian) {
+ StringExtractor ex("");
+ EXPECT_EQ(0x0ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("0");
+ EXPECT_EQ(0x0ull, ex.GetHexMaxU64(false, 1));
+
+ ex.Reset("1");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("01");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("001");
+ EXPECT_EQ(0x1ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("12");
+ EXPECT_EQ(0x12ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("123");
+ EXPECT_EQ(0x123ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("1203");
+ EXPECT_EQ(0x1203ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("1234");
+ EXPECT_EQ(0x1234ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("12340");
+ EXPECT_EQ(0x12340ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("123400");
+ EXPECT_EQ(0x123400ull, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("123456789ABCDEF0");
+ EXPECT_EQ(0x123456789ABCDEF0ULL, ex.GetHexMaxU64(false, 0));
+
+ ex.Reset("123456789ABCDEF000");
+ EXPECT_EQ(0ull, ex.GetHexMaxU64(false, 0));
+}
diff --git a/unittests/Utility/TaskPoolTest.cpp b/unittests/Utility/TaskPoolTest.cpp
index 24431e2c7896..172e32a9c6c0 100644
--- a/unittests/Utility/TaskPoolTest.cpp
+++ b/unittests/Utility/TaskPoolTest.cpp
@@ -2,61 +2,53 @@
#include "lldb/Utility/TaskPool.h"
-TEST (TaskPoolTest, AddTask)
-{
- auto fn = [](int x) { return x * x + 1; };
-
- auto f1 = TaskPool::AddTask(fn, 1);
- auto f2 = TaskPool::AddTask(fn, 2);
- auto f3 = TaskPool::AddTask(fn, 3);
- auto f4 = TaskPool::AddTask(fn, 4);
-
- ASSERT_EQ (10, f3.get());
- ASSERT_EQ ( 2, f1.get());
- ASSERT_EQ (17, f4.get());
- ASSERT_EQ ( 5, f2.get());
+TEST(TaskPoolTest, AddTask) {
+ auto fn = [](int x) { return x * x + 1; };
+
+ auto f1 = TaskPool::AddTask(fn, 1);
+ auto f2 = TaskPool::AddTask(fn, 2);
+ auto f3 = TaskPool::AddTask(fn, 3);
+ auto f4 = TaskPool::AddTask(fn, 4);
+
+ ASSERT_EQ(10, f3.get());
+ ASSERT_EQ(2, f1.get());
+ ASSERT_EQ(17, f4.get());
+ ASSERT_EQ(5, f2.get());
}
-TEST (TaskPoolTest, RunTasks)
-{
- std::vector<int> r(4);
-
- auto fn = [](int x, int& y) { y = x * x + 1; };
-
- TaskPool::RunTasks(
- [fn, &r]() { fn(1, r[0]); },
- [fn, &r]() { fn(2, r[1]); },
- [fn, &r]() { fn(3, r[2]); },
- [fn, &r]() { fn(4, r[3]); }
- );
-
- ASSERT_EQ ( 2, r[0]);
- ASSERT_EQ ( 5, r[1]);
- ASSERT_EQ (10, r[2]);
- ASSERT_EQ (17, r[3]);
+TEST(TaskPoolTest, RunTasks) {
+ std::vector<int> r(4);
+
+ auto fn = [](int x, int &y) { y = x * x + 1; };
+
+ TaskPool::RunTasks([fn, &r]() { fn(1, r[0]); }, [fn, &r]() { fn(2, r[1]); },
+ [fn, &r]() { fn(3, r[2]); }, [fn, &r]() { fn(4, r[3]); });
+
+ ASSERT_EQ(2, r[0]);
+ ASSERT_EQ(5, r[1]);
+ ASSERT_EQ(10, r[2]);
+ ASSERT_EQ(17, r[3]);
}
-TEST (TaskPoolTest, TaskRunner)
-{
- auto fn = [](int x) { return std::make_pair(x, x * x); };
-
- TaskRunner<std::pair<int, int>> tr;
- tr.AddTask(fn, 1);
- tr.AddTask(fn, 2);
- tr.AddTask(fn, 3);
- tr.AddTask(fn, 4);
-
- int count = 0;
- while (true)
- {
- auto f = tr.WaitForNextCompletedTask();
- if (!f.valid())
- break;
-
- ++count;
- std::pair<int, int> v = f.get();
- ASSERT_EQ (v.first * v.first, v.second);
- }
-
- ASSERT_EQ(4, count);
+TEST(TaskPoolTest, TaskRunner) {
+ auto fn = [](int x) { return std::make_pair(x, x * x); };
+
+ TaskRunner<std::pair<int, int>> tr;
+ tr.AddTask(fn, 1);
+ tr.AddTask(fn, 2);
+ tr.AddTask(fn, 3);
+ tr.AddTask(fn, 4);
+
+ int count = 0;
+ while (true) {
+ auto f = tr.WaitForNextCompletedTask();
+ if (!f.valid())
+ break;
+
+ ++count;
+ std::pair<int, int> v = f.get();
+ ASSERT_EQ(v.first * v.first, v.second);
+ }
+
+ ASSERT_EQ(4, count);
}
diff --git a/unittests/Utility/TimeoutTest.cpp b/unittests/Utility/TimeoutTest.cpp
new file mode 100644
index 000000000000..a30c616d411b
--- /dev/null
+++ b/unittests/Utility/TimeoutTest.cpp
@@ -0,0 +1,22 @@
+//===-- TimeoutTest.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Timeout.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace std::chrono;
+
+TEST(TimeoutTest, Construction) {
+ ASSERT_FALSE(Timeout<std::micro>(llvm::None));
+ ASSERT_TRUE(bool(Timeout<std::micro>(seconds(0))));
+ ASSERT_EQ(seconds(0), *Timeout<std::micro>(seconds(0)));
+ ASSERT_EQ(seconds(3), *Timeout<std::micro>(seconds(3)));
+ ASSERT_TRUE(bool(Timeout<std::micro>(Timeout<std::milli>(seconds(0)))));
+}
diff --git a/unittests/Utility/UriParserTest.cpp b/unittests/Utility/UriParserTest.cpp
index fe0a6a70f212..8b08e63eb8c7 100644
--- a/unittests/Utility/UriParserTest.cpp
+++ b/unittests/Utility/UriParserTest.cpp
@@ -1,159 +1,155 @@
-#include "gtest/gtest.h"
#include "Utility/UriParser.h"
+#include "gtest/gtest.h"
-namespace
-{
- class UriParserTest: public ::testing::Test
- {
- };
+namespace {
+class UriParserTest : public ::testing::Test {};
}
// result strings (scheme/hostname/port/path) passed into UriParser::Parse
-// are initialized to kAsdf so we can verify that they are unmodified if the
+// are initialized to kAsdf so we can verify that they are unmodified if the
// URI is invalid
-static const char* kAsdf = "asdf";
+static const char *kAsdf = "asdf";
-class UriTestCase
-{
+class UriTestCase {
public:
- UriTestCase(const char* uri, const char* scheme, const char* hostname, int port, const char* path) :
- m_uri(uri),
- m_result(true),
- m_scheme(scheme),
- m_hostname(hostname),
- m_port(port),
- m_path(path)
- {
- }
-
- UriTestCase(const char* uri) :
- m_uri(uri),
- m_result(false),
- m_scheme(kAsdf),
- m_hostname(kAsdf),
- m_port(1138),
- m_path(kAsdf)
- {
- }
-
- const char* m_uri;
- bool m_result;
- const char* m_scheme;
- const char* m_hostname;
- int m_port;
- const char* m_path;
+ UriTestCase(const char *uri, const char *scheme, const char *hostname,
+ int port, const char *path)
+ : m_uri(uri), m_result(true), m_scheme(scheme), m_hostname(hostname),
+ m_port(port), m_path(path) {}
+
+ UriTestCase(const char *uri)
+ : m_uri(uri), m_result(false), m_scheme(kAsdf), m_hostname(kAsdf),
+ m_port(1138), m_path(kAsdf) {}
+
+ const char *m_uri;
+ bool m_result;
+ const char *m_scheme;
+ const char *m_hostname;
+ int m_port;
+ const char *m_path;
};
-#define VALIDATE \
- std::string scheme(kAsdf); \
- std::string hostname(kAsdf); \
- int port(1138); \
- std::string path(kAsdf); \
- EXPECT_EQ (testCase.m_result, UriParser::Parse(testCase.m_uri, scheme, hostname, port, path)); \
- EXPECT_STREQ (testCase.m_scheme, scheme.c_str()); \
- EXPECT_STREQ (testCase.m_hostname, hostname.c_str()); \
- EXPECT_EQ (testCase.m_port, port); \
- EXPECT_STREQ (testCase.m_path, path.c_str());
+#define VALIDATE \
+ llvm::StringRef scheme(kAsdf); \
+ llvm::StringRef hostname(kAsdf); \
+ int port(1138); \
+ llvm::StringRef path(kAsdf); \
+ EXPECT_EQ(testCase.m_result, \
+ UriParser::Parse(testCase.m_uri, scheme, hostname, port, path)); \
+ EXPECT_STREQ(testCase.m_scheme, scheme.str().c_str()); \
+ EXPECT_STREQ(testCase.m_hostname, hostname.str().c_str()); \
+ EXPECT_EQ(testCase.m_port, port); \
+ EXPECT_STREQ(testCase.m_path, path.str().c_str());
-TEST_F (UriParserTest, Minimal)
-{
- const UriTestCase testCase("x://y", "x", "y", -1, "/");
- VALIDATE
+TEST_F(UriParserTest, Minimal) {
+ const UriTestCase testCase("x://y", "x", "y", -1, "/");
+ VALIDATE
}
-TEST_F (UriParserTest, MinimalPort)
-{
- const UriTestCase testCase("x://y:1", "x", "y", 1, "/");
- VALIDATE
-}
+TEST_F(UriParserTest, MinimalPort) {
+ const UriTestCase testCase("x://y:1", "x", "y", 1, "/");
+ llvm::StringRef scheme(kAsdf);
+ llvm::StringRef hostname(kAsdf);
+ int port(1138);
+ llvm::StringRef path(kAsdf);
+ bool result = UriParser::Parse(testCase.m_uri, scheme, hostname, port, path);
+ EXPECT_EQ(testCase.m_result, result);
-TEST_F (UriParserTest, MinimalPath)
-{
- const UriTestCase testCase("x://y/", "x", "y", -1, "/");
- VALIDATE
+ EXPECT_STREQ(testCase.m_scheme, scheme.str().c_str());
+ EXPECT_STREQ(testCase.m_hostname, hostname.str().c_str());
+ EXPECT_EQ(testCase.m_port, port);
+ EXPECT_STREQ(testCase.m_path, path.str().c_str());
}
-TEST_F (UriParserTest, MinimalPortPath)
-{
- const UriTestCase testCase("x://y:1/", "x", "y", 1, "/");
- VALIDATE
+TEST_F(UriParserTest, MinimalPath) {
+ const UriTestCase testCase("x://y/", "x", "y", -1, "/");
+ VALIDATE
}
-TEST_F (UriParserTest, LongPath)
-{
- const UriTestCase testCase("x://y/abc/def/xyz", "x", "y", -1, "/abc/def/xyz");
- VALIDATE
+TEST_F(UriParserTest, MinimalPortPath) {
+ const UriTestCase testCase("x://y:1/", "x", "y", 1, "/");
+ VALIDATE
}
-TEST_F (UriParserTest, TypicalPortPath)
-{
- const UriTestCase testCase("connect://192.168.100.132:5432/", "connect", "192.168.100.132", 5432, "/");
- VALIDATE
+TEST_F(UriParserTest, LongPath) {
+ const UriTestCase testCase("x://y/abc/def/xyz", "x", "y", -1, "/abc/def/xyz");
+ VALIDATE
}
-TEST_F (UriParserTest, BracketedHostnamePort)
-{
- const UriTestCase testCase("connect://[192.168.100.132]:5432/", "connect", "192.168.100.132", 5432, "/");
- VALIDATE
+TEST_F(UriParserTest, TypicalPortPath) {
+ const UriTestCase testCase("connect://192.168.100.132:5432/", "connect",
+ "192.168.100.132", 5432, "/");
+ VALIDATE;
}
-TEST_F (UriParserTest, BracketedHostname)
-{
- const UriTestCase testCase("connect://[192.168.100.132]", "connect", "192.168.100.132", -1, "/");
- VALIDATE
+TEST_F(UriParserTest, BracketedHostnamePort) {
+ const UriTestCase testCase("connect://[192.168.100.132]:5432/", "connect",
+ "192.168.100.132", 5432, "/");
+ llvm::StringRef scheme(kAsdf);
+ llvm::StringRef hostname(kAsdf);
+ int port(1138);
+ llvm::StringRef path(kAsdf);
+ bool result = UriParser::Parse(testCase.m_uri, scheme, hostname, port, path);
+ EXPECT_EQ(testCase.m_result, result);
+
+ EXPECT_STREQ(testCase.m_scheme, scheme.str().c_str());
+ EXPECT_STREQ(testCase.m_hostname, hostname.str().c_str());
+ EXPECT_EQ(testCase.m_port, port);
+ EXPECT_STREQ(testCase.m_path, path.str().c_str());
}
-TEST_F (UriParserTest, BracketedHostnameWithColon)
-{
- const UriTestCase testCase("connect://[192.168.100.132:5555]:1234", "connect", "192.168.100.132:5555", 1234, "/");
- VALIDATE
+TEST_F(UriParserTest, BracketedHostname) {
+ const UriTestCase testCase("connect://[192.168.100.132]", "connect",
+ "192.168.100.132", -1, "/");
+ VALIDATE
}
-TEST_F (UriParserTest, SchemeHostSeparator)
-{
- const UriTestCase testCase("x:/y");
- VALIDATE
+TEST_F(UriParserTest, BracketedHostnameWithColon) {
+ const UriTestCase testCase("connect://[192.168.100.132:5555]:1234", "connect",
+ "192.168.100.132:5555", 1234, "/");
+ VALIDATE
}
-TEST_F (UriParserTest, SchemeHostSeparator2)
-{
- const UriTestCase testCase("x:y");
- VALIDATE
+TEST_F(UriParserTest, SchemeHostSeparator) {
+ const UriTestCase testCase("x:/y");
+ VALIDATE
}
-TEST_F (UriParserTest, SchemeHostSeparator3)
-{
- const UriTestCase testCase("x//y");
- VALIDATE
+TEST_F(UriParserTest, SchemeHostSeparator2) {
+ const UriTestCase testCase("x:y");
+ VALIDATE
}
-TEST_F (UriParserTest, SchemeHostSeparator4)
-{
- const UriTestCase testCase("x/y");
- VALIDATE
+TEST_F(UriParserTest, SchemeHostSeparator3) {
+ const UriTestCase testCase("x//y");
+ VALIDATE
}
-TEST_F (UriParserTest, BadPort)
-{
- const UriTestCase testCase("x://y:a/");
- VALIDATE
+TEST_F(UriParserTest, SchemeHostSeparator4) {
+ const UriTestCase testCase("x/y");
+ VALIDATE
}
-TEST_F (UriParserTest, BadPort2)
-{
- const UriTestCase testCase("x://y:5432a/");
- VALIDATE
+TEST_F(UriParserTest, BadPort) {
+ const UriTestCase testCase("x://y:a/");
+ VALIDATE
}
-TEST_F (UriParserTest, Empty)
-{
- const UriTestCase testCase("");
- VALIDATE
+TEST_F(UriParserTest, BadPort2) {
+ const UriTestCase testCase("x://y:5432a/");
+ VALIDATE
}
-TEST_F (UriParserTest, PortOverflow)
-{
- const UriTestCase testCase("x://y:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/");
- VALIDATE
+TEST_F(UriParserTest, Empty) {
+ const UriTestCase testCase("");
+ VALIDATE
}
+TEST_F(UriParserTest, PortOverflow) {
+ const UriTestCase testCase("x://"
+ "y:"
+ "0123456789012345678901234567890123456789012345678"
+ "9012345678901234567890123456789012345678901234567"
+ "89/");
+ VALIDATE
+}
diff --git a/unittests/gtest_common.h b/unittests/gtest_common.h
index 006c9596ca4f..c8fe92575941 100644
--- a/unittests/gtest_common.h
+++ b/unittests/gtest_common.h
@@ -17,8 +17,10 @@
// units. Be very leary about putting anything in this file.
#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
-// Due to a bug in <thread>, when _HAS_EXCEPTIONS == 0 the header will try to call
-// uncaught_exception() without having a declaration for it. The fix for this is
+// Due to a bug in <thread>, when _HAS_EXCEPTIONS == 0 the header will try to
+// call
+// uncaught_exception() without having a declaration for it. The fix for this
+// is
// to manually #include <eh.h>, which contains this declaration.
#include <eh.h>
#endif