1//===-- DWARFFormValue.cpp --------------------------------------*- C++ -*-===//
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 <assert.h>
10
11#include "lldb/Core/Module.h"
12#include "lldb/Core/dwarf.h"
13#include "lldb/Symbol/ObjectFile.h"
14#include "lldb/Utility/Stream.h"
15
16#include "DWARFDebugInfo.h"
17#include "DWARFFormValue.h"
18#include "DWARFUnit.h"
19
20class DWARFUnit;
21
22using namespace lldb_private;
23
24void DWARFFormValue::Clear() {
25  m_unit = nullptr;
26  m_form = 0;
27  m_value = ValueTypeTag();
28}
29
30bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data,
31                                  lldb::offset_t *offset_ptr) {
32  if (m_form == DW_FORM_implicit_const)
33    return true;
34
35  bool indirect = false;
36  bool is_block = false;
37  m_value.data = nullptr;
38  uint8_t ref_addr_size;
39  // Read the value for the form into value and follow and DW_FORM_indirect
40  // instances we run into
41  do {
42    indirect = false;
43    switch (m_form) {
44    case DW_FORM_addr:
45      assert(m_unit);
46      m_value.value.uval =
47          data.GetMaxU64(offset_ptr, DWARFUnit::GetAddressByteSize(m_unit));
48      break;
49    case DW_FORM_block1:
50      m_value.value.uval = data.GetU8(offset_ptr);
51      is_block = true;
52      break;
53    case DW_FORM_block2:
54      m_value.value.uval = data.GetU16(offset_ptr);
55      is_block = true;
56      break;
57    case DW_FORM_block4:
58      m_value.value.uval = data.GetU32(offset_ptr);
59      is_block = true;
60      break;
61    case DW_FORM_data16:
62      m_value.value.uval = 16;
63      is_block = true;
64      break;
65    case DW_FORM_exprloc:
66    case DW_FORM_block:
67      m_value.value.uval = data.GetULEB128(offset_ptr);
68      is_block = true;
69      break;
70    case DW_FORM_string:
71      m_value.value.cstr = data.GetCStr(offset_ptr);
72      break;
73    case DW_FORM_sdata:
74      m_value.value.sval = data.GetSLEB128(offset_ptr);
75      break;
76    case DW_FORM_strp:
77    case DW_FORM_line_strp:
78    case DW_FORM_sec_offset:
79      m_value.value.uval = data.GetMaxU64(offset_ptr, 4);
80      break;
81    case DW_FORM_addrx1:
82    case DW_FORM_strx1:
83    case DW_FORM_ref1:
84    case DW_FORM_data1:
85    case DW_FORM_flag:
86      m_value.value.uval = data.GetU8(offset_ptr);
87      break;
88    case DW_FORM_addrx2:
89    case DW_FORM_strx2:
90    case DW_FORM_ref2:
91    case DW_FORM_data2:
92      m_value.value.uval = data.GetU16(offset_ptr);
93      break;
94    case DW_FORM_addrx3:
95    case DW_FORM_strx3:
96      m_value.value.uval = data.GetMaxU64(offset_ptr, 3);
97      break;
98    case DW_FORM_addrx4:
99    case DW_FORM_strx4:
100    case DW_FORM_ref4:
101    case DW_FORM_data4:
102      m_value.value.uval = data.GetU32(offset_ptr);
103      break;
104    case DW_FORM_data8:
105    case DW_FORM_ref8:
106    case DW_FORM_ref_sig8:
107      m_value.value.uval = data.GetU64(offset_ptr);
108      break;
109    case DW_FORM_addrx:
110    case DW_FORM_loclistx:
111    case DW_FORM_rnglistx:
112    case DW_FORM_strx:
113    case DW_FORM_udata:
114    case DW_FORM_ref_udata:
115    case DW_FORM_GNU_str_index:
116    case DW_FORM_GNU_addr_index:
117      m_value.value.uval = data.GetULEB128(offset_ptr);
118      break;
119    case DW_FORM_ref_addr:
120      assert(m_unit);
121      if (m_unit->GetVersion() <= 2)
122        ref_addr_size = m_unit->GetAddressByteSize();
123      else
124        ref_addr_size = 4;
125      m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size);
126      break;
127    case DW_FORM_indirect:
128      m_form = data.GetULEB128(offset_ptr);
129      indirect = true;
130      break;
131    case DW_FORM_flag_present:
132      m_value.value.uval = 1;
133      break;
134    default:
135      return false;
136    }
137  } while (indirect);
138
139  if (is_block) {
140    m_value.data = data.PeekData(*offset_ptr, m_value.value.uval);
141    if (m_value.data != nullptr) {
142      *offset_ptr += m_value.value.uval;
143    }
144  }
145
146  return true;
147}
148
149struct FormSize {
150  uint8_t valid:1, size:7;
151};
152static FormSize g_form_sizes[] = {
153  {0,0}, // 0x00 unused
154  {0,0}, // 0x01 DW_FORM_addr
155  {0,0}, // 0x02 unused
156  {0,0}, // 0x03 DW_FORM_block2
157  {0,0}, // 0x04 DW_FORM_block4
158  {1,2}, // 0x05 DW_FORM_data2
159  {1,4}, // 0x06 DW_FORM_data4
160  {1,8}, // 0x07 DW_FORM_data8
161  {0,0}, // 0x08 DW_FORM_string
162  {0,0}, // 0x09 DW_FORM_block
163  {0,0}, // 0x0a DW_FORM_block1
164  {1,1}, // 0x0b DW_FORM_data1
165  {1,1}, // 0x0c DW_FORM_flag
166  {0,0}, // 0x0d DW_FORM_sdata
167  {1,4}, // 0x0e DW_FORM_strp
168  {0,0}, // 0x0f DW_FORM_udata
169  {0,0}, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes for
170         // DWARF32, 8 bytes for DWARF32 in DWARF 3 and later
171  {1,1}, // 0x11 DW_FORM_ref1
172  {1,2}, // 0x12 DW_FORM_ref2
173  {1,4}, // 0x13 DW_FORM_ref4
174  {1,8}, // 0x14 DW_FORM_ref8
175  {0,0}, // 0x15 DW_FORM_ref_udata
176  {0,0}, // 0x16 DW_FORM_indirect
177  {1,4}, // 0x17 DW_FORM_sec_offset
178  {0,0}, // 0x18 DW_FORM_exprloc
179  {1,0}, // 0x19 DW_FORM_flag_present
180  {0,0}, // 0x1a
181  {0,0}, // 0x1b
182  {0,0}, // 0x1c
183  {0,0}, // 0x1d
184  {0,0}, // 0x1e
185  {0,0}, // 0x1f
186  {1,8}, // 0x20 DW_FORM_ref_sig8
187};
188
189llvm::Optional<uint8_t>
190DWARFFormValue::GetFixedSize(dw_form_t form, const DWARFUnit *u) {
191  if (form <= DW_FORM_ref_sig8 && g_form_sizes[form].valid)
192    return g_form_sizes[form].size;
193  if (form == DW_FORM_addr && u)
194    return u->GetAddressByteSize();
195  return llvm::None;
196}
197
198llvm::Optional<uint8_t> DWARFFormValue::GetFixedSize() const {
199  return GetFixedSize(m_form, m_unit);
200}
201
202bool DWARFFormValue::SkipValue(const DWARFDataExtractor &debug_info_data,
203                               lldb::offset_t *offset_ptr) const {
204  return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, m_unit);
205}
206
207bool DWARFFormValue::SkipValue(dw_form_t form,
208                               const DWARFDataExtractor &debug_info_data,
209                               lldb::offset_t *offset_ptr,
210                               const DWARFUnit *unit) {
211  uint8_t ref_addr_size;
212  switch (form) {
213  // Blocks if inlined data that have a length field and the data bytes inlined
214  // in the .debug_info
215  case DW_FORM_exprloc:
216  case DW_FORM_block: {
217    dw_uleb128_t size = debug_info_data.GetULEB128(offset_ptr);
218    *offset_ptr += size;
219  }
220    return true;
221  case DW_FORM_block1: {
222    dw_uleb128_t size = debug_info_data.GetU8(offset_ptr);
223    *offset_ptr += size;
224  }
225    return true;
226  case DW_FORM_block2: {
227    dw_uleb128_t size = debug_info_data.GetU16(offset_ptr);
228    *offset_ptr += size;
229  }
230    return true;
231  case DW_FORM_block4: {
232    dw_uleb128_t size = debug_info_data.GetU32(offset_ptr);
233    *offset_ptr += size;
234  }
235    return true;
236
237  // Inlined NULL terminated C-strings
238  case DW_FORM_string:
239    debug_info_data.GetCStr(offset_ptr);
240    return true;
241
242  // Compile unit address sized values
243  case DW_FORM_addr:
244    *offset_ptr += DWARFUnit::GetAddressByteSize(unit);
245    return true;
246
247  case DW_FORM_ref_addr:
248    ref_addr_size = 4;
249    assert(unit); // Unit must be valid for DW_FORM_ref_addr objects or we will
250                  // get this wrong
251    if (unit->GetVersion() <= 2)
252      ref_addr_size = unit->GetAddressByteSize();
253    else
254      ref_addr_size = 4;
255    *offset_ptr += ref_addr_size;
256    return true;
257
258  // 0 bytes values (implied from DW_FORM)
259  case DW_FORM_flag_present:
260  case DW_FORM_implicit_const:
261    return true;
262
263    // 1 byte values
264    case DW_FORM_addrx1:
265    case DW_FORM_data1:
266    case DW_FORM_flag:
267    case DW_FORM_ref1:
268    case DW_FORM_strx1:
269      *offset_ptr += 1;
270      return true;
271
272    // 2 byte values
273    case DW_FORM_addrx2:
274    case DW_FORM_data2:
275    case DW_FORM_ref2:
276    case DW_FORM_strx2:
277      *offset_ptr += 2;
278      return true;
279
280    // 3 byte values
281    case DW_FORM_addrx3:
282    case DW_FORM_strx3:
283      *offset_ptr += 3;
284      return true;
285
286    // 32 bit for DWARF 32, 64 for DWARF 64
287    case DW_FORM_sec_offset:
288    case DW_FORM_strp:
289      *offset_ptr += 4;
290      return true;
291
292    // 4 byte values
293    case DW_FORM_addrx4:
294    case DW_FORM_data4:
295    case DW_FORM_ref4:
296    case DW_FORM_strx4:
297      *offset_ptr += 4;
298      return true;
299
300    // 8 byte values
301    case DW_FORM_data8:
302    case DW_FORM_ref8:
303    case DW_FORM_ref_sig8:
304      *offset_ptr += 8;
305      return true;
306
307    // signed or unsigned LEB 128 values
308    case DW_FORM_addrx:
309    case DW_FORM_loclistx:
310    case DW_FORM_rnglistx:
311    case DW_FORM_sdata:
312    case DW_FORM_udata:
313    case DW_FORM_ref_udata:
314    case DW_FORM_GNU_addr_index:
315    case DW_FORM_GNU_str_index:
316    case DW_FORM_strx:
317      debug_info_data.Skip_LEB128(offset_ptr);
318      return true;
319
320  case DW_FORM_indirect: {
321    dw_form_t indirect_form = debug_info_data.GetULEB128(offset_ptr);
322    return DWARFFormValue::SkipValue(indirect_form, debug_info_data, offset_ptr,
323                                     unit);
324  }
325
326  default:
327    break;
328  }
329  return false;
330}
331
332void DWARFFormValue::Dump(Stream &s) const {
333  uint64_t uvalue = Unsigned();
334  bool unit_relative_offset = false;
335
336  switch (m_form) {
337  case DW_FORM_addr:
338    DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t));
339    break;
340  case DW_FORM_flag:
341  case DW_FORM_data1:
342    s.PutHex8(uvalue);
343    break;
344  case DW_FORM_data2:
345    s.PutHex16(uvalue);
346    break;
347  case DW_FORM_sec_offset:
348  case DW_FORM_data4:
349    s.PutHex32(uvalue);
350    break;
351  case DW_FORM_ref_sig8:
352  case DW_FORM_data8:
353    s.PutHex64(uvalue);
354    break;
355  case DW_FORM_string:
356    s.QuotedCString(AsCString());
357    break;
358  case DW_FORM_exprloc:
359  case DW_FORM_block:
360  case DW_FORM_block1:
361  case DW_FORM_block2:
362  case DW_FORM_block4:
363    if (uvalue > 0) {
364      switch (m_form) {
365      case DW_FORM_exprloc:
366      case DW_FORM_block:
367        s.Printf("<0x%" PRIx64 "> ", uvalue);
368        break;
369      case DW_FORM_block1:
370        s.Printf("<0x%2.2x> ", (uint8_t)uvalue);
371        break;
372      case DW_FORM_block2:
373        s.Printf("<0x%4.4x> ", (uint16_t)uvalue);
374        break;
375      case DW_FORM_block4:
376        s.Printf("<0x%8.8x> ", (uint32_t)uvalue);
377        break;
378      default:
379        break;
380      }
381
382      const uint8_t *data_ptr = m_value.data;
383      if (data_ptr) {
384        const uint8_t *end_data_ptr =
385            data_ptr + uvalue; // uvalue contains size of block
386        while (data_ptr < end_data_ptr) {
387          s.Printf("%2.2x ", *data_ptr);
388          ++data_ptr;
389        }
390      } else
391        s.PutCString("NULL");
392    }
393    break;
394
395  case DW_FORM_sdata:
396    s.PutSLEB128(uvalue);
397    break;
398  case DW_FORM_udata:
399    s.PutULEB128(uvalue);
400    break;
401  case DW_FORM_strp: {
402    const char *dbg_str = AsCString();
403    if (dbg_str) {
404      s.QuotedCString(dbg_str);
405    } else {
406      s.PutHex32(uvalue);
407    }
408  } break;
409
410  case DW_FORM_ref_addr: {
411    assert(m_unit); // Unit must be valid for DW_FORM_ref_addr objects or we
412                    // will get this wrong
413    if (m_unit->GetVersion() <= 2)
414      DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t) * 2);
415    else
416      DumpAddress(s.AsRawOstream(), uvalue,
417                  4 * 2); // 4 for DWARF32, 8 for DWARF64, but we don't
418                          // support DWARF64 yet
419    break;
420  }
421  case DW_FORM_ref1:
422    unit_relative_offset = true;
423    break;
424  case DW_FORM_ref2:
425    unit_relative_offset = true;
426    break;
427  case DW_FORM_ref4:
428    unit_relative_offset = true;
429    break;
430  case DW_FORM_ref8:
431    unit_relative_offset = true;
432    break;
433  case DW_FORM_ref_udata:
434    unit_relative_offset = true;
435    break;
436
437  // All DW_FORM_indirect attributes should be resolved prior to calling this
438  // function
439  case DW_FORM_indirect:
440    s.PutCString("DW_FORM_indirect");
441    break;
442  case DW_FORM_flag_present:
443    break;
444  default:
445    s.Printf("DW_FORM(0x%4.4x)", m_form);
446    break;
447  }
448
449  if (unit_relative_offset) {
450    assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile
451                    // unit relative or we will get this wrong
452    s.Printf("{0x%8.8" PRIx64 "}", uvalue + m_unit->GetOffset());
453  }
454}
455
456const char *DWARFFormValue::AsCString() const {
457  SymbolFileDWARF &symbol_file = m_unit->GetSymbolFileDWARF();
458
459  if (m_form == DW_FORM_string) {
460    return m_value.value.cstr;
461  } else if (m_form == DW_FORM_strp) {
462    return symbol_file.GetDWARFContext().getOrLoadStrData().PeekCStr(
463        m_value.value.uval);
464  } else if (m_form == DW_FORM_GNU_str_index) {
465    uint32_t index_size = 4;
466    lldb::offset_t offset = m_value.value.uval * index_size;
467    dw_offset_t str_offset =
468        symbol_file.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64(
469            &offset, index_size);
470    return symbol_file.GetDWARFContext().getOrLoadStrData().PeekCStr(
471        str_offset);
472  }
473
474  if (m_form == DW_FORM_strx || m_form == DW_FORM_strx1 ||
475      m_form == DW_FORM_strx2 || m_form == DW_FORM_strx3 ||
476      m_form == DW_FORM_strx4) {
477
478    // The same code as above.
479    uint32_t indexSize = 4;
480    lldb::offset_t offset =
481        m_unit->GetStrOffsetsBase() + m_value.value.uval * indexSize;
482    dw_offset_t strOffset =
483        symbol_file.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64(
484            &offset, indexSize);
485    return symbol_file.GetDWARFContext().getOrLoadStrData().PeekCStr(strOffset);
486  }
487
488  if (m_form == DW_FORM_line_strp)
489    return symbol_file.GetDWARFContext().getOrLoadLineStrData().PeekCStr(
490        m_value.value.uval);
491
492  return nullptr;
493}
494
495dw_addr_t DWARFFormValue::Address() const {
496  SymbolFileDWARF &symbol_file = m_unit->GetSymbolFileDWARF();
497
498  if (m_form == DW_FORM_addr)
499    return Unsigned();
500
501  assert(m_unit);
502  assert(m_form == DW_FORM_GNU_addr_index || m_form == DW_FORM_addrx ||
503         m_form == DW_FORM_addrx1 || m_form == DW_FORM_addrx2 ||
504         m_form == DW_FORM_addrx3 || m_form == DW_FORM_addrx4);
505
506  uint32_t index_size = m_unit->GetAddressByteSize();
507  dw_offset_t addr_base = m_unit->GetAddrBase();
508  lldb::offset_t offset = addr_base + m_value.value.uval * index_size;
509  return symbol_file.GetDWARFContext().getOrLoadAddrData().GetMaxU64(
510      &offset, index_size);
511}
512
513DWARFDIE DWARFFormValue::Reference() const {
514  uint64_t value = m_value.value.uval;
515  switch (m_form) {
516  case DW_FORM_ref1:
517  case DW_FORM_ref2:
518  case DW_FORM_ref4:
519  case DW_FORM_ref8:
520  case DW_FORM_ref_udata:
521    assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile
522                    // unit relative or we will get this wrong
523    value += m_unit->GetOffset();
524    if (!m_unit->ContainsDIEOffset(value)) {
525      m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
526          "DW_FORM_ref* DIE reference 0x%" PRIx64 " is outside of its CU",
527          value);
528      return {};
529    }
530    return const_cast<DWARFUnit *>(m_unit)->GetDIE(value);
531
532  case DW_FORM_ref_addr: {
533    DWARFUnit *ref_cu =
534        m_unit->GetSymbolFileDWARF().DebugInfo()->GetUnitContainingDIEOffset(
535            DIERef::Section::DebugInfo, value);
536    if (!ref_cu) {
537      m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
538          "DW_FORM_ref_addr DIE reference 0x%" PRIx64 " has no matching CU",
539          value);
540      return {};
541    }
542    return ref_cu->GetDIE(value);
543  }
544
545  case DW_FORM_ref_sig8: {
546    DWARFTypeUnit *tu =
547        m_unit->GetSymbolFileDWARF().DebugInfo()->GetTypeUnitForHash(value);
548    if (!tu)
549      return {};
550    return tu->GetDIE(tu->GetTypeOffset());
551  }
552
553  default:
554    return {};
555  }
556}
557
558uint64_t DWARFFormValue::Reference(dw_offset_t base_offset) const {
559  uint64_t value = m_value.value.uval;
560  switch (m_form) {
561  case DW_FORM_ref1:
562  case DW_FORM_ref2:
563  case DW_FORM_ref4:
564  case DW_FORM_ref8:
565  case DW_FORM_ref_udata:
566    return value + base_offset;
567
568  case DW_FORM_ref_addr:
569  case DW_FORM_ref_sig8:
570  case DW_FORM_GNU_ref_alt:
571    return value;
572
573  default:
574    return DW_INVALID_OFFSET;
575  }
576}
577
578const uint8_t *DWARFFormValue::BlockData() const { return m_value.data; }
579
580bool DWARFFormValue::IsBlockForm(const dw_form_t form) {
581  switch (form) {
582  case DW_FORM_exprloc:
583  case DW_FORM_block:
584  case DW_FORM_block1:
585  case DW_FORM_block2:
586  case DW_FORM_block4:
587    return true;
588  }
589  return false;
590}
591
592bool DWARFFormValue::IsDataForm(const dw_form_t form) {
593  switch (form) {
594  case DW_FORM_sdata:
595  case DW_FORM_udata:
596  case DW_FORM_data1:
597  case DW_FORM_data2:
598  case DW_FORM_data4:
599  case DW_FORM_data8:
600    return true;
601  }
602  return false;
603}
604
605bool DWARFFormValue::FormIsSupported(dw_form_t form) {
606  switch (form) {
607    case DW_FORM_addr:
608    case DW_FORM_addrx:
609    case DW_FORM_loclistx:
610    case DW_FORM_rnglistx:
611    case DW_FORM_block2:
612    case DW_FORM_block4:
613    case DW_FORM_data2:
614    case DW_FORM_data4:
615    case DW_FORM_data8:
616    case DW_FORM_string:
617    case DW_FORM_block:
618    case DW_FORM_block1:
619    case DW_FORM_data1:
620    case DW_FORM_flag:
621    case DW_FORM_sdata:
622    case DW_FORM_strp:
623    case DW_FORM_strx:
624    case DW_FORM_strx1:
625    case DW_FORM_strx2:
626    case DW_FORM_strx3:
627    case DW_FORM_strx4:
628    case DW_FORM_udata:
629    case DW_FORM_ref_addr:
630    case DW_FORM_ref1:
631    case DW_FORM_ref2:
632    case DW_FORM_ref4:
633    case DW_FORM_ref8:
634    case DW_FORM_ref_udata:
635    case DW_FORM_indirect:
636    case DW_FORM_sec_offset:
637    case DW_FORM_exprloc:
638    case DW_FORM_flag_present:
639    case DW_FORM_ref_sig8:
640    case DW_FORM_GNU_str_index:
641    case DW_FORM_GNU_addr_index:
642    case DW_FORM_implicit_const:
643      return true;
644    default:
645      break;
646  }
647  return false;
648}
649