File indexing completed on 2024-05-19 05:44:07

0001 /*
0002     Copyright (C) 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 "dwarfaddressranges.h"
0019 #include "dwarfinfo.h"
0020 #include "dwarfcudie.h"
0021 
0022 #include <dwarf.h>
0023 
0024 #include <cassert>
0025 
0026 DwarfAddressRanges::DwarfAddressRanges(DwarfInfo* info) :
0027     m_aranges(nullptr),
0028     m_info(info)
0029 {
0030     assert(info);
0031     const auto res = dwarf_get_aranges(info->dwarfHandle(), &m_aranges, &m_arangesSize, nullptr);
0032     if (res != DW_DLV_OK)
0033         return;
0034 }
0035 
0036 DwarfAddressRanges::~DwarfAddressRanges()
0037 {
0038     for (int i = 0; i < m_arangesSize; ++i)
0039         dwarf_dealloc(m_info->dwarfHandle(), m_aranges[i], DW_DLA_ARANGE);
0040     dwarf_dealloc(m_info->dwarfHandle(), m_aranges, DW_DLA_LIST);
0041 }
0042 
0043 bool DwarfAddressRanges::isValid() const
0044 {
0045     return m_aranges;
0046 }
0047 
0048 DwarfCuDie* DwarfAddressRanges::compilationUnitForAddress(uint64_t addr) const
0049 {
0050     if (!isValid())
0051         return nullptr;
0052 
0053     Dwarf_Arange arange;
0054     auto res = dwarf_get_arange(m_aranges, m_arangesSize, addr, &arange, nullptr);
0055     if (res != DW_DLV_OK)
0056         return nullptr;
0057 
0058     Dwarf_Off offset;
0059     res = dwarf_get_cu_die_offset(arange, &offset, nullptr);
0060     if (res != DW_DLV_OK)
0061         return nullptr;
0062 
0063     auto die = m_info->dieAtOffset(offset);
0064     if (!die)
0065         return nullptr;
0066 
0067     assert(die->isCompilationUnit());
0068     return static_cast<DwarfCuDie*>(die);
0069 }
0070 
0071 static DwarfDie* findByLowPCRecursive(DwarfDie *die, uint64_t addr)
0072 {
0073     const auto lowPC = die->attribute(DW_AT_low_pc).toULongLong();
0074     if (lowPC == addr)
0075         return die;
0076 
0077     foreach (const auto child, die->children()) {
0078         auto res = findByLowPCRecursive(child, addr);
0079         if (res)
0080             return res;
0081     }
0082 
0083     return nullptr;
0084 }
0085 
0086 DwarfDie* DwarfAddressRanges::dieForAddress(uint64_t addr) const
0087 {
0088     const auto cu = compilationUnitForAddress(addr);
0089     if (!cu)
0090         return nullptr;
0091 
0092     foreach (const auto die, cu->children()) {
0093         auto res = findByLowPCRecursive(die, addr);
0094         if (res)
0095             return res;
0096     }
0097 
0098     return nullptr;
0099 }