1 //===-- Section.cpp ---------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Core/Section.h" 10 #include "lldb/Core/Address.h" 11 #include "lldb/Core/Module.h" 12 #include "lldb/Symbol/ObjectFile.h" 13 #include "lldb/Target/SectionLoadList.h" 14 #include "lldb/Target/Target.h" 15 #include "lldb/Utility/FileSpec.h" 16 #include "lldb/Utility/Stream.h" 17 #include "lldb/Utility/VMRange.h" 18 19 #include <inttypes.h> 20 #include <limits> 21 #include <utility> 22 23 namespace lldb_private { 24 class DataExtractor; 25 } 26 using namespace lldb; 27 using namespace lldb_private; 28 29 const char *Section::GetTypeAsCString() const { 30 switch (m_type) { 31 case eSectionTypeInvalid: 32 return "invalid"; 33 case eSectionTypeCode: 34 return "code"; 35 case eSectionTypeContainer: 36 return "container"; 37 case eSectionTypeData: 38 return "data"; 39 case eSectionTypeDataCString: 40 return "data-cstr"; 41 case eSectionTypeDataCStringPointers: 42 return "data-cstr-ptr"; 43 case eSectionTypeDataSymbolAddress: 44 return "data-symbol-addr"; 45 case eSectionTypeData4: 46 return "data-4-byte"; 47 case eSectionTypeData8: 48 return "data-8-byte"; 49 case eSectionTypeData16: 50 return "data-16-byte"; 51 case eSectionTypeDataPointers: 52 return "data-ptrs"; 53 case eSectionTypeDebug: 54 return "debug"; 55 case eSectionTypeZeroFill: 56 return "zero-fill"; 57 case eSectionTypeDataObjCMessageRefs: 58 return "objc-message-refs"; 59 case eSectionTypeDataObjCCFStrings: 60 return "objc-cfstrings"; 61 case eSectionTypeDWARFDebugAbbrev: 62 return "dwarf-abbrev"; 63 case eSectionTypeDWARFDebugAbbrevDwo: 64 return "dwarf-abbrev-dwo"; 65 case eSectionTypeDWARFDebugAddr: 66 return "dwarf-addr"; 67 case eSectionTypeDWARFDebugAranges: 68 return "dwarf-aranges"; 69 case eSectionTypeDWARFDebugCuIndex: 70 return "dwarf-cu-index"; 71 case eSectionTypeDWARFDebugFrame: 72 return "dwarf-frame"; 73 case eSectionTypeDWARFDebugInfo: 74 return "dwarf-info"; 75 case eSectionTypeDWARFDebugInfoDwo: 76 return "dwarf-info-dwo"; 77 case eSectionTypeDWARFDebugLine: 78 return "dwarf-line"; 79 case eSectionTypeDWARFDebugLineStr: 80 return "dwarf-line-str"; 81 case eSectionTypeDWARFDebugLoc: 82 return "dwarf-loc"; 83 case eSectionTypeDWARFDebugLocLists: 84 return "dwarf-loclists"; 85 case eSectionTypeDWARFDebugMacInfo: 86 return "dwarf-macinfo"; 87 case eSectionTypeDWARFDebugMacro: 88 return "dwarf-macro"; 89 case eSectionTypeDWARFDebugPubNames: 90 return "dwarf-pubnames"; 91 case eSectionTypeDWARFDebugPubTypes: 92 return "dwarf-pubtypes"; 93 case eSectionTypeDWARFDebugRanges: 94 return "dwarf-ranges"; 95 case eSectionTypeDWARFDebugRngLists: 96 return "dwarf-rnglists"; 97 case eSectionTypeDWARFDebugRngListsDwo: 98 return "dwarf-rnglists-dwo"; 99 case eSectionTypeDWARFDebugStr: 100 return "dwarf-str"; 101 case eSectionTypeDWARFDebugStrDwo: 102 return "dwarf-str-dwo"; 103 case eSectionTypeDWARFDebugStrOffsets: 104 return "dwarf-str-offsets"; 105 case eSectionTypeDWARFDebugStrOffsetsDwo: 106 return "dwarf-str-offsets-dwo"; 107 case eSectionTypeDWARFDebugTypes: 108 return "dwarf-types"; 109 case eSectionTypeDWARFDebugTypesDwo: 110 return "dwarf-types-dwo"; 111 case eSectionTypeDWARFDebugNames: 112 return "dwarf-names"; 113 case eSectionTypeELFSymbolTable: 114 return "elf-symbol-table"; 115 case eSectionTypeELFDynamicSymbols: 116 return "elf-dynamic-symbols"; 117 case eSectionTypeELFRelocationEntries: 118 return "elf-relocation-entries"; 119 case eSectionTypeELFDynamicLinkInfo: 120 return "elf-dynamic-link-info"; 121 case eSectionTypeDWARFAppleNames: 122 return "apple-names"; 123 case eSectionTypeDWARFAppleTypes: 124 return "apple-types"; 125 case eSectionTypeDWARFAppleNamespaces: 126 return "apple-namespaces"; 127 case eSectionTypeDWARFAppleObjC: 128 return "apple-objc"; 129 case eSectionTypeEHFrame: 130 return "eh-frame"; 131 case eSectionTypeARMexidx: 132 return "ARM.exidx"; 133 case eSectionTypeARMextab: 134 return "ARM.extab"; 135 case eSectionTypeCompactUnwind: 136 return "compact-unwind"; 137 case eSectionTypeGoSymtab: 138 return "go-symtab"; 139 case eSectionTypeAbsoluteAddress: 140 return "absolute"; 141 case eSectionTypeDWARFGNUDebugAltLink: 142 return "dwarf-gnu-debugaltlink"; 143 case eSectionTypeOther: 144 return "regular"; 145 } 146 return "unknown"; 147 } 148 149 Section::Section(const ModuleSP &module_sp, ObjectFile *obj_file, 150 user_id_t sect_id, ConstString name, 151 SectionType sect_type, addr_t file_addr, addr_t byte_size, 152 lldb::offset_t file_offset, lldb::offset_t file_size, 153 uint32_t log2align, uint32_t flags, 154 uint32_t target_byte_size /*=1*/) 155 : ModuleChild(module_sp), UserID(sect_id), Flags(flags), 156 m_obj_file(obj_file), m_type(sect_type), m_parent_wp(), m_name(name), 157 m_file_addr(file_addr), m_byte_size(byte_size), 158 m_file_offset(file_offset), m_file_size(file_size), 159 m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false), 160 m_thread_specific(false), m_readable(false), m_writable(false), 161 m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) { 162 // printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", 163 // addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " 164 // - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s\n", 165 // this, module_sp.get(), sect_id, file_addr, file_addr + 166 // byte_size, file_offset, file_offset + file_size, flags, 167 // name.GetCString()); 168 } 169 170 Section::Section(const lldb::SectionSP &parent_section_sp, 171 const ModuleSP &module_sp, ObjectFile *obj_file, 172 user_id_t sect_id, ConstString name, 173 SectionType sect_type, addr_t file_addr, addr_t byte_size, 174 lldb::offset_t file_offset, lldb::offset_t file_size, 175 uint32_t log2align, uint32_t flags, 176 uint32_t target_byte_size /*=1*/) 177 : ModuleChild(module_sp), UserID(sect_id), Flags(flags), 178 m_obj_file(obj_file), m_type(sect_type), m_parent_wp(), m_name(name), 179 m_file_addr(file_addr), m_byte_size(byte_size), 180 m_file_offset(file_offset), m_file_size(file_size), 181 m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false), 182 m_thread_specific(false), m_readable(false), m_writable(false), 183 m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) { 184 // printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ", 185 // addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 " 186 // - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s.%s\n", 187 // this, module_sp.get(), sect_id, file_addr, file_addr + 188 // byte_size, file_offset, file_offset + file_size, flags, 189 // parent_section_sp->GetName().GetCString(), name.GetCString()); 190 if (parent_section_sp) 191 m_parent_wp = parent_section_sp; 192 } 193 194 Section::~Section() { 195 // printf ("Section::~Section(%p)\n", this); 196 } 197 198 addr_t Section::GetFileAddress() const { 199 SectionSP parent_sp(GetParent()); 200 if (parent_sp) { 201 // This section has a parent which means m_file_addr is an offset into the 202 // parent section, so the file address for this section is the file address 203 // of the parent plus the offset 204 return parent_sp->GetFileAddress() + m_file_addr; 205 } 206 // This section has no parent, so m_file_addr is the file base address 207 return m_file_addr; 208 } 209 210 bool Section::SetFileAddress(lldb::addr_t file_addr) { 211 SectionSP parent_sp(GetParent()); 212 if (parent_sp) { 213 if (m_file_addr >= file_addr) 214 return parent_sp->SetFileAddress(m_file_addr - file_addr); 215 return false; 216 } else { 217 // This section has no parent, so m_file_addr is the file base address 218 m_file_addr = file_addr; 219 return true; 220 } 221 } 222 223 lldb::addr_t Section::GetOffset() const { 224 // This section has a parent which means m_file_addr is an offset. 225 SectionSP parent_sp(GetParent()); 226 if (parent_sp) 227 return m_file_addr; 228 229 // This section has no parent, so there is no offset to be had 230 return 0; 231 } 232 233 addr_t Section::GetLoadBaseAddress(Target *target) const { 234 addr_t load_base_addr = LLDB_INVALID_ADDRESS; 235 SectionSP parent_sp(GetParent()); 236 if (parent_sp) { 237 load_base_addr = parent_sp->GetLoadBaseAddress(target); 238 if (load_base_addr != LLDB_INVALID_ADDRESS) 239 load_base_addr += GetOffset(); 240 } 241 if (load_base_addr == LLDB_INVALID_ADDRESS) { 242 load_base_addr = target->GetSectionLoadList().GetSectionLoadAddress( 243 const_cast<Section *>(this)->shared_from_this()); 244 } 245 return load_base_addr; 246 } 247 248 bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr, 249 bool allow_section_end) const { 250 const size_t num_children = m_children.GetSize(); 251 for (size_t i = 0; i < num_children; i++) { 252 Section *child_section = m_children.GetSectionAtIndex(i).get(); 253 254 addr_t child_offset = child_section->GetOffset(); 255 if (child_offset <= offset && 256 offset - child_offset < 257 child_section->GetByteSize() + (allow_section_end ? 1 : 0)) 258 return child_section->ResolveContainedAddress(offset - child_offset, 259 so_addr, allow_section_end); 260 } 261 so_addr.SetOffset(offset); 262 so_addr.SetSection(const_cast<Section *>(this)->shared_from_this()); 263 264 #ifdef LLDB_CONFIGURATION_DEBUG 265 // For debug builds, ensure that there are no orphaned (i.e., moduleless) 266 // sections. 267 assert(GetModule().get()); 268 #endif 269 return true; 270 } 271 272 bool Section::ContainsFileAddress(addr_t vm_addr) const { 273 const addr_t file_addr = GetFileAddress(); 274 if (file_addr != LLDB_INVALID_ADDRESS && !IsThreadSpecific()) { 275 if (file_addr <= vm_addr) { 276 const addr_t offset = (vm_addr - file_addr) * m_target_byte_size; 277 return offset < GetByteSize(); 278 } 279 } 280 return false; 281 } 282 283 void Section::Dump(Stream *s, Target *target, uint32_t depth) const { 284 // s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); 285 s->Indent(); 286 s->Printf("0x%8.8" PRIx64 " %-16s ", GetID(), GetTypeAsCString()); 287 bool resolved = true; 288 addr_t addr = LLDB_INVALID_ADDRESS; 289 290 if (GetByteSize() == 0) 291 s->Printf("%39s", ""); 292 else { 293 if (target) 294 addr = GetLoadBaseAddress(target); 295 296 if (addr == LLDB_INVALID_ADDRESS) { 297 if (target) 298 resolved = false; 299 addr = GetFileAddress(); 300 } 301 302 VMRange range(addr, addr + m_byte_size); 303 range.Dump(s->AsRawOstream(), 0); 304 } 305 306 s->Printf("%c %c%c%c 0x%8.8" PRIx64 " 0x%8.8" PRIx64 " 0x%8.8x ", 307 resolved ? ' ' : '*', m_readable ? 'r' : '-', 308 m_writable ? 'w' : '-', m_executable ? 'x' : '-', m_file_offset, 309 m_file_size, Get()); 310 311 DumpName(s); 312 313 s->EOL(); 314 315 if (depth > 0) 316 m_children.Dump(s, target, false, depth - 1); 317 } 318 319 void Section::DumpName(Stream *s) const { 320 SectionSP parent_sp(GetParent()); 321 if (parent_sp) { 322 parent_sp->DumpName(s); 323 s->PutChar('.'); 324 } else { 325 // The top most section prints the module basename 326 const char *name = nullptr; 327 ModuleSP module_sp(GetModule()); 328 329 if (m_obj_file) { 330 const FileSpec &file_spec = m_obj_file->GetFileSpec(); 331 name = file_spec.GetFilename().AsCString(); 332 } 333 if ((!name || !name[0]) && module_sp) 334 name = module_sp->GetFileSpec().GetFilename().AsCString(); 335 if (name && name[0]) 336 s->Printf("%s.", name); 337 } 338 m_name.Dump(s); 339 } 340 341 bool Section::IsDescendant(const Section *section) { 342 if (this == section) 343 return true; 344 SectionSP parent_sp(GetParent()); 345 if (parent_sp) 346 return parent_sp->IsDescendant(section); 347 return false; 348 } 349 350 bool Section::Slide(addr_t slide_amount, bool slide_children) { 351 if (m_file_addr != LLDB_INVALID_ADDRESS) { 352 if (slide_amount == 0) 353 return true; 354 355 m_file_addr += slide_amount; 356 357 if (slide_children) 358 m_children.Slide(slide_amount, slide_children); 359 360 return true; 361 } 362 return false; 363 } 364 365 /// Get the permissions as OR'ed bits from lldb::Permissions 366 uint32_t Section::GetPermissions() const { 367 uint32_t permissions = 0; 368 if (m_readable) 369 permissions |= ePermissionsReadable; 370 if (m_writable) 371 permissions |= ePermissionsWritable; 372 if (m_executable) 373 permissions |= ePermissionsExecutable; 374 return permissions; 375 } 376 377 /// Set the permissions using bits OR'ed from lldb::Permissions 378 void Section::SetPermissions(uint32_t permissions) { 379 m_readable = (permissions & ePermissionsReadable) != 0; 380 m_writable = (permissions & ePermissionsWritable) != 0; 381 m_executable = (permissions & ePermissionsExecutable) != 0; 382 } 383 384 lldb::offset_t Section::GetSectionData(void *dst, lldb::offset_t dst_len, 385 lldb::offset_t offset) { 386 if (m_obj_file) 387 return m_obj_file->ReadSectionData(this, offset, dst, dst_len); 388 return 0; 389 } 390 391 lldb::offset_t Section::GetSectionData(DataExtractor §ion_data) { 392 if (m_obj_file) 393 return m_obj_file->ReadSectionData(this, section_data); 394 return 0; 395 } 396 397 #pragma mark SectionList 398 399 SectionList &SectionList::operator=(const SectionList &rhs) { 400 if (this != &rhs) 401 m_sections = rhs.m_sections; 402 return *this; 403 } 404 405 size_t SectionList::AddSection(const lldb::SectionSP §ion_sp) { 406 if (section_sp) { 407 size_t section_index = m_sections.size(); 408 m_sections.push_back(section_sp); 409 return section_index; 410 } 411 412 return std::numeric_limits<size_t>::max(); 413 } 414 415 // Warning, this can be slow as it's removing items from a std::vector. 416 bool SectionList::DeleteSection(size_t idx) { 417 if (idx < m_sections.size()) { 418 m_sections.erase(m_sections.begin() + idx); 419 return true; 420 } 421 return false; 422 } 423 424 size_t SectionList::FindSectionIndex(const Section *sect) { 425 iterator sect_iter; 426 iterator begin = m_sections.begin(); 427 iterator end = m_sections.end(); 428 for (sect_iter = begin; sect_iter != end; ++sect_iter) { 429 if (sect_iter->get() == sect) { 430 // The secton was already in this section list 431 return std::distance(begin, sect_iter); 432 } 433 } 434 return UINT32_MAX; 435 } 436 437 size_t SectionList::AddUniqueSection(const lldb::SectionSP §_sp) { 438 size_t sect_idx = FindSectionIndex(sect_sp.get()); 439 if (sect_idx == UINT32_MAX) { 440 sect_idx = AddSection(sect_sp); 441 } 442 return sect_idx; 443 } 444 445 bool SectionList::ReplaceSection(user_id_t sect_id, 446 const lldb::SectionSP §_sp, 447 uint32_t depth) { 448 iterator sect_iter, end = m_sections.end(); 449 for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) { 450 if ((*sect_iter)->GetID() == sect_id) { 451 *sect_iter = sect_sp; 452 return true; 453 } else if (depth > 0) { 454 if ((*sect_iter) 455 ->GetChildren() 456 .ReplaceSection(sect_id, sect_sp, depth - 1)) 457 return true; 458 } 459 } 460 return false; 461 } 462 463 size_t SectionList::GetNumSections(uint32_t depth) const { 464 size_t count = m_sections.size(); 465 if (depth > 0) { 466 const_iterator sect_iter, end = m_sections.end(); 467 for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) { 468 count += (*sect_iter)->GetChildren().GetNumSections(depth - 1); 469 } 470 } 471 return count; 472 } 473 474 SectionSP SectionList::GetSectionAtIndex(size_t idx) const { 475 SectionSP sect_sp; 476 if (idx < m_sections.size()) 477 sect_sp = m_sections[idx]; 478 return sect_sp; 479 } 480 481 SectionSP 482 SectionList::FindSectionByName(ConstString section_dstr) const { 483 SectionSP sect_sp; 484 // Check if we have a valid section string 485 if (section_dstr && !m_sections.empty()) { 486 const_iterator sect_iter; 487 const_iterator end = m_sections.end(); 488 for (sect_iter = m_sections.begin(); 489 sect_iter != end && sect_sp.get() == nullptr; ++sect_iter) { 490 Section *child_section = sect_iter->get(); 491 if (child_section) { 492 if (child_section->GetName() == section_dstr) { 493 sect_sp = *sect_iter; 494 } else { 495 sect_sp = 496 child_section->GetChildren().FindSectionByName(section_dstr); 497 } 498 } 499 } 500 } 501 return sect_sp; 502 } 503 504 SectionSP SectionList::FindSectionByID(user_id_t sect_id) const { 505 SectionSP sect_sp; 506 if (sect_id) { 507 const_iterator sect_iter; 508 const_iterator end = m_sections.end(); 509 for (sect_iter = m_sections.begin(); 510 sect_iter != end && sect_sp.get() == nullptr; ++sect_iter) { 511 if ((*sect_iter)->GetID() == sect_id) { 512 sect_sp = *sect_iter; 513 break; 514 } else { 515 sect_sp = (*sect_iter)->GetChildren().FindSectionByID(sect_id); 516 } 517 } 518 } 519 return sect_sp; 520 } 521 522 SectionSP SectionList::FindSectionByType(SectionType sect_type, 523 bool check_children, 524 size_t start_idx) const { 525 SectionSP sect_sp; 526 size_t num_sections = m_sections.size(); 527 for (size_t idx = start_idx; idx < num_sections; ++idx) { 528 if (m_sections[idx]->GetType() == sect_type) { 529 sect_sp = m_sections[idx]; 530 break; 531 } else if (check_children) { 532 sect_sp = m_sections[idx]->GetChildren().FindSectionByType( 533 sect_type, check_children, 0); 534 if (sect_sp) 535 break; 536 } 537 } 538 return sect_sp; 539 } 540 541 SectionSP SectionList::FindSectionContainingFileAddress(addr_t vm_addr, 542 uint32_t depth) const { 543 SectionSP sect_sp; 544 const_iterator sect_iter; 545 const_iterator end = m_sections.end(); 546 for (sect_iter = m_sections.begin(); 547 sect_iter != end && sect_sp.get() == nullptr; ++sect_iter) { 548 Section *sect = sect_iter->get(); 549 if (sect->ContainsFileAddress(vm_addr)) { 550 // The file address is in this section. We need to make sure one of our 551 // child sections doesn't contain this address as well as obeying the 552 // depth limit that was passed in. 553 if (depth > 0) 554 sect_sp = sect->GetChildren().FindSectionContainingFileAddress( 555 vm_addr, depth - 1); 556 557 if (sect_sp.get() == nullptr && !sect->IsFake()) 558 sect_sp = *sect_iter; 559 } 560 } 561 return sect_sp; 562 } 563 564 bool SectionList::ContainsSection(user_id_t sect_id) const { 565 return FindSectionByID(sect_id).get() != nullptr; 566 } 567 568 void SectionList::Dump(Stream *s, Target *target, bool show_header, 569 uint32_t depth) const { 570 bool target_has_loaded_sections = 571 target && !target->GetSectionLoadList().IsEmpty(); 572 if (show_header && !m_sections.empty()) { 573 s->Indent(); 574 s->Printf("SectID Type %s Address " 575 " Perm File Off. File Size Flags " 576 " Section Name\n", 577 target_has_loaded_sections ? "Load" : "File"); 578 s->Indent(); 579 s->PutCString("---------- ---------------- " 580 "--------------------------------------- ---- ---------- " 581 "---------- " 582 "---------- ----------------------------\n"); 583 } 584 585 const_iterator sect_iter; 586 const_iterator end = m_sections.end(); 587 for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) { 588 (*sect_iter)->Dump(s, target_has_loaded_sections ? target : nullptr, depth); 589 } 590 591 if (show_header && !m_sections.empty()) 592 s->IndentLess(); 593 } 594 595 size_t SectionList::Slide(addr_t slide_amount, bool slide_children) { 596 size_t count = 0; 597 const_iterator pos, end = m_sections.end(); 598 for (pos = m_sections.begin(); pos != end; ++pos) { 599 if ((*pos)->Slide(slide_amount, slide_children)) 600 ++count; 601 } 602 return count; 603 } 604