Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
39645 views
//===-- DWARFFormValue.cpp ------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <cassert>9#include <optional>1011#include "lldb/Core/Module.h"12#include "lldb/Core/dwarf.h"13#include "lldb/Symbol/ObjectFile.h"14#include "lldb/Utility/Stream.h"1516#include "DWARFDebugInfo.h"17#include "DWARFFormValue.h"18#include "DWARFUnit.h"1920using namespace lldb_private;21using namespace lldb_private::dwarf;22using namespace lldb_private::plugin::dwarf;2324void DWARFFormValue::Clear() {25m_unit = nullptr;26m_form = dw_form_t(0);27m_value = ValueTypeTag();28}2930bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data,31lldb::offset_t *offset_ptr) {32if (m_form == DW_FORM_implicit_const)33return true;3435bool indirect = false;36bool is_block = false;37m_value.data = nullptr;38uint8_t ref_addr_size;39// Read the value for the form into value and follow and DW_FORM_indirect40// instances we run into41do {42indirect = false;43switch (m_form) {44case DW_FORM_addr:45assert(m_unit);46m_value.value.uval =47data.GetMaxU64(offset_ptr, DWARFUnit::GetAddressByteSize(m_unit));48break;49case DW_FORM_block1:50m_value.value.uval = data.GetU8(offset_ptr);51is_block = true;52break;53case DW_FORM_block2:54m_value.value.uval = data.GetU16(offset_ptr);55is_block = true;56break;57case DW_FORM_block4:58m_value.value.uval = data.GetU32(offset_ptr);59is_block = true;60break;61case DW_FORM_data16:62m_value.value.uval = 16;63is_block = true;64break;65case DW_FORM_exprloc:66case DW_FORM_block:67m_value.value.uval = data.GetULEB128(offset_ptr);68is_block = true;69break;70case DW_FORM_string:71m_value.value.cstr = data.GetCStr(offset_ptr);72break;73case DW_FORM_sdata:74m_value.value.sval = data.GetSLEB128(offset_ptr);75break;76case DW_FORM_strp:77case DW_FORM_line_strp:78case DW_FORM_sec_offset:79m_value.value.uval = data.GetMaxU64(offset_ptr, 4);80break;81case DW_FORM_addrx1:82case DW_FORM_strx1:83case DW_FORM_ref1:84case DW_FORM_data1:85case DW_FORM_flag:86m_value.value.uval = data.GetU8(offset_ptr);87break;88case DW_FORM_addrx2:89case DW_FORM_strx2:90case DW_FORM_ref2:91case DW_FORM_data2:92m_value.value.uval = data.GetU16(offset_ptr);93break;94case DW_FORM_addrx3:95case DW_FORM_strx3:96m_value.value.uval = data.GetMaxU64(offset_ptr, 3);97break;98case DW_FORM_addrx4:99case DW_FORM_strx4:100case DW_FORM_ref4:101case DW_FORM_data4:102m_value.value.uval = data.GetU32(offset_ptr);103break;104case DW_FORM_data8:105case DW_FORM_ref8:106case DW_FORM_ref_sig8:107m_value.value.uval = data.GetU64(offset_ptr);108break;109case DW_FORM_addrx:110case DW_FORM_loclistx:111case DW_FORM_rnglistx:112case DW_FORM_strx:113case DW_FORM_udata:114case DW_FORM_ref_udata:115case DW_FORM_GNU_str_index:116case DW_FORM_GNU_addr_index:117m_value.value.uval = data.GetULEB128(offset_ptr);118break;119case DW_FORM_ref_addr:120assert(m_unit);121if (m_unit->GetVersion() <= 2)122ref_addr_size = m_unit->GetAddressByteSize();123else124ref_addr_size = 4;125m_value.value.uval = data.GetMaxU64(offset_ptr, ref_addr_size);126break;127case DW_FORM_indirect:128m_form = static_cast<dw_form_t>(data.GetULEB128(offset_ptr));129indirect = true;130break;131case DW_FORM_flag_present:132m_value.value.uval = 1;133break;134default:135return false;136}137} while (indirect);138139if (is_block) {140m_value.data = data.PeekData(*offset_ptr, m_value.value.uval);141if (m_value.data != nullptr) {142*offset_ptr += m_value.value.uval;143}144}145146return true;147}148149struct FormSize {150uint8_t valid:1, size:7;151};152static FormSize g_form_sizes[] = {153{0, 0}, // 0x00 unused154{0, 0}, // 0x01 DW_FORM_addr155{0, 0}, // 0x02 unused156{0, 0}, // 0x03 DW_FORM_block2157{0, 0}, // 0x04 DW_FORM_block4158{1, 2}, // 0x05 DW_FORM_data2159{1, 4}, // 0x06 DW_FORM_data4160{1, 8}, // 0x07 DW_FORM_data8161{0, 0}, // 0x08 DW_FORM_string162{0, 0}, // 0x09 DW_FORM_block163{0, 0}, // 0x0a DW_FORM_block1164{1, 1}, // 0x0b DW_FORM_data1165{1, 1}, // 0x0c DW_FORM_flag166{0, 0}, // 0x0d DW_FORM_sdata167{1, 4}, // 0x0e DW_FORM_strp168{0, 0}, // 0x0f DW_FORM_udata169{0, 0}, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes170// for DWARF32, 8 bytes for DWARF32 in DWARF 3 and later171{1, 1}, // 0x11 DW_FORM_ref1172{1, 2}, // 0x12 DW_FORM_ref2173{1, 4}, // 0x13 DW_FORM_ref4174{1, 8}, // 0x14 DW_FORM_ref8175{0, 0}, // 0x15 DW_FORM_ref_udata176{0, 0}, // 0x16 DW_FORM_indirect177{1, 4}, // 0x17 DW_FORM_sec_offset178{0, 0}, // 0x18 DW_FORM_exprloc179{1, 0}, // 0x19 DW_FORM_flag_present180{0, 0}, // 0x1a DW_FORM_strx (ULEB128)181{0, 0}, // 0x1b DW_FORM_addrx (ULEB128)182{1, 4}, // 0x1c DW_FORM_ref_sup4183{0, 0}, // 0x1d DW_FORM_strp_sup (4 bytes for DWARF32, 8 bytes for DWARF64)184{1, 16}, // 0x1e DW_FORM_data16185{1, 4}, // 0x1f DW_FORM_line_strp186{1, 8}, // 0x20 DW_FORM_ref_sig8187};188189std::optional<uint8_t> DWARFFormValue::GetFixedSize(dw_form_t form,190const DWARFUnit *u) {191if (form <= DW_FORM_ref_sig8 && g_form_sizes[form].valid)192return static_cast<uint8_t>(g_form_sizes[form].size);193if (form == DW_FORM_addr && u)194return u->GetAddressByteSize();195return std::nullopt;196}197198std::optional<uint8_t> DWARFFormValue::GetFixedSize() const {199return GetFixedSize(m_form, m_unit);200}201202bool DWARFFormValue::SkipValue(const DWARFDataExtractor &debug_info_data,203lldb::offset_t *offset_ptr) const {204return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, m_unit);205}206207bool DWARFFormValue::SkipValue(dw_form_t form,208const DWARFDataExtractor &debug_info_data,209lldb::offset_t *offset_ptr,210const DWARFUnit *unit) {211uint8_t ref_addr_size;212switch (form) {213// Blocks if inlined data that have a length field and the data bytes inlined214// in the .debug_info215case DW_FORM_exprloc:216case DW_FORM_block: {217uint64_t size = debug_info_data.GetULEB128(offset_ptr);218*offset_ptr += size;219}220return true;221case DW_FORM_block1: {222uint8_t size = debug_info_data.GetU8(offset_ptr);223*offset_ptr += size;224}225return true;226case DW_FORM_block2: {227uint16_t size = debug_info_data.GetU16(offset_ptr);228*offset_ptr += size;229}230return true;231case DW_FORM_block4: {232uint32_t size = debug_info_data.GetU32(offset_ptr);233*offset_ptr += size;234}235return true;236237// Inlined NULL terminated C-strings238case DW_FORM_string:239debug_info_data.GetCStr(offset_ptr);240return true;241242// Compile unit address sized values243case DW_FORM_addr:244*offset_ptr += DWARFUnit::GetAddressByteSize(unit);245return true;246247case DW_FORM_ref_addr:248ref_addr_size = 4;249assert(unit); // Unit must be valid for DW_FORM_ref_addr objects or we will250// get this wrong251if (unit->GetVersion() <= 2)252ref_addr_size = unit->GetAddressByteSize();253else254ref_addr_size = 4;255*offset_ptr += ref_addr_size;256return true;257258// 0 bytes values (implied from DW_FORM)259case DW_FORM_flag_present:260case DW_FORM_implicit_const:261return true;262263// 1 byte values264case DW_FORM_addrx1:265case DW_FORM_data1:266case DW_FORM_flag:267case DW_FORM_ref1:268case DW_FORM_strx1:269*offset_ptr += 1;270return true;271272// 2 byte values273case DW_FORM_addrx2:274case DW_FORM_data2:275case DW_FORM_ref2:276case DW_FORM_strx2:277*offset_ptr += 2;278return true;279280// 3 byte values281case DW_FORM_addrx3:282case DW_FORM_strx3:283*offset_ptr += 3;284return true;285286// 32 bit for DWARF 32, 64 for DWARF 64287case DW_FORM_sec_offset:288case DW_FORM_strp:289case DW_FORM_line_strp:290*offset_ptr += 4;291return true;292293// 4 byte values294case DW_FORM_addrx4:295case DW_FORM_data4:296case DW_FORM_ref4:297case DW_FORM_strx4:298*offset_ptr += 4;299return true;300301// 8 byte values302case DW_FORM_data8:303case DW_FORM_ref8:304case DW_FORM_ref_sig8:305*offset_ptr += 8;306return true;307308// signed or unsigned LEB 128 values309case DW_FORM_addrx:310case DW_FORM_loclistx:311case DW_FORM_rnglistx:312case DW_FORM_sdata:313case DW_FORM_udata:314case DW_FORM_ref_udata:315case DW_FORM_GNU_addr_index:316case DW_FORM_GNU_str_index:317case DW_FORM_strx:318debug_info_data.Skip_LEB128(offset_ptr);319return true;320321case DW_FORM_indirect: {322auto indirect_form =323static_cast<dw_form_t>(debug_info_data.GetULEB128(offset_ptr));324return DWARFFormValue::SkipValue(indirect_form, debug_info_data,325offset_ptr, unit);326}327328default:329break;330}331return false;332}333334void DWARFFormValue::Dump(Stream &s) const {335uint64_t uvalue = Unsigned();336bool unit_relative_offset = false;337338switch (m_form) {339case DW_FORM_addr:340DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t));341break;342case DW_FORM_flag:343case DW_FORM_data1:344s.PutHex8(uvalue);345break;346case DW_FORM_data2:347s.PutHex16(uvalue);348break;349case DW_FORM_sec_offset:350case DW_FORM_data4:351s.PutHex32(uvalue);352break;353case DW_FORM_ref_sig8:354case DW_FORM_data8:355s.PutHex64(uvalue);356break;357case DW_FORM_string:358s.QuotedCString(AsCString());359break;360case DW_FORM_exprloc:361case DW_FORM_block:362case DW_FORM_block1:363case DW_FORM_block2:364case DW_FORM_block4:365if (uvalue > 0) {366switch (m_form) {367case DW_FORM_exprloc:368case DW_FORM_block:369s.Printf("<0x%" PRIx64 "> ", uvalue);370break;371case DW_FORM_block1:372s.Printf("<0x%2.2x> ", (uint8_t)uvalue);373break;374case DW_FORM_block2:375s.Printf("<0x%4.4x> ", (uint16_t)uvalue);376break;377case DW_FORM_block4:378s.Printf("<0x%8.8x> ", (uint32_t)uvalue);379break;380default:381break;382}383384const uint8_t *data_ptr = m_value.data;385if (data_ptr) {386const uint8_t *end_data_ptr =387data_ptr + uvalue; // uvalue contains size of block388while (data_ptr < end_data_ptr) {389s.Printf("%2.2x ", *data_ptr);390++data_ptr;391}392} else393s.PutCString("NULL");394}395break;396397case DW_FORM_sdata:398s.PutSLEB128(uvalue);399break;400case DW_FORM_udata:401s.PutULEB128(uvalue);402break;403case DW_FORM_strp:404case DW_FORM_line_strp: {405const char *dbg_str = AsCString();406if (dbg_str) {407s.QuotedCString(dbg_str);408} else {409s.PutHex32(uvalue);410}411} break;412413case DW_FORM_ref_addr: {414assert(m_unit); // Unit must be valid for DW_FORM_ref_addr objects or we415// will get this wrong416if (m_unit->GetVersion() <= 2)417DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t) * 2);418else419DumpAddress(s.AsRawOstream(), uvalue,4204 * 2); // 4 for DWARF32, 8 for DWARF64, but we don't421// support DWARF64 yet422break;423}424case DW_FORM_ref1:425unit_relative_offset = true;426break;427case DW_FORM_ref2:428unit_relative_offset = true;429break;430case DW_FORM_ref4:431unit_relative_offset = true;432break;433case DW_FORM_ref8:434unit_relative_offset = true;435break;436case DW_FORM_ref_udata:437unit_relative_offset = true;438break;439440// All DW_FORM_indirect attributes should be resolved prior to calling this441// function442case DW_FORM_indirect:443s.PutCString("DW_FORM_indirect");444break;445case DW_FORM_flag_present:446break;447default:448s.Printf("DW_FORM(0x%4.4x)", m_form);449break;450}451452if (unit_relative_offset) {453assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile454// unit relative or we will get this wrong455s.Printf("{0x%8.8" PRIx64 "}", uvalue + m_unit->GetOffset());456}457}458459const char *DWARFFormValue::AsCString() const {460DWARFContext &context = m_unit->GetSymbolFileDWARF().GetDWARFContext();461462if (m_form == DW_FORM_string)463return m_value.value.cstr;464if (m_form == DW_FORM_strp)465return context.getOrLoadStrData().PeekCStr(m_value.value.uval);466467if (m_form == DW_FORM_GNU_str_index || m_form == DW_FORM_strx ||468m_form == DW_FORM_strx1 || m_form == DW_FORM_strx2 ||469m_form == DW_FORM_strx3 || m_form == DW_FORM_strx4) {470471std::optional<uint64_t> offset =472m_unit->GetStringOffsetSectionItem(m_value.value.uval);473if (!offset)474return nullptr;475return context.getOrLoadStrData().PeekCStr(*offset);476}477478if (m_form == DW_FORM_line_strp)479return context.getOrLoadLineStrData().PeekCStr(m_value.value.uval);480481return nullptr;482}483484dw_addr_t DWARFFormValue::Address() const {485SymbolFileDWARF &symbol_file = m_unit->GetSymbolFileDWARF();486487if (m_form == DW_FORM_addr)488return Unsigned();489490assert(m_unit);491assert(m_form == DW_FORM_GNU_addr_index || m_form == DW_FORM_addrx ||492m_form == DW_FORM_addrx1 || m_form == DW_FORM_addrx2 ||493m_form == DW_FORM_addrx3 || m_form == DW_FORM_addrx4);494495uint32_t index_size = m_unit->GetAddressByteSize();496dw_offset_t addr_base = m_unit->GetAddrBase();497lldb::offset_t offset = addr_base + m_value.value.uval * index_size;498return symbol_file.GetDWARFContext().getOrLoadAddrData().GetMaxU64(499&offset, index_size);500}501502std::pair<DWARFUnit *, uint64_t>503DWARFFormValue::ReferencedUnitAndOffset() const {504uint64_t value = m_value.value.uval;505switch (m_form) {506case DW_FORM_ref1:507case DW_FORM_ref2:508case DW_FORM_ref4:509case DW_FORM_ref8:510case DW_FORM_ref_udata:511assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile512// unit relative or we will get this wrong513value += m_unit->GetOffset();514if (!m_unit->ContainsDIEOffset(value)) {515m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(516"DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value);517return {nullptr, 0};518}519return {const_cast<DWARFUnit *>(m_unit), value};520521case DW_FORM_ref_addr: {522DWARFUnit *ref_cu =523m_unit->GetSymbolFileDWARF().DebugInfo().GetUnitContainingDIEOffset(524DIERef::Section::DebugInfo, value);525if (!ref_cu) {526m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(527"DW_FORM_ref_addr DIE reference {0:x16} has no matching CU", value);528return {nullptr, 0};529}530return {ref_cu, value};531}532533case DW_FORM_ref_sig8: {534DWARFTypeUnit *tu =535m_unit->GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(value);536if (!tu)537return {nullptr, 0};538return {tu, tu->GetTypeOffset()};539}540541default:542return {nullptr, 0};543}544}545546DWARFDIE DWARFFormValue::Reference() const {547auto [unit, offset] = ReferencedUnitAndOffset();548return unit ? unit->GetDIE(offset) : DWARFDIE();549}550551uint64_t DWARFFormValue::Reference(dw_offset_t base_offset) const {552uint64_t value = m_value.value.uval;553switch (m_form) {554case DW_FORM_ref1:555case DW_FORM_ref2:556case DW_FORM_ref4:557case DW_FORM_ref8:558case DW_FORM_ref_udata:559return value + base_offset;560561case DW_FORM_ref_addr:562case DW_FORM_ref_sig8:563case DW_FORM_GNU_ref_alt:564return value;565566default:567return DW_INVALID_OFFSET;568}569}570571const uint8_t *DWARFFormValue::BlockData() const { return m_value.data; }572573bool DWARFFormValue::IsBlockForm(const dw_form_t form) {574switch (form) {575case DW_FORM_exprloc:576case DW_FORM_block:577case DW_FORM_block1:578case DW_FORM_block2:579case DW_FORM_block4:580return true;581default:582return false;583}584llvm_unreachable("All cases handled above!");585}586587bool DWARFFormValue::IsDataForm(const dw_form_t form) {588switch (form) {589case DW_FORM_sdata:590case DW_FORM_udata:591case DW_FORM_data1:592case DW_FORM_data2:593case DW_FORM_data4:594case DW_FORM_data8:595return true;596default:597return false;598}599llvm_unreachable("All cases handled above!");600}601602bool DWARFFormValue::FormIsSupported(dw_form_t form) {603switch (form) {604case DW_FORM_addr:605case DW_FORM_addrx:606case DW_FORM_loclistx:607case DW_FORM_rnglistx:608case DW_FORM_block2:609case DW_FORM_block4:610case DW_FORM_data2:611case DW_FORM_data4:612case DW_FORM_data8:613case DW_FORM_string:614case DW_FORM_block:615case DW_FORM_block1:616case DW_FORM_data1:617case DW_FORM_flag:618case DW_FORM_sdata:619case DW_FORM_strp:620case DW_FORM_line_strp:621case DW_FORM_strx:622case DW_FORM_strx1:623case DW_FORM_strx2:624case DW_FORM_strx3:625case DW_FORM_strx4:626case DW_FORM_udata:627case DW_FORM_ref_addr:628case DW_FORM_ref1:629case DW_FORM_ref2:630case DW_FORM_ref4:631case DW_FORM_ref8:632case DW_FORM_ref_udata:633case DW_FORM_indirect:634case DW_FORM_sec_offset:635case DW_FORM_exprloc:636case DW_FORM_flag_present:637case DW_FORM_ref_sig8:638case DW_FORM_GNU_str_index:639case DW_FORM_GNU_addr_index:640case DW_FORM_implicit_const:641return true;642default:643break;644}645return false;646}647648649