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 }