File indexing completed on 2024-05-12 05:43:27
0001 /* 0002 Copyright (C) 2014-2015 Volker Krause <vkrause@kde.org> 0003 0004 This program is free software; you can redistribute it and/or modify it 0005 under the terms of the GNU Library General Public License as published by 0006 the Free Software Foundation; either version 2 of the License, or (at your 0007 option) any later version. 0008 0009 This program is distributed in the hope that it will be useful, but WITHOUT 0010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 0012 License for more details. 0013 0014 You should have received a copy of the GNU General Public License 0015 along with this program. If not, see <https://www.gnu.org/licenses/>. 0016 */ 0017 0018 #include "dwarfinfo.h" 0019 #include "dwarfcudie.h" 0020 #include "dwarfaddressranges.h" 0021 #include "dwarfranges.h" 0022 0023 #include <QDebug> 0024 0025 #include <dwarf.h> 0026 #include <libdwarf.h> 0027 0028 #include <elf.h> 0029 0030 #include <type_traits> 0031 0032 class DwarfInfoPrivate { 0033 public: 0034 DwarfInfoPrivate(DwarfInfo* qq); 0035 ~DwarfInfoPrivate(); 0036 0037 void scanCompilationUnits(); 0038 DwarfDie *dieForMangledSymbolRecursive(const QByteArray &symbol, DwarfDie *die) const; 0039 0040 ElfFile *elfFile = nullptr; 0041 QVector<DwarfCuDie*> compilationUnits; 0042 Dwarf_Obj_Access_Interface objAccessIface; 0043 Dwarf_Obj_Access_Methods objAccessMethods; 0044 0045 Dwarf_Debug dbg; 0046 0047 DwarfInfo *q; 0048 DwarfAddressRanges *aranges = nullptr; 0049 0050 bool isValid; 0051 }; 0052 0053 0054 static Dwarf_Endianness callback_get_byte_order(void *obj) 0055 { 0056 const DwarfInfoPrivate *d = reinterpret_cast<DwarfInfoPrivate*>(obj); 0057 return d->elfFile->byteOrder() == ELFDATA2LSB ? DW_OBJECT_LSB : DW_OBJECT_MSB; 0058 } 0059 0060 static Dwarf_Small callback_get_length_size(void *obj) 0061 { 0062 const DwarfInfoPrivate *d = reinterpret_cast<DwarfInfoPrivate*>(obj); 0063 return d->elfFile->addressSize(); 0064 } 0065 0066 static Dwarf_Small callback_get_pointer_size(void *obj) 0067 { 0068 const DwarfInfoPrivate *d = reinterpret_cast<DwarfInfoPrivate*>(obj); 0069 return d->elfFile->addressSize(); 0070 } 0071 0072 static Dwarf_Unsigned callback_get_section_count(void *obj) 0073 { 0074 const DwarfInfoPrivate *d = reinterpret_cast<DwarfInfoPrivate*>(obj); 0075 return d->elfFile->sectionHeaders().size(); 0076 } 0077 0078 static void callback_dwarf_handler(Dwarf_Error error, Dwarf_Ptr errarg) 0079 { 0080 DwarfInfoPrivate *d = reinterpret_cast<DwarfInfoPrivate*>(errarg); 0081 0082 // Ensure that errcore can be converted 0083 static_assert( std::is_convertible<Dwarf_Unsigned, unsigned long long>::value, "Incompatible DWARFs" ); 0084 0085 const char *errmsg = dwarf_errmsg(error); 0086 const Dwarf_Unsigned errcode = dwarf_errno(error); 0087 if (d->elfFile->isSeparateDebugFile()) { 0088 qWarning("DWARF error in debug file for %s: %s (errno %llu)", 0089 qPrintable(d->elfFile->contentFile()->fileName()), errmsg, static_cast<unsigned long long>(errcode)); 0090 } else { 0091 qWarning("DWARF error in %s: %s (errno %llu)", 0092 qPrintable(d->elfFile->fileName()), errmsg, static_cast<unsigned long long>(errcode)); 0093 } 0094 0095 d->isValid = false; 0096 } 0097 0098 static int callback_get_section_info(void *obj, Dwarf_Half index, Dwarf_Obj_Access_Section *sectionInfo, int *error) 0099 { 0100 const DwarfInfoPrivate *d = reinterpret_cast<DwarfInfoPrivate*>(obj); 0101 const auto sectionHeader = d->elfFile->sectionHeaders().at(index); 0102 sectionInfo->addr = (Dwarf_Addr)(d->elfFile->rawData() + sectionHeader->sectionOffset()); 0103 sectionInfo->size = sectionHeader->size(); 0104 sectionInfo->name = sectionHeader->name(); 0105 *error = DW_DLV_OK; 0106 return DW_DLV_OK; 0107 } 0108 0109 static int callback_load_section(void *obj, Dwarf_Half index, Dwarf_Small **returnData, int *error) 0110 { 0111 const DwarfInfoPrivate *d = reinterpret_cast<DwarfInfoPrivate*>(obj); 0112 const auto sectionHeader = d->elfFile->sectionHeaders().at(index); 0113 *returnData = d->elfFile->rawData() + sectionHeader->sectionOffset(); 0114 *error = DW_DLV_OK; 0115 return DW_DLV_OK; 0116 } 0117 0118 0119 DwarfInfoPrivate::DwarfInfoPrivate(DwarfInfo *qq) : 0120 q(qq), 0121 isValid(true) 0122 { 0123 objAccessIface.object = this; 0124 objAccessIface.methods = &objAccessMethods; 0125 objAccessMethods.get_byte_order = callback_get_byte_order; 0126 objAccessMethods.get_length_size = callback_get_length_size; 0127 objAccessMethods.get_pointer_size = callback_get_pointer_size; 0128 objAccessMethods.get_section_count = callback_get_section_count; 0129 objAccessMethods.get_section_info = callback_get_section_info; 0130 objAccessMethods.load_section = callback_load_section; 0131 #ifndef Q_OS_FREEBSD 0132 // TODO: check structure fields at cmake or compile time 0133 // rather than ifdeffing on an OS. 0134 // 0135 // FreeBSD's DWARF.h doesn't have this (separate developments). 0136 objAccessMethods.relocate_a_section = nullptr; 0137 #endif 0138 } 0139 0140 DwarfInfoPrivate::~DwarfInfoPrivate() 0141 { 0142 qDeleteAll(compilationUnits); 0143 dwarf_object_finish(dbg, nullptr); 0144 } 0145 0146 void DwarfInfoPrivate::scanCompilationUnits() 0147 { 0148 Dwarf_Unsigned nextHeader = 0; 0149 forever { 0150 auto res = dwarf_next_cu_header(dbg, nullptr, nullptr, nullptr, nullptr, &nextHeader, nullptr); 0151 if (res != DW_DLV_OK) 0152 return; 0153 0154 Dwarf_Die cuDie = nullptr; 0155 res = dwarf_siblingof_b(dbg, nullptr, true, &cuDie, nullptr); 0156 if(res != DW_DLV_OK) 0157 return; 0158 0159 compilationUnits.push_back(new DwarfCuDie(cuDie, q)); 0160 } 0161 } 0162 0163 0164 DwarfDie* DwarfInfoPrivate::dieForMangledSymbolRecursive(const QByteArray& symbol, DwarfDie *die) const 0165 { 0166 if (die->attribute(DW_AT_linkage_name).toByteArray() == symbol) 0167 return die; 0168 foreach (auto childDie, die->children()) { 0169 const auto hit = dieForMangledSymbolRecursive(symbol, childDie); 0170 if (hit) 0171 return hit; 0172 } 0173 return nullptr; 0174 } 0175 0176 DwarfInfo::DwarfInfo(ElfFile* elfFile) : 0177 d(new DwarfInfoPrivate(this)) 0178 { 0179 d->elfFile = elfFile; 0180 0181 if (dwarf_object_init(&d->objAccessIface, &callback_dwarf_handler, d.get(), &d->dbg, nullptr) != DW_DLV_OK) { 0182 qDebug() << "error loading dwarf data"; 0183 } 0184 } 0185 0186 DwarfInfo::~DwarfInfo() 0187 { 0188 // make sure this is destroyed before d is reset, needs dwarfHandle in its dtor 0189 delete d->aranges; 0190 } 0191 0192 ElfFile* DwarfInfo::elfFile() const 0193 { 0194 if (d->elfFile->isSeparateDebugFile()) 0195 return d->elfFile->contentFile(); 0196 return d->elfFile; 0197 } 0198 0199 DwarfAddressRanges* DwarfInfo::addressRanges() const 0200 { 0201 if (!d->aranges) 0202 d->aranges = new DwarfAddressRanges(const_cast<DwarfInfo*>(this)); 0203 return d->aranges; 0204 } 0205 0206 Dwarf_Debug DwarfInfo::dwarfHandle() const 0207 { 0208 return d->dbg; 0209 } 0210 0211 QVector< DwarfCuDie* > DwarfInfo::compilationUnits() const 0212 { 0213 if (d->compilationUnits.isEmpty()) 0214 d->scanCompilationUnits(); 0215 return d->compilationUnits; 0216 } 0217 0218 DwarfCuDie* DwarfInfo::compilationUnitForAddress(uint64_t address) const 0219 { 0220 auto cu = addressRanges()->compilationUnitForAddress(address); 0221 if (cu) 0222 return cu; 0223 0224 foreach (auto cu, compilationUnits()) { 0225 auto ranges = cu->attribute(DW_AT_ranges).value<DwarfRanges>(); 0226 for (int i = 0; i < ranges.size(); ++i) { 0227 auto range = ranges.entry(i); 0228 if (range->dwr_type == DW_RANGES_ENTRY && range->dwr_addr1 <= address && address < range->dwr_addr2) 0229 return cu; 0230 // TODO DW_RANGES_ADDRESS_SELECTION 0231 } 0232 } 0233 0234 return nullptr; 0235 } 0236 0237 DwarfDie* DwarfInfo::dieAtOffset(Dwarf_Off offset) const 0238 { 0239 const auto cus = compilationUnits(); 0240 if (cus.isEmpty()) 0241 return nullptr; 0242 0243 auto it = std::lower_bound(cus.begin(), cus.end(), offset, [](DwarfDie* lhs, Dwarf_Off rhs) { return lhs->offset() < rhs; }); 0244 0245 if (it != cus.end() && (*it)->offset() == offset) 0246 return *it; 0247 0248 Q_ASSERT(it != cus.begin()); 0249 --it; 0250 return (*it)->dieAtOffset(offset); 0251 } 0252 0253 DwarfDie* DwarfInfo::dieForMangledSymbol(const QByteArray& symbol) const 0254 { 0255 foreach (auto die, compilationUnits()) { 0256 const auto hit = d->dieForMangledSymbolRecursive(symbol, die); 0257 if (hit) 0258 return hit; 0259 } 0260 return nullptr; 0261 } 0262 0263 bool DwarfInfo::isValid() const 0264 { 0265 return d->isValid; 0266 }