1 //===-- TestDWARFCallFrameInfo.cpp ------------------------------*- C++ -*-===//
2 //
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 #include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
12 #include "Plugins/Process/Utility/RegisterContext_x86.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/ModuleSpec.h"
15 #include "lldb/Core/Section.h"
16 #include "lldb/Host/HostInfo.h"
17 #include "lldb/Symbol/DWARFCallFrameInfo.h"
18 #include "lldb/Utility/StreamString.h"
19 #include "TestingSupport/TestUtilities.h"
20 #include "llvm/Support/FileUtilities.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/Program.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include "gtest/gtest.h"
25 
26 using namespace lldb_private;
27 using namespace lldb;
28 
29 class DWARFCallFrameInfoTest : public testing::Test {
30 public:
31   void SetUp() override {
32     HostInfo::Initialize();
33     ObjectFileELF::Initialize();
34   }
35 
36   void TearDown() override {
37     ObjectFileELF::Terminate();
38     HostInfo::Terminate();
39   }
40 
41 protected:
42   void TestBasic(DWARFCallFrameInfo::Type type, llvm::StringRef symbol);
43 };
44 
45 #define ASSERT_NO_ERROR(x)                                                     \
46   if (std::error_code ASSERT_NO_ERROR_ec = x) {                                \
47     llvm::SmallString<128> MessageStorage;                                     \
48     llvm::raw_svector_ostream Message(MessageStorage);                         \
49     Message << #x ": did not return errc::success.\n"                          \
50             << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n"          \
51             << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n";      \
52     GTEST_FATAL_FAILURE_(MessageStorage.c_str());                              \
53   } else {                                                                     \
54   }
55 
56 namespace lldb_private {
57 static std::ostream &operator<<(std::ostream &OS, const UnwindPlan::Row &row) {
58   StreamString SS;
59   row.Dump(SS, nullptr, nullptr, 0);
60   return OS << SS.GetData();
61 }
62 } // namespace lldb_private
63 
64 static UnwindPlan::Row GetExpectedRow0() {
65   UnwindPlan::Row row;
66   row.SetOffset(0);
67   row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 8);
68   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
69   return row;
70 }
71 
72 static UnwindPlan::Row GetExpectedRow1() {
73   UnwindPlan::Row row;
74   row.SetOffset(1);
75   row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 16);
76   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
77   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
78   return row;
79 }
80 
81 static UnwindPlan::Row GetExpectedRow2() {
82   UnwindPlan::Row row;
83   row.SetOffset(4);
84   row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp_x86_64, 16);
85   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
86   row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
87   return row;
88 }
89 
90 void DWARFCallFrameInfoTest::TestBasic(DWARFCallFrameInfo::Type type,
91                                        llvm::StringRef symbol) {
92   std::string yaml = GetInputFilePath("basic-call-frame-info.yaml");
93   llvm::SmallString<128> obj;
94 
95   ASSERT_NO_ERROR(llvm::sys::fs::createTemporaryFile(
96       "basic-call-frame-info-%%%%%%", "obj", obj));
97   llvm::FileRemover obj_remover(obj);
98 
99   const char *args[] = {YAML2OBJ, yaml.c_str(), nullptr};
100   llvm::StringRef obj_ref = obj;
101   const llvm::Optional<llvm::StringRef> redirects[] = {llvm::None, obj_ref,
102                                                        llvm::None};
103   ASSERT_EQ(0, llvm::sys::ExecuteAndWait(YAML2OBJ, args, nullptr, redirects));
104 
105   uint64_t size;
106   ASSERT_NO_ERROR(llvm::sys::fs::file_size(obj, size));
107   ASSERT_GT(size, 0u);
108 
109   auto module_sp = std::make_shared<Module>(ModuleSpec(FileSpec(obj, false)));
110   SectionList *list = module_sp->GetSectionList();
111   ASSERT_NE(nullptr, list);
112 
113   auto section_sp = list->FindSectionByType(type == DWARFCallFrameInfo::EH
114                                                 ? eSectionTypeEHFrame
115                                                 : eSectionTypeDWARFDebugFrame,
116                                             false);
117   ASSERT_NE(nullptr, section_sp);
118 
119   DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp, type);
120 
121   const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
122       ConstString(symbol), eSymbolTypeAny);
123   ASSERT_NE(nullptr, sym);
124 
125   UnwindPlan plan(eRegisterKindGeneric);
126   ASSERT_TRUE(cfi.GetUnwindPlan(sym->GetAddress(), plan));
127   ASSERT_EQ(3, plan.GetRowCount());
128   EXPECT_EQ(GetExpectedRow0(), *plan.GetRowAtIndex(0));
129   EXPECT_EQ(GetExpectedRow1(), *plan.GetRowAtIndex(1));
130   EXPECT_EQ(GetExpectedRow2(), *plan.GetRowAtIndex(2));
131 }
132 
133 TEST_F(DWARFCallFrameInfoTest, Basic_dwarf3) {
134   TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame3");
135 }
136 
137 TEST_F(DWARFCallFrameInfoTest, Basic_dwarf4) {
138   TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame4");
139 }
140 
141 TEST_F(DWARFCallFrameInfoTest, Basic_eh) {
142   TestBasic(DWARFCallFrameInfo::EH, "eh_frame");
143 }
144