Path: blob/main/contrib/llvm-project/lldb/source/Core/Section.cpp
39587 views
//===-- Section.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 "lldb/Core/Section.h"9#include "lldb/Core/Address.h"10#include "lldb/Core/Module.h"11#include "lldb/Symbol/ObjectFile.h"12#include "lldb/Target/SectionLoadList.h"13#include "lldb/Target/Target.h"14#include "lldb/Utility/FileSpec.h"15#include "lldb/Utility/VMRange.h"1617#include <cinttypes>18#include <limits>19#include <utility>2021namespace lldb_private {22class DataExtractor;23}24using namespace lldb;25using namespace lldb_private;2627const char *Section::GetTypeAsCString() const {28switch (m_type) {29case eSectionTypeInvalid:30return "invalid";31case eSectionTypeCode:32return "code";33case eSectionTypeContainer:34return "container";35case eSectionTypeData:36return "data";37case eSectionTypeDataCString:38return "data-cstr";39case eSectionTypeDataCStringPointers:40return "data-cstr-ptr";41case eSectionTypeDataSymbolAddress:42return "data-symbol-addr";43case eSectionTypeData4:44return "data-4-byte";45case eSectionTypeData8:46return "data-8-byte";47case eSectionTypeData16:48return "data-16-byte";49case eSectionTypeDataPointers:50return "data-ptrs";51case eSectionTypeDebug:52return "debug";53case eSectionTypeZeroFill:54return "zero-fill";55case eSectionTypeDataObjCMessageRefs:56return "objc-message-refs";57case eSectionTypeDataObjCCFStrings:58return "objc-cfstrings";59case eSectionTypeDWARFDebugAbbrev:60return "dwarf-abbrev";61case eSectionTypeDWARFDebugAbbrevDwo:62return "dwarf-abbrev-dwo";63case eSectionTypeDWARFDebugAddr:64return "dwarf-addr";65case eSectionTypeDWARFDebugAranges:66return "dwarf-aranges";67case eSectionTypeDWARFDebugCuIndex:68return "dwarf-cu-index";69case eSectionTypeDWARFDebugTuIndex:70return "dwarf-tu-index";71case eSectionTypeDWARFDebugFrame:72return "dwarf-frame";73case eSectionTypeDWARFDebugInfo:74return "dwarf-info";75case eSectionTypeDWARFDebugInfoDwo:76return "dwarf-info-dwo";77case eSectionTypeDWARFDebugLine:78return "dwarf-line";79case eSectionTypeDWARFDebugLineStr:80return "dwarf-line-str";81case eSectionTypeDWARFDebugLoc:82return "dwarf-loc";83case eSectionTypeDWARFDebugLocDwo:84return "dwarf-loc-dwo";85case eSectionTypeDWARFDebugLocLists:86return "dwarf-loclists";87case eSectionTypeDWARFDebugLocListsDwo:88return "dwarf-loclists-dwo";89case eSectionTypeDWARFDebugMacInfo:90return "dwarf-macinfo";91case eSectionTypeDWARFDebugMacro:92return "dwarf-macro";93case eSectionTypeDWARFDebugPubNames:94return "dwarf-pubnames";95case eSectionTypeDWARFDebugPubTypes:96return "dwarf-pubtypes";97case eSectionTypeDWARFDebugRanges:98return "dwarf-ranges";99case eSectionTypeDWARFDebugRngLists:100return "dwarf-rnglists";101case eSectionTypeDWARFDebugRngListsDwo:102return "dwarf-rnglists-dwo";103case eSectionTypeDWARFDebugStr:104return "dwarf-str";105case eSectionTypeDWARFDebugStrDwo:106return "dwarf-str-dwo";107case eSectionTypeDWARFDebugStrOffsets:108return "dwarf-str-offsets";109case eSectionTypeDWARFDebugStrOffsetsDwo:110return "dwarf-str-offsets-dwo";111case eSectionTypeDWARFDebugTypes:112return "dwarf-types";113case eSectionTypeDWARFDebugTypesDwo:114return "dwarf-types-dwo";115case eSectionTypeDWARFDebugNames:116return "dwarf-names";117case eSectionTypeELFSymbolTable:118return "elf-symbol-table";119case eSectionTypeELFDynamicSymbols:120return "elf-dynamic-symbols";121case eSectionTypeELFRelocationEntries:122return "elf-relocation-entries";123case eSectionTypeELFDynamicLinkInfo:124return "elf-dynamic-link-info";125case eSectionTypeDWARFAppleNames:126return "apple-names";127case eSectionTypeDWARFAppleTypes:128return "apple-types";129case eSectionTypeDWARFAppleNamespaces:130return "apple-namespaces";131case eSectionTypeDWARFAppleObjC:132return "apple-objc";133case eSectionTypeEHFrame:134return "eh-frame";135case eSectionTypeARMexidx:136return "ARM.exidx";137case eSectionTypeARMextab:138return "ARM.extab";139case eSectionTypeCompactUnwind:140return "compact-unwind";141case eSectionTypeGoSymtab:142return "go-symtab";143case eSectionTypeAbsoluteAddress:144return "absolute";145case eSectionTypeDWARFGNUDebugAltLink:146return "dwarf-gnu-debugaltlink";147case eSectionTypeCTF:148return "ctf";149case eSectionTypeOther:150return "regular";151case eSectionTypeSwiftModules:152return "swift-modules";153}154return "unknown";155}156157Section::Section(const ModuleSP &module_sp, ObjectFile *obj_file,158user_id_t sect_id, ConstString name,159SectionType sect_type, addr_t file_addr, addr_t byte_size,160lldb::offset_t file_offset, lldb::offset_t file_size,161uint32_t log2align, uint32_t flags,162uint32_t target_byte_size /*=1*/)163: ModuleChild(module_sp), UserID(sect_id), Flags(flags),164m_obj_file(obj_file), m_type(sect_type), m_parent_wp(), m_name(name),165m_file_addr(file_addr), m_byte_size(byte_size),166m_file_offset(file_offset), m_file_size(file_size),167m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false),168m_thread_specific(false), m_readable(false), m_writable(false),169m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) {170}171172Section::Section(const lldb::SectionSP &parent_section_sp,173const ModuleSP &module_sp, ObjectFile *obj_file,174user_id_t sect_id, ConstString name,175SectionType sect_type, addr_t file_addr, addr_t byte_size,176lldb::offset_t file_offset, lldb::offset_t file_size,177uint32_t log2align, uint32_t flags,178uint32_t target_byte_size /*=1*/)179: ModuleChild(module_sp), UserID(sect_id), Flags(flags),180m_obj_file(obj_file), m_type(sect_type), m_parent_wp(), m_name(name),181m_file_addr(file_addr), m_byte_size(byte_size),182m_file_offset(file_offset), m_file_size(file_size),183m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false),184m_thread_specific(false), m_readable(false), m_writable(false),185m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) {186if (parent_section_sp)187m_parent_wp = parent_section_sp;188}189190Section::~Section() = default;191192addr_t Section::GetFileAddress() const {193SectionSP parent_sp(GetParent());194if (parent_sp) {195// This section has a parent which means m_file_addr is an offset into the196// parent section, so the file address for this section is the file address197// of the parent plus the offset198return parent_sp->GetFileAddress() + m_file_addr;199}200// This section has no parent, so m_file_addr is the file base address201return m_file_addr;202}203204bool Section::SetFileAddress(lldb::addr_t file_addr) {205SectionSP parent_sp(GetParent());206if (parent_sp) {207if (m_file_addr >= file_addr)208return parent_sp->SetFileAddress(m_file_addr - file_addr);209return false;210} else {211// This section has no parent, so m_file_addr is the file base address212m_file_addr = file_addr;213return true;214}215}216217lldb::addr_t Section::GetOffset() const {218// This section has a parent which means m_file_addr is an offset.219SectionSP parent_sp(GetParent());220if (parent_sp)221return m_file_addr;222223// This section has no parent, so there is no offset to be had224return 0;225}226227addr_t Section::GetLoadBaseAddress(Target *target) const {228addr_t load_base_addr = LLDB_INVALID_ADDRESS;229SectionSP parent_sp(GetParent());230if (parent_sp) {231load_base_addr = parent_sp->GetLoadBaseAddress(target);232if (load_base_addr != LLDB_INVALID_ADDRESS)233load_base_addr += GetOffset();234}235if (load_base_addr == LLDB_INVALID_ADDRESS) {236load_base_addr = target->GetSectionLoadList().GetSectionLoadAddress(237const_cast<Section *>(this)->shared_from_this());238}239return load_base_addr;240}241242bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr,243bool allow_section_end) const {244const size_t num_children = m_children.GetSize();245for (size_t i = 0; i < num_children; i++) {246Section *child_section = m_children.GetSectionAtIndex(i).get();247248addr_t child_offset = child_section->GetOffset();249if (child_offset <= offset &&250offset - child_offset <251child_section->GetByteSize() + (allow_section_end ? 1 : 0))252return child_section->ResolveContainedAddress(offset - child_offset,253so_addr, allow_section_end);254}255so_addr.SetOffset(offset);256so_addr.SetSection(const_cast<Section *>(this)->shared_from_this());257258// Ensure that there are no orphaned (i.e., moduleless) sections.259assert(GetModule().get());260return true;261}262263bool Section::ContainsFileAddress(addr_t vm_addr) const {264const addr_t file_addr = GetFileAddress();265if (file_addr != LLDB_INVALID_ADDRESS && !IsThreadSpecific()) {266if (file_addr <= vm_addr) {267const addr_t offset = (vm_addr - file_addr) * m_target_byte_size;268return offset < GetByteSize();269}270}271return false;272}273274void Section::Dump(llvm::raw_ostream &s, unsigned indent, Target *target,275uint32_t depth) const {276s.indent(indent);277s << llvm::format("0x%16.16" PRIx64 " %-22s ", GetID(), GetTypeAsCString());278bool resolved = true;279addr_t addr = LLDB_INVALID_ADDRESS;280281if (GetByteSize() == 0)282s.indent(39);283else {284if (target)285addr = GetLoadBaseAddress(target);286287if (addr == LLDB_INVALID_ADDRESS) {288if (target)289resolved = false;290addr = GetFileAddress();291}292293VMRange range(addr, addr + m_byte_size);294range.Dump(s, 0);295}296297s << llvm::format("%c %c%c%c 0x%8.8" PRIx64 " 0x%8.8" PRIx64 " 0x%8.8x ",298resolved ? ' ' : '*', m_readable ? 'r' : '-',299m_writable ? 'w' : '-', m_executable ? 'x' : '-',300m_file_offset, m_file_size, Get());301302DumpName(s);303304s << "\n";305306if (depth > 0)307m_children.Dump(s, indent, target, false, depth - 1);308}309310void Section::DumpName(llvm::raw_ostream &s) const {311SectionSP parent_sp(GetParent());312if (parent_sp) {313parent_sp->DumpName(s);314s << '.';315} else {316// The top most section prints the module basename317const char *name = nullptr;318ModuleSP module_sp(GetModule());319320if (m_obj_file) {321const FileSpec &file_spec = m_obj_file->GetFileSpec();322name = file_spec.GetFilename().AsCString();323}324if ((!name || !name[0]) && module_sp)325name = module_sp->GetFileSpec().GetFilename().AsCString();326if (name && name[0])327s << name << '.';328}329s << m_name;330}331332bool Section::IsDescendant(const Section *section) {333if (this == section)334return true;335SectionSP parent_sp(GetParent());336if (parent_sp)337return parent_sp->IsDescendant(section);338return false;339}340341bool Section::Slide(addr_t slide_amount, bool slide_children) {342if (m_file_addr != LLDB_INVALID_ADDRESS) {343if (slide_amount == 0)344return true;345346m_file_addr += slide_amount;347348if (slide_children)349m_children.Slide(slide_amount, slide_children);350351return true;352}353return false;354}355356/// Get the permissions as OR'ed bits from lldb::Permissions357uint32_t Section::GetPermissions() const {358uint32_t permissions = 0;359if (m_readable)360permissions |= ePermissionsReadable;361if (m_writable)362permissions |= ePermissionsWritable;363if (m_executable)364permissions |= ePermissionsExecutable;365return permissions;366}367368/// Set the permissions using bits OR'ed from lldb::Permissions369void Section::SetPermissions(uint32_t permissions) {370m_readable = (permissions & ePermissionsReadable) != 0;371m_writable = (permissions & ePermissionsWritable) != 0;372m_executable = (permissions & ePermissionsExecutable) != 0;373}374375lldb::offset_t Section::GetSectionData(void *dst, lldb::offset_t dst_len,376lldb::offset_t offset) {377if (m_obj_file)378return m_obj_file->ReadSectionData(this, offset, dst, dst_len);379return 0;380}381382lldb::offset_t Section::GetSectionData(DataExtractor §ion_data) {383if (m_obj_file)384return m_obj_file->ReadSectionData(this, section_data);385return 0;386}387388bool Section::ContainsOnlyDebugInfo() const {389switch (m_type) {390case eSectionTypeInvalid:391case eSectionTypeCode:392case eSectionTypeContainer:393case eSectionTypeData:394case eSectionTypeDataCString:395case eSectionTypeDataCStringPointers:396case eSectionTypeDataSymbolAddress:397case eSectionTypeData4:398case eSectionTypeData8:399case eSectionTypeData16:400case eSectionTypeDataPointers:401case eSectionTypeZeroFill:402case eSectionTypeDataObjCMessageRefs:403case eSectionTypeDataObjCCFStrings:404case eSectionTypeELFSymbolTable:405case eSectionTypeELFDynamicSymbols:406case eSectionTypeELFRelocationEntries:407case eSectionTypeELFDynamicLinkInfo:408case eSectionTypeEHFrame:409case eSectionTypeARMexidx:410case eSectionTypeARMextab:411case eSectionTypeCompactUnwind:412case eSectionTypeGoSymtab:413case eSectionTypeAbsoluteAddress:414case eSectionTypeOther:415// Used for "__dof_cache" in mach-o or ".debug" for COFF which isn't debug416// information that we parse at all. This was causing system files with no417// debug info to show debug info byte sizes in the "statistics dump" output418// for each module. New "eSectionType" enums should be created for dedicated419// debug info that has a predefined format if we wish for these sections to420// show up as debug info.421case eSectionTypeDebug:422return false;423424case eSectionTypeDWARFDebugAbbrev:425case eSectionTypeDWARFDebugAbbrevDwo:426case eSectionTypeDWARFDebugAddr:427case eSectionTypeDWARFDebugAranges:428case eSectionTypeDWARFDebugCuIndex:429case eSectionTypeDWARFDebugTuIndex:430case eSectionTypeDWARFDebugFrame:431case eSectionTypeDWARFDebugInfo:432case eSectionTypeDWARFDebugInfoDwo:433case eSectionTypeDWARFDebugLine:434case eSectionTypeDWARFDebugLineStr:435case eSectionTypeDWARFDebugLoc:436case eSectionTypeDWARFDebugLocDwo:437case eSectionTypeDWARFDebugLocLists:438case eSectionTypeDWARFDebugLocListsDwo:439case eSectionTypeDWARFDebugMacInfo:440case eSectionTypeDWARFDebugMacro:441case eSectionTypeDWARFDebugPubNames:442case eSectionTypeDWARFDebugPubTypes:443case eSectionTypeDWARFDebugRanges:444case eSectionTypeDWARFDebugRngLists:445case eSectionTypeDWARFDebugRngListsDwo:446case eSectionTypeDWARFDebugStr:447case eSectionTypeDWARFDebugStrDwo:448case eSectionTypeDWARFDebugStrOffsets:449case eSectionTypeDWARFDebugStrOffsetsDwo:450case eSectionTypeDWARFDebugTypes:451case eSectionTypeDWARFDebugTypesDwo:452case eSectionTypeDWARFDebugNames:453case eSectionTypeDWARFAppleNames:454case eSectionTypeDWARFAppleTypes:455case eSectionTypeDWARFAppleNamespaces:456case eSectionTypeDWARFAppleObjC:457case eSectionTypeDWARFGNUDebugAltLink:458case eSectionTypeCTF:459case eSectionTypeSwiftModules:460return true;461}462return false;463}464465466#pragma mark SectionList467468SectionList &SectionList::operator=(const SectionList &rhs) {469if (this != &rhs)470m_sections = rhs.m_sections;471return *this;472}473474size_t SectionList::AddSection(const lldb::SectionSP §ion_sp) {475if (section_sp) {476size_t section_index = m_sections.size();477m_sections.push_back(section_sp);478return section_index;479}480481return std::numeric_limits<size_t>::max();482}483484// Warning, this can be slow as it's removing items from a std::vector.485bool SectionList::DeleteSection(size_t idx) {486if (idx < m_sections.size()) {487m_sections.erase(m_sections.begin() + idx);488return true;489}490return false;491}492493size_t SectionList::FindSectionIndex(const Section *sect) {494iterator sect_iter;495iterator begin = m_sections.begin();496iterator end = m_sections.end();497for (sect_iter = begin; sect_iter != end; ++sect_iter) {498if (sect_iter->get() == sect) {499// The secton was already in this section list500return std::distance(begin, sect_iter);501}502}503return UINT32_MAX;504}505506size_t SectionList::AddUniqueSection(const lldb::SectionSP §_sp) {507size_t sect_idx = FindSectionIndex(sect_sp.get());508if (sect_idx == UINT32_MAX) {509sect_idx = AddSection(sect_sp);510}511return sect_idx;512}513514bool SectionList::ReplaceSection(user_id_t sect_id,515const lldb::SectionSP §_sp,516uint32_t depth) {517iterator sect_iter, end = m_sections.end();518for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) {519if ((*sect_iter)->GetID() == sect_id) {520*sect_iter = sect_sp;521return true;522} else if (depth > 0) {523if ((*sect_iter)524->GetChildren()525.ReplaceSection(sect_id, sect_sp, depth - 1))526return true;527}528}529return false;530}531532size_t SectionList::GetNumSections(uint32_t depth) const {533size_t count = m_sections.size();534if (depth > 0) {535const_iterator sect_iter, end = m_sections.end();536for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) {537count += (*sect_iter)->GetChildren().GetNumSections(depth - 1);538}539}540return count;541}542543SectionSP SectionList::GetSectionAtIndex(size_t idx) const {544SectionSP sect_sp;545if (idx < m_sections.size())546sect_sp = m_sections[idx];547return sect_sp;548}549550SectionSP551SectionList::FindSectionByName(ConstString section_dstr) const {552SectionSP sect_sp;553// Check if we have a valid section string554if (section_dstr && !m_sections.empty()) {555const_iterator sect_iter;556const_iterator end = m_sections.end();557for (sect_iter = m_sections.begin();558sect_iter != end && sect_sp.get() == nullptr; ++sect_iter) {559Section *child_section = sect_iter->get();560if (child_section) {561if (child_section->GetName() == section_dstr) {562sect_sp = *sect_iter;563} else {564sect_sp =565child_section->GetChildren().FindSectionByName(section_dstr);566}567}568}569}570return sect_sp;571}572573SectionSP SectionList::FindSectionByID(user_id_t sect_id) const {574SectionSP sect_sp;575if (sect_id) {576const_iterator sect_iter;577const_iterator end = m_sections.end();578for (sect_iter = m_sections.begin();579sect_iter != end && sect_sp.get() == nullptr; ++sect_iter) {580if ((*sect_iter)->GetID() == sect_id) {581sect_sp = *sect_iter;582break;583} else {584sect_sp = (*sect_iter)->GetChildren().FindSectionByID(sect_id);585}586}587}588return sect_sp;589}590591SectionSP SectionList::FindSectionByType(SectionType sect_type,592bool check_children,593size_t start_idx) const {594SectionSP sect_sp;595size_t num_sections = m_sections.size();596for (size_t idx = start_idx; idx < num_sections; ++idx) {597if (m_sections[idx]->GetType() == sect_type) {598sect_sp = m_sections[idx];599break;600} else if (check_children) {601sect_sp = m_sections[idx]->GetChildren().FindSectionByType(602sect_type, check_children, 0);603if (sect_sp)604break;605}606}607return sect_sp;608}609610SectionSP SectionList::FindSectionContainingFileAddress(addr_t vm_addr,611uint32_t depth) const {612SectionSP sect_sp;613const_iterator sect_iter;614const_iterator end = m_sections.end();615for (sect_iter = m_sections.begin();616sect_iter != end && sect_sp.get() == nullptr; ++sect_iter) {617Section *sect = sect_iter->get();618if (sect->ContainsFileAddress(vm_addr)) {619// The file address is in this section. We need to make sure one of our620// child sections doesn't contain this address as well as obeying the621// depth limit that was passed in.622if (depth > 0)623sect_sp = sect->GetChildren().FindSectionContainingFileAddress(624vm_addr, depth - 1);625626if (sect_sp.get() == nullptr && !sect->IsFake())627sect_sp = *sect_iter;628}629}630return sect_sp;631}632633bool SectionList::ContainsSection(user_id_t sect_id) const {634return FindSectionByID(sect_id).get() != nullptr;635}636637void SectionList::Dump(llvm::raw_ostream &s, unsigned indent, Target *target,638bool show_header, uint32_t depth) const {639bool target_has_loaded_sections =640target && !target->GetSectionLoadList().IsEmpty();641if (show_header && !m_sections.empty()) {642s.indent(indent);643s << llvm::formatv(644"SectID Type {0} Address "645" Perm File Off. File Size Flags Section Name\n",646target_has_loaded_sections ? "Load" : "File");647s.indent(indent);648s << "------------------ ---------------------- "649"--------------------------------------- ---- ---------- ---------- "650"---------- ----------------------------\n";651}652653for (const auto §ion_sp : m_sections)654section_sp->Dump(s, indent, target_has_loaded_sections ? target : nullptr,655depth);656}657658size_t SectionList::Slide(addr_t slide_amount, bool slide_children) {659size_t count = 0;660const_iterator pos, end = m_sections.end();661for (pos = m_sections.begin(); pos != end; ++pos) {662if ((*pos)->Slide(slide_amount, slide_children))663++count;664}665return count;666}667668uint64_t SectionList::GetDebugInfoSize() const {669uint64_t debug_info_size = 0;670for (const auto §ion : m_sections) {671const SectionList &sub_sections = section->GetChildren();672if (sub_sections.GetSize() > 0)673debug_info_size += sub_sections.GetDebugInfoSize();674else if (section->ContainsOnlyDebugInfo())675debug_info_size += section->GetFileSize();676}677return debug_info_size;678}679680namespace llvm {681namespace json {682683bool fromJSON(const llvm::json::Value &value,684lldb_private::JSONSection §ion, llvm::json::Path path) {685llvm::json::ObjectMapper o(value, path);686return o && o.map("name", section.name) && o.map("type", section.type) &&687o.map("size", section.address) && o.map("size", section.size);688}689690bool fromJSON(const llvm::json::Value &value, lldb::SectionType &type,691llvm::json::Path path) {692if (auto str = value.getAsString()) {693type = llvm::StringSwitch<lldb::SectionType>(*str)694.Case("code", eSectionTypeCode)695.Case("container", eSectionTypeContainer)696.Case("data", eSectionTypeData)697.Case("debug", eSectionTypeDebug)698.Default(eSectionTypeInvalid);699700if (type == eSectionTypeInvalid) {701path.report("invalid section type");702return false;703}704705return true;706}707path.report("expected string");708return false;709}710} // namespace json711} // namespace llvm712713714