|
22 | 22 |
|
23 | 23 | using namespace lldb_private; |
24 | 24 |
|
| 25 | +static llvm::Expected<Scalar> Evaluate(llvm::ArrayRef<uint8_t> expr, |
| 26 | + lldb::ModuleSP module_sp = {}, |
| 27 | + DWARFUnit *unit = nullptr) { |
| 28 | + DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle, |
| 29 | + /*addr_size*/ 4); |
| 30 | + Value result; |
| 31 | + Status status; |
| 32 | + if (!DWARFExpression::Evaluate( |
| 33 | + /*exe_ctx*/ nullptr, /*reg_ctx*/ nullptr, module_sp, extractor, unit, |
| 34 | + lldb::eRegisterKindLLDB, |
| 35 | + /*initial_value_ptr*/ nullptr, |
| 36 | + /*object_address_ptr*/ nullptr, result, &status)) |
| 37 | + return status.ToError(); |
| 38 | + |
| 39 | + switch (result.GetValueType()) { |
| 40 | + case Value::eValueTypeScalar: |
| 41 | + return result.GetScalar(); |
| 42 | + case Value::eValueTypeHostAddress: { |
| 43 | + // Convert small buffers to scalars to simplify the tests. |
| 44 | + DataBufferHeap &buf = result.GetBuffer(); |
| 45 | + if (buf.GetByteSize() <= 8) { |
| 46 | + uint64_t val = 0; |
| 47 | + memcpy(&val, buf.GetBytes(), buf.GetByteSize()); |
| 48 | + return Scalar(llvm::APInt(buf.GetByteSize()*8, val, false)); |
| 49 | + } |
| 50 | + } |
| 51 | + LLVM_FALLTHROUGH; |
| 52 | + default: |
| 53 | + return status.ToError(); |
| 54 | + } |
| 55 | +} |
| 56 | + |
25 | 57 | /// A mock module holding an object file parsed from YAML. |
26 | 58 | class YAMLModule : public lldb_private::Module { |
27 | 59 | public: |
@@ -99,22 +131,51 @@ class YAMLObjectFile : public lldb_private::ObjectFile { |
99 | 131 | /// \} |
100 | 132 | }; |
101 | 133 |
|
102 | | -static llvm::Expected<Scalar> Evaluate(llvm::ArrayRef<uint8_t> expr, |
103 | | - lldb::ModuleSP module_sp = {}, |
104 | | - DWARFUnit *unit = nullptr) { |
105 | | - DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle, |
106 | | - /*addr_size*/ 4); |
107 | | - Value result; |
108 | | - Status status; |
109 | | - if (!DWARFExpression::Evaluate( |
110 | | - /*exe_ctx*/ nullptr, /*reg_ctx*/ nullptr, module_sp, extractor, unit, |
111 | | - lldb::eRegisterKindLLDB, |
112 | | - /*initial_value_ptr*/ nullptr, |
113 | | - /*object_address_ptr*/ nullptr, result, &status)) |
114 | | - return status.ToError(); |
| 134 | +/// Helper class that can construct a module from YAML and evaluate |
| 135 | +/// DWARF expressions on it. |
| 136 | +class YAMLModuleTester { |
| 137 | + llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> m_sections_map; |
| 138 | + lldb::ModuleSP m_module_sp; |
| 139 | + lldb::ObjectFileSP m_objfile_sp; |
| 140 | + DWARFUnitSP m_dwarf_unit; |
| 141 | + std::unique_ptr<SymbolFileDWARF> m_symfile_dwarf; |
115 | 142 |
|
116 | | - return result.GetScalar(); |
117 | | -} |
| 143 | +public: |
| 144 | + /// Parse the debug info sections from the YAML description. |
| 145 | + YAMLModuleTester(llvm::StringRef yaml_data, llvm::StringRef triple) { |
| 146 | + FileSystem::Initialize(); |
| 147 | + |
| 148 | + auto sections_map = llvm::DWARFYAML::EmitDebugSections(yaml_data, true); |
| 149 | + if (!sections_map) |
| 150 | + return; |
| 151 | + m_sections_map = std::move(*sections_map); |
| 152 | + ArchSpec arch(triple); |
| 153 | + m_module_sp = std::make_shared<YAMLModule>(arch); |
| 154 | + m_objfile_sp = std::make_shared<YAMLObjectFile>(m_module_sp, m_sections_map); |
| 155 | + static_cast<YAMLModule *>(m_module_sp.get())->SetObjectFile(m_objfile_sp); |
| 156 | + |
| 157 | + lldb::user_id_t uid = 0; |
| 158 | + llvm::StringRef raw_debug_info = m_sections_map["debug_info"]->getBuffer(); |
| 159 | + lldb_private::DataExtractor debug_info( |
| 160 | + raw_debug_info.data(), raw_debug_info.size(), |
| 161 | + m_objfile_sp->GetByteOrder(), m_objfile_sp->GetAddressByteSize()); |
| 162 | + lldb::offset_t offset_ptr = 0; |
| 163 | + m_symfile_dwarf = std::make_unique<SymbolFileDWARF>(m_objfile_sp, nullptr); |
| 164 | + llvm::Expected<DWARFUnitSP> dwarf_unit = DWARFUnit::extract( |
| 165 | + *m_symfile_dwarf, uid, |
| 166 | + *static_cast<lldb_private::DWARFDataExtractor *>(&debug_info), |
| 167 | + DIERef::DebugInfo, &offset_ptr); |
| 168 | + if (dwarf_unit) |
| 169 | + m_dwarf_unit = dwarf_unit.get(); |
| 170 | + } |
| 171 | + ~YAMLModuleTester() { FileSystem::Terminate(); } |
| 172 | + DWARFUnitSP GetDwarfUnit() { return m_dwarf_unit; } |
| 173 | + |
| 174 | + // Evaluate a raw DWARF expression. |
| 175 | + llvm::Expected<Scalar> Eval(llvm::ArrayRef<uint8_t> expr) { |
| 176 | + return ::Evaluate(expr, m_module_sp, m_dwarf_unit.get()); |
| 177 | + } |
| 178 | +}; |
118 | 179 |
|
119 | 180 | /// Unfortunately Scalar's operator==() is really picky. |
120 | 181 | static Scalar GetScalar(unsigned bits, uint64_t value, bool sign) { |
@@ -226,103 +287,78 @@ TEST(DWARFExpression, DW_OP_convert) { |
226 | 287 | uint8_t offs_uchar = 0x00000017; |
227 | 288 | uint8_t offs_schar = 0x0000001a; |
228 | 289 |
|
229 | | - // |
230 | | - // Setup. Parse the debug info sections from the YAML description. |
231 | | - // |
232 | | - auto sections_map = llvm::DWARFYAML::EmitDebugSections(yamldata, true); |
233 | | - ASSERT_TRUE((bool)sections_map); |
234 | | - ArchSpec arch("i386-unknown-linux"); |
235 | | - FileSystem::Initialize(); |
236 | | - auto module_sp = std::make_shared<YAMLModule>(arch); |
237 | | - lldb::ObjectFileSP objfile_sp = |
238 | | - std::make_shared<YAMLObjectFile>(module_sp, *sections_map); |
239 | | - module_sp->SetObjectFile(objfile_sp); |
240 | | - SymbolFileDWARF symfile_dwarf(objfile_sp, nullptr); |
241 | | - |
242 | | - lldb::user_id_t uid = 0; |
243 | | - llvm::StringRef raw_debug_info = (*sections_map)["debug_info"]->getBuffer(); |
244 | | - lldb_private::DataExtractor debug_info( |
245 | | - raw_debug_info.data(), raw_debug_info.size(), objfile_sp->GetByteOrder(), |
246 | | - objfile_sp->GetAddressByteSize()); |
247 | | - lldb::offset_t offset_ptr = 0; |
248 | | - llvm::Expected<DWARFUnitSP> dwarf_unit = DWARFUnit::extract( |
249 | | - symfile_dwarf, uid, |
250 | | - *static_cast<lldb_private::DWARFDataExtractor *>(&debug_info), |
251 | | - DIERef::DebugInfo, &offset_ptr); |
252 | | - ASSERT_TRUE((bool)dwarf_unit); |
253 | | - |
254 | | - // |
255 | | - // Actual tests. |
256 | | - // |
| 290 | + YAMLModuleTester t(yamldata, "i386-unknown-linux"); |
| 291 | + ASSERT_TRUE((bool)t.GetDwarfUnit()); |
257 | 292 |
|
258 | 293 | // Constant is given as little-endian. |
259 | 294 | bool is_signed = true; |
260 | 295 | bool not_signed = false; |
261 | 296 |
|
| 297 | + // |
| 298 | + // Positive tests. |
| 299 | + // |
| 300 | + |
262 | 301 | // Truncate to default unspecified (pointer-sized) type. |
263 | | - EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const8u, 0x11, 0x22, 0x33, 0x44, 0x55, |
264 | | - 0x66, 0x77, 0x88, DW_OP_convert, 0x00}, |
265 | | - module_sp, dwarf_unit->get()), |
266 | | - llvm::HasValue(GetScalar(32, 0x44332211, not_signed))); |
267 | | - // Truncate to 32 bits. |
268 | 302 | EXPECT_THAT_EXPECTED( |
269 | | - Evaluate({DW_OP_const8u, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, |
270 | | - DW_OP_convert, offs_uint32_t}, |
271 | | - module_sp, dwarf_unit->get()), |
| 303 | + t.Eval({DW_OP_const8u, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // |
| 304 | + DW_OP_convert, 0x00}), |
272 | 305 | llvm::HasValue(GetScalar(32, 0x44332211, not_signed))); |
| 306 | + // Truncate to 32 bits. |
| 307 | + EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const8u, // |
| 308 | + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,// |
| 309 | + DW_OP_convert, offs_uint32_t}), |
| 310 | + llvm::HasValue(GetScalar(32, 0x44332211, not_signed))); |
273 | 311 |
|
274 | 312 | // Leave as is. |
275 | 313 | EXPECT_THAT_EXPECTED( |
276 | | - Evaluate({DW_OP_const8u, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, |
277 | | - DW_OP_convert, offs_uint64_t}, |
278 | | - module_sp, dwarf_unit->get()), |
| 314 | + t.Eval({DW_OP_const8u, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // |
| 315 | + DW_OP_convert, offs_uint64_t}), |
279 | 316 | llvm::HasValue(GetScalar(64, 0x8877665544332211, not_signed))); |
280 | 317 |
|
281 | 318 | // Sign-extend to 64 bits. |
282 | 319 | EXPECT_THAT_EXPECTED( |
283 | | - Evaluate({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // |
284 | | - DW_OP_convert, offs_sint64_t}, |
285 | | - module_sp, dwarf_unit->get()), |
| 320 | + t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // |
| 321 | + DW_OP_convert, offs_sint64_t}), |
286 | 322 | llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed))); |
287 | 323 |
|
288 | 324 | // Truncate to 8 bits. |
289 | | - EXPECT_THAT_EXPECTED( |
290 | | - Evaluate({DW_OP_const4s, 'A', 'B', 'C', 'D', 0xee, 0xff, // |
291 | | - DW_OP_convert, offs_uchar}, |
292 | | - module_sp, dwarf_unit->get()), |
293 | | - llvm::HasValue(GetScalar(8, 'A', not_signed))); |
| 325 | + EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', 0xee, 0xff, // |
| 326 | + DW_OP_convert, offs_uchar}), |
| 327 | + llvm::HasValue(GetScalar(8, 'A', not_signed))); |
294 | 328 |
|
295 | 329 | // Also truncate to 8 bits. |
296 | | - EXPECT_THAT_EXPECTED( |
297 | | - Evaluate({DW_OP_const4s, 'A', 'B', 'C', 'D', 0xee, 0xff, // |
298 | | - DW_OP_convert, offs_schar}, |
299 | | - module_sp, dwarf_unit->get()), |
300 | | - llvm::HasValue(GetScalar(8, 'A', is_signed))); |
| 330 | + EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', 0xee, 0xff, // |
| 331 | + DW_OP_convert, offs_schar}), |
| 332 | + llvm::HasValue(GetScalar(8, 'A', is_signed))); |
301 | 333 |
|
302 | 334 | // |
303 | 335 | // Errors. |
304 | 336 | // |
305 | 337 |
|
306 | 338 | // No Module. |
307 | 339 | EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x00}, nullptr, |
308 | | - dwarf_unit->get()) |
| 340 | + t.GetDwarfUnit().get()) |
309 | 341 | .takeError(), |
310 | 342 | llvm::Failed()); |
311 | 343 |
|
312 | 344 | // No DIE. |
313 | | - EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x01}, |
314 | | - module_sp, dwarf_unit->get()) |
315 | | - .takeError(), |
316 | | - llvm::Failed()); |
| 345 | + EXPECT_THAT_ERROR( |
| 346 | + t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x01}).takeError(), |
| 347 | + llvm::Failed()); |
317 | 348 |
|
318 | 349 | // Unsupported. |
319 | | - EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}, nullptr, |
320 | | - dwarf_unit->get()) |
321 | | - .takeError(), |
322 | | - llvm::Failed()); |
| 350 | + EXPECT_THAT_ERROR( |
| 351 | + t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(), |
| 352 | + llvm::Failed()); |
| 353 | +} |
323 | 354 |
|
324 | | - // |
325 | | - // Tear down. |
326 | | - // |
327 | | - FileSystem::Terminate(); |
| 355 | +TEST(DWARFExpression, DW_OP_piece) { |
| 356 | + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2, |
| 357 | + DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}), |
| 358 | + llvm::HasValue(GetScalar(32, 0x44332211, true))); |
| 359 | + EXPECT_THAT_EXPECTED( |
| 360 | + Evaluate({DW_OP_piece, 1, DW_OP_const1u, 0xff, DW_OP_piece, 1}), |
| 361 | + // Note that the "00" should really be "undef", but we can't |
| 362 | + // represent that yet. |
| 363 | + llvm::HasValue(GetScalar(16, 0xff00, true))); |
328 | 364 | } |
0 commit comments