1 //===-- DWARFExpressionTest.cpp -------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Expression/DWARFExpression.h" 10 #include "Plugins/Platform/Linux/PlatformLinux.h" 11 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 12 #include "TestingSupport/Symbol/YAMLModuleTester.h" 13 #include "lldb/Core/Value.h" 14 #include "lldb/Core/Debugger.h" 15 #include "lldb/Core/dwarf.h" 16 #include "lldb/Host/HostInfo.h" 17 #include "lldb/Symbol/ObjectFile.h" 18 #include "lldb/Utility/Reproducer.h" 19 #include "lldb/Utility/StreamString.h" 20 #include "llvm/ADT/StringExtras.h" 21 #include "llvm/Testing/Support/Error.h" 22 #include "gtest/gtest.h" 23 24 using namespace lldb_private; 25 26 static llvm::Expected<Scalar> Evaluate(llvm::ArrayRef<uint8_t> expr, 27 lldb::ModuleSP module_sp = {}, 28 DWARFUnit *unit = nullptr, 29 ExecutionContext *exe_ctx = nullptr) { 30 DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle, 31 /*addr_size*/ 4); 32 Value result; 33 Status status; 34 if (!DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp, 35 extractor, unit, lldb::eRegisterKindLLDB, 36 /*initial_value_ptr*/ nullptr, 37 /*object_address_ptr*/ nullptr, result, 38 &status)) 39 return status.ToError(); 40 41 switch (result.GetValueType()) { 42 case Value::ValueType::Scalar: 43 return result.GetScalar(); 44 case Value::ValueType::LoadAddress: 45 return LLDB_INVALID_ADDRESS; 46 case Value::ValueType::HostAddress: { 47 // Convert small buffers to scalars to simplify the tests. 48 DataBufferHeap &buf = result.GetBuffer(); 49 if (buf.GetByteSize() <= 8) { 50 uint64_t val = 0; 51 memcpy(&val, buf.GetBytes(), buf.GetByteSize()); 52 return Scalar(llvm::APInt(buf.GetByteSize()*8, val, false)); 53 } 54 } 55 LLVM_FALLTHROUGH; 56 default: 57 return status.ToError(); 58 } 59 } 60 61 class DWARFExpressionTester : public YAMLModuleTester { 62 public: 63 using YAMLModuleTester::YAMLModuleTester; 64 llvm::Expected<Scalar> Eval(llvm::ArrayRef<uint8_t> expr) { 65 return ::Evaluate(expr, m_module_sp, m_dwarf_unit); 66 } 67 }; 68 69 /// Unfortunately Scalar's operator==() is really picky. 70 static Scalar GetScalar(unsigned bits, uint64_t value, bool sign) { 71 Scalar scalar(value); 72 scalar.TruncOrExtendTo(bits, sign); 73 return scalar; 74 } 75 76 /// This is needed for the tests that use a mock process. 77 class DWARFExpressionMockProcessTest : public ::testing::Test { 78 public: 79 void SetUp() override { 80 llvm::cantFail(repro::Reproducer::Initialize(repro::ReproducerMode::Off, {})); 81 FileSystem::Initialize(); 82 HostInfo::Initialize(); 83 platform_linux::PlatformLinux::Initialize(); 84 } 85 void TearDown() override { 86 platform_linux::PlatformLinux::Terminate(); 87 HostInfo::Terminate(); 88 FileSystem::Terminate(); 89 repro::Reproducer::Terminate(); 90 } 91 }; 92 93 TEST(DWARFExpression, DW_OP_pick) { 94 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 0}), 95 llvm::HasValue(0)); 96 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 1}), 97 llvm::HasValue(1)); 98 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 2}), 99 llvm::Failed()); 100 } 101 102 TEST(DWARFExpression, DW_OP_const) { 103 // Extend to address size. 104 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x88}), llvm::HasValue(0x88)); 105 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, 0x88}), 106 llvm::HasValue(0xffffff88)); 107 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x47, 0x88}), 108 llvm::HasValue(0x8847)); 109 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2s, 0x47, 0x88}), 110 llvm::HasValue(0xffff8847)); 111 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4u, 0x44, 0x42, 0x47, 0x88}), 112 llvm::HasValue(0x88474244)); 113 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4s, 0x44, 0x42, 0x47, 0x88}), 114 llvm::HasValue(0x88474244)); 115 116 // Truncate to address size. 117 EXPECT_THAT_EXPECTED( 118 Evaluate({DW_OP_const8u, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}), 119 llvm::HasValue(0x33221100)); 120 EXPECT_THAT_EXPECTED( 121 Evaluate({DW_OP_const8s, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}), 122 llvm::HasValue(0x33221100)); 123 124 // Don't truncate to address size for compatibility with clang (pr48087). 125 EXPECT_THAT_EXPECTED( 126 Evaluate({DW_OP_constu, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}), 127 llvm::HasValue(0x01010101010101)); 128 EXPECT_THAT_EXPECTED( 129 Evaluate({DW_OP_consts, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}), 130 llvm::HasValue(0xffff010101010101)); 131 } 132 133 TEST(DWARFExpression, DW_OP_convert) { 134 /// Auxiliary debug info. 135 const char *yamldata = R"( 136 --- !ELF 137 FileHeader: 138 Class: ELFCLASS64 139 Data: ELFDATA2LSB 140 Type: ET_EXEC 141 Machine: EM_386 142 DWARF: 143 debug_abbrev: 144 - Table: 145 - Code: 0x00000001 146 Tag: DW_TAG_compile_unit 147 Children: DW_CHILDREN_yes 148 Attributes: 149 - Attribute: DW_AT_language 150 Form: DW_FORM_data2 151 - Code: 0x00000002 152 Tag: DW_TAG_base_type 153 Children: DW_CHILDREN_no 154 Attributes: 155 - Attribute: DW_AT_encoding 156 Form: DW_FORM_data1 157 - Attribute: DW_AT_byte_size 158 Form: DW_FORM_data1 159 debug_info: 160 - Version: 4 161 AddrSize: 8 162 Entries: 163 - AbbrCode: 0x00000001 164 Values: 165 - Value: 0x000000000000000C 166 # 0x0000000e: 167 - AbbrCode: 0x00000002 168 Values: 169 - Value: 0x0000000000000007 # DW_ATE_unsigned 170 - Value: 0x0000000000000004 171 # 0x00000011: 172 - AbbrCode: 0x00000002 173 Values: 174 - Value: 0x0000000000000007 # DW_ATE_unsigned 175 - Value: 0x0000000000000008 176 # 0x00000014: 177 - AbbrCode: 0x00000002 178 Values: 179 - Value: 0x0000000000000005 # DW_ATE_signed 180 - Value: 0x0000000000000008 181 # 0x00000017: 182 - AbbrCode: 0x00000002 183 Values: 184 - Value: 0x0000000000000008 # DW_ATE_unsigned_char 185 - Value: 0x0000000000000001 186 # 0x0000001a: 187 - AbbrCode: 0x00000002 188 Values: 189 - Value: 0x0000000000000006 # DW_ATE_signed_char 190 - Value: 0x0000000000000001 191 # 0x0000001d: 192 - AbbrCode: 0x00000002 193 Values: 194 - Value: 0x000000000000000b # DW_ATE_numeric_string 195 - Value: 0x0000000000000001 196 - AbbrCode: 0x00000000 197 )"; 198 uint8_t offs_uint32_t = 0x0000000e; 199 uint8_t offs_uint64_t = 0x00000011; 200 uint8_t offs_sint64_t = 0x00000014; 201 uint8_t offs_uchar = 0x00000017; 202 uint8_t offs_schar = 0x0000001a; 203 204 DWARFExpressionTester t(yamldata); 205 ASSERT_TRUE((bool)t.GetDwarfUnit()); 206 207 // Constant is given as little-endian. 208 bool is_signed = true; 209 bool not_signed = false; 210 211 // 212 // Positive tests. 213 // 214 215 // Leave as is. 216 EXPECT_THAT_EXPECTED( 217 t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, // 218 DW_OP_convert, offs_uint32_t, DW_OP_stack_value}), 219 llvm::HasValue(GetScalar(64, 0x44332211, not_signed))); 220 221 // Zero-extend to 64 bits. 222 EXPECT_THAT_EXPECTED( 223 t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, // 224 DW_OP_convert, offs_uint64_t, DW_OP_stack_value}), 225 llvm::HasValue(GetScalar(64, 0x44332211, not_signed))); 226 227 // Sign-extend to 64 bits. 228 EXPECT_THAT_EXPECTED( 229 t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // 230 DW_OP_convert, offs_sint64_t, DW_OP_stack_value}), 231 llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed))); 232 233 // Sign-extend, then truncate. 234 EXPECT_THAT_EXPECTED( 235 t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // 236 DW_OP_convert, offs_sint64_t, // 237 DW_OP_convert, offs_uint32_t, DW_OP_stack_value}), 238 llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed))); 239 240 // Truncate to default unspecified (pointer-sized) type. 241 EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // 242 DW_OP_convert, offs_sint64_t, // 243 DW_OP_convert, 0x00, DW_OP_stack_value}), 244 llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed))); 245 246 // Truncate to 8 bits. 247 EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, 248 offs_uchar, DW_OP_stack_value}), 249 llvm::HasValue(GetScalar(8, 'A', not_signed))); 250 251 // Also truncate to 8 bits. 252 EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, 253 offs_schar, DW_OP_stack_value}), 254 llvm::HasValue(GetScalar(8, 'A', is_signed))); 255 256 // 257 // Errors. 258 // 259 260 // No Module. 261 EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x00}, nullptr, 262 t.GetDwarfUnit()) 263 .takeError(), 264 llvm::Failed()); 265 266 // No DIE. 267 EXPECT_THAT_ERROR( 268 t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x01}).takeError(), 269 llvm::Failed()); 270 271 // Unsupported. 272 EXPECT_THAT_ERROR( 273 t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(), 274 llvm::Failed()); 275 } 276 277 TEST(DWARFExpression, DW_OP_stack_value) { 278 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed()); 279 } 280 281 TEST(DWARFExpression, DW_OP_piece) { 282 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2, 283 DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}), 284 llvm::HasValue(GetScalar(32, 0x44332211, true))); 285 EXPECT_THAT_EXPECTED( 286 Evaluate({DW_OP_piece, 1, DW_OP_const1u, 0xff, DW_OP_piece, 1}), 287 // Note that the "00" should really be "undef", but we can't 288 // represent that yet. 289 llvm::HasValue(GetScalar(16, 0xff00, true))); 290 } 291 292 TEST(DWARFExpression, DW_OP_implicit_value) { 293 unsigned char bytes = 4; 294 295 EXPECT_THAT_EXPECTED( 296 Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}), 297 llvm::HasValue(GetScalar(8 * bytes, 0x44332211, true))); 298 } 299 300 TEST(DWARFExpression, DW_OP_unknown) { 301 EXPECT_THAT_EXPECTED( 302 Evaluate({0xff}), 303 llvm::FailedWithMessage( 304 "Unhandled opcode DW_OP_unknown_ff in DWARFExpression")); 305 } 306 307 TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) { 308 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed()); 309 310 struct MockProcess : Process { 311 using Process::Process; 312 llvm::StringRef GetPluginName() override { return "mock process"; } 313 bool CanDebug(lldb::TargetSP target, 314 bool plugin_specified_by_name) override { 315 return false; 316 }; 317 Status DoDestroy() override { return {}; } 318 void RefreshStateAfterStop() override {} 319 bool DoUpdateThreadList(ThreadList &old_thread_list, 320 ThreadList &new_thread_list) override { 321 return false; 322 }; 323 size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, 324 Status &error) override { 325 for (size_t i = 0; i < size; ++i) 326 ((char *)buf)[i] = (vm_addr + i) & 0xff; 327 error.Clear(); 328 return size; 329 } 330 }; 331 332 // Set up a mock process. 333 ArchSpec arch("i386-pc-linux"); 334 Platform::SetHostPlatform( 335 platform_linux::PlatformLinux::CreateInstance(true, &arch)); 336 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); 337 ASSERT_TRUE(debugger_sp); 338 lldb::TargetSP target_sp; 339 lldb::PlatformSP platform_sp; 340 debugger_sp->GetTargetList().CreateTarget( 341 *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); 342 ASSERT_TRUE(target_sp); 343 ASSERT_TRUE(target_sp->GetArchitecture().IsValid()); 344 ASSERT_TRUE(platform_sp); 345 lldb::ListenerSP listener_sp(Listener::MakeListener("dummy")); 346 lldb::ProcessSP process_sp = 347 std::make_shared<MockProcess>(target_sp, listener_sp); 348 ASSERT_TRUE(process_sp); 349 350 ExecutionContext exe_ctx(process_sp); 351 // Implicit location: *0x4. 352 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, 353 {}, {}, &exe_ctx), 354 llvm::HasValue(GetScalar(32, 0x07060504, false))); 355 // Memory location: *(*0x4). 356 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses. 357 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx), 358 llvm::HasValue(Scalar(LLDB_INVALID_ADDRESS))); 359 // Memory location: *0x4. 360 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses. 361 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4}, {}, {}, &exe_ctx), 362 llvm::HasValue(Scalar(4))); 363 // Implicit location: *0x4. 364 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses. 365 EXPECT_THAT_EXPECTED( 366 Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx), 367 llvm::HasValue(GetScalar(32, 0x07060504, false))); 368 } 369