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 eSectionTypeDWARFDebugStr:
98     return "dwarf-str";
99   case eSectionTypeDWARFDebugStrDwo:
100     return "dwarf-str-dwo";
101   case eSectionTypeDWARFDebugStrOffsets:
102     return "dwarf-str-offsets";
103   case eSectionTypeDWARFDebugStrOffsetsDwo:
104     return "dwarf-str-offsets-dwo";
105   case eSectionTypeDWARFDebugTypes:
106     return "dwarf-types";
107   case eSectionTypeDWARFDebugNames:
108     return "dwarf-names";
109   case eSectionTypeELFSymbolTable:
110     return "elf-symbol-table";
111   case eSectionTypeELFDynamicSymbols:
112     return "elf-dynamic-symbols";
113   case eSectionTypeELFRelocationEntries:
114     return "elf-relocation-entries";
115   case eSectionTypeELFDynamicLinkInfo:
116     return "elf-dynamic-link-info";
117   case eSectionTypeDWARFAppleNames:
118     return "apple-names";
119   case eSectionTypeDWARFAppleTypes:
120     return "apple-types";
121   case eSectionTypeDWARFAppleNamespaces:
122     return "apple-namespaces";
123   case eSectionTypeDWARFAppleObjC:
124     return "apple-objc";
125   case eSectionTypeEHFrame:
126     return "eh-frame";
127   case eSectionTypeARMexidx:
128     return "ARM.exidx";
129   case eSectionTypeARMextab:
130     return "ARM.extab";
131   case eSectionTypeCompactUnwind:
132     return "compact-unwind";
133   case eSectionTypeGoSymtab:
134     return "go-symtab";
135   case eSectionTypeAbsoluteAddress:
136     return "absolute";
137   case eSectionTypeDWARFGNUDebugAltLink:
138     return "dwarf-gnu-debugaltlink";
139   case eSectionTypeOther:
140     return "regular";
141   }
142   return "unknown";
143 }
144 
145 Section::Section(const ModuleSP &module_sp, ObjectFile *obj_file,
146                  user_id_t sect_id, ConstString name,
147                  SectionType sect_type, addr_t file_addr, addr_t byte_size,
148                  lldb::offset_t file_offset, lldb::offset_t file_size,
149                  uint32_t log2align, uint32_t flags,
150                  uint32_t target_byte_size /*=1*/)
151     : ModuleChild(module_sp), UserID(sect_id), Flags(flags),
152       m_obj_file(obj_file), m_type(sect_type), m_parent_wp(), m_name(name),
153       m_file_addr(file_addr), m_byte_size(byte_size),
154       m_file_offset(file_offset), m_file_size(file_size),
155       m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false),
156       m_thread_specific(false), m_readable(false), m_writable(false),
157       m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) {
158   //    printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ",
159   //    addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 "
160   //    - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s\n",
161   //            this, module_sp.get(), sect_id, file_addr, file_addr +
162   //            byte_size, file_offset, file_offset + file_size, flags,
163   //            name.GetCString());
164 }
165 
166 Section::Section(const lldb::SectionSP &parent_section_sp,
167                  const ModuleSP &module_sp, ObjectFile *obj_file,
168                  user_id_t sect_id, ConstString name,
169                  SectionType sect_type, addr_t file_addr, addr_t byte_size,
170                  lldb::offset_t file_offset, lldb::offset_t file_size,
171                  uint32_t log2align, uint32_t flags,
172                  uint32_t target_byte_size /*=1*/)
173     : ModuleChild(module_sp), UserID(sect_id), Flags(flags),
174       m_obj_file(obj_file), m_type(sect_type), m_parent_wp(), m_name(name),
175       m_file_addr(file_addr), m_byte_size(byte_size),
176       m_file_offset(file_offset), m_file_size(file_size),
177       m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false),
178       m_thread_specific(false), m_readable(false), m_writable(false),
179       m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) {
180   //    printf ("Section::Section(%p): module=%p, sect_id = 0x%16.16" PRIx64 ",
181   //    addr=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), file [0x%16.16" PRIx64 "
182   //    - 0x%16.16" PRIx64 "), flags = 0x%8.8x, name = %s.%s\n",
183   //            this, module_sp.get(), sect_id, file_addr, file_addr +
184   //            byte_size, file_offset, file_offset + file_size, flags,
185   //            parent_section_sp->GetName().GetCString(), name.GetCString());
186   if (parent_section_sp)
187     m_parent_wp = parent_section_sp;
188 }
189 
190 Section::~Section() {
191   //    printf ("Section::~Section(%p)\n", this);
192 }
193 
194 addr_t Section::GetFileAddress() const {
195   SectionSP parent_sp(GetParent());
196   if (parent_sp) {
197     // This section has a parent which means m_file_addr is an offset into the
198     // parent section, so the file address for this section is the file address
199     // of the parent plus the offset
200     return parent_sp->GetFileAddress() + m_file_addr;
201   }
202   // This section has no parent, so m_file_addr is the file base address
203   return m_file_addr;
204 }
205 
206 bool Section::SetFileAddress(lldb::addr_t file_addr) {
207   SectionSP parent_sp(GetParent());
208   if (parent_sp) {
209     if (m_file_addr >= file_addr)
210       return parent_sp->SetFileAddress(m_file_addr - file_addr);
211     return false;
212   } else {
213     // This section has no parent, so m_file_addr is the file base address
214     m_file_addr = file_addr;
215     return true;
216   }
217 }
218 
219 lldb::addr_t Section::GetOffset() const {
220   // This section has a parent which means m_file_addr is an offset.
221   SectionSP parent_sp(GetParent());
222   if (parent_sp)
223     return m_file_addr;
224 
225   // This section has no parent, so there is no offset to be had
226   return 0;
227 }
228 
229 addr_t Section::GetLoadBaseAddress(Target *target) const {
230   addr_t load_base_addr = LLDB_INVALID_ADDRESS;
231   SectionSP parent_sp(GetParent());
232   if (parent_sp) {
233     load_base_addr = parent_sp->GetLoadBaseAddress(target);
234     if (load_base_addr != LLDB_INVALID_ADDRESS)
235       load_base_addr += GetOffset();
236   }
237   if (load_base_addr == LLDB_INVALID_ADDRESS) {
238     load_base_addr = target->GetSectionLoadList().GetSectionLoadAddress(
239         const_cast<Section *>(this)->shared_from_this());
240   }
241   return load_base_addr;
242 }
243 
244 bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr,
245                                       bool allow_section_end) const {
246   const size_t num_children = m_children.GetSize();
247   for (size_t i = 0; i < num_children; i++) {
248     Section *child_section = m_children.GetSectionAtIndex(i).get();
249 
250     addr_t child_offset = child_section->GetOffset();
251     if (child_offset <= offset &&
252         offset - child_offset <
253             child_section->GetByteSize() + (allow_section_end ? 1 : 0))
254       return child_section->ResolveContainedAddress(offset - child_offset,
255                                                     so_addr, allow_section_end);
256   }
257   so_addr.SetOffset(offset);
258   so_addr.SetSection(const_cast<Section *>(this)->shared_from_this());
259 
260 #ifdef LLDB_CONFIGURATION_DEBUG
261   // For debug builds, ensure that there are no orphaned (i.e., moduleless)
262   // sections.
263   assert(GetModule().get());
264 #endif
265   return true;
266 }
267 
268 bool Section::ContainsFileAddress(addr_t vm_addr) const {
269   const addr_t file_addr = GetFileAddress();
270   if (file_addr != LLDB_INVALID_ADDRESS) {
271     if (file_addr <= vm_addr) {
272       const addr_t offset = (vm_addr - file_addr) * m_target_byte_size;
273       return offset < GetByteSize();
274     }
275   }
276   return false;
277 }
278 
279 int Section::Compare(const Section &a, const Section &b) {
280   if (&a == &b)
281     return 0;
282 
283   const ModuleSP a_module_sp = a.GetModule();
284   const ModuleSP b_module_sp = b.GetModule();
285   if (a_module_sp == b_module_sp) {
286     user_id_t a_sect_uid = a.GetID();
287     user_id_t b_sect_uid = b.GetID();
288     if (a_sect_uid < b_sect_uid)
289       return -1;
290     if (a_sect_uid > b_sect_uid)
291       return 1;
292     return 0;
293   } else {
294     // The modules are different, just compare the module pointers
295     if (a_module_sp.get() < b_module_sp.get())
296       return -1;
297     else
298       return 1; // We already know the modules aren't equal
299   }
300 }
301 
302 void Section::Dump(Stream *s, Target *target, uint32_t depth) const {
303   //    s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
304   s->Indent();
305   s->Printf("0x%8.8" PRIx64 " %-16s ", GetID(), GetTypeAsCString());
306   bool resolved = true;
307   addr_t addr = LLDB_INVALID_ADDRESS;
308 
309   if (GetByteSize() == 0)
310     s->Printf("%39s", "");
311   else {
312     if (target)
313       addr = GetLoadBaseAddress(target);
314 
315     if (addr == LLDB_INVALID_ADDRESS) {
316       if (target)
317         resolved = false;
318       addr = GetFileAddress();
319     }
320 
321     VMRange range(addr, addr + m_byte_size);
322     range.Dump(s, 0);
323   }
324 
325   s->Printf("%c %c%c%c  0x%8.8" PRIx64 " 0x%8.8" PRIx64 " 0x%8.8x ",
326             resolved ? ' ' : '*', m_readable ? 'r' : '-',
327             m_writable ? 'w' : '-', m_executable ? 'x' : '-', m_file_offset,
328             m_file_size, Get());
329 
330   DumpName(s);
331 
332   s->EOL();
333 
334   if (depth > 0)
335     m_children.Dump(s, target, false, depth - 1);
336 }
337 
338 void Section::DumpName(Stream *s) const {
339   SectionSP parent_sp(GetParent());
340   if (parent_sp) {
341     parent_sp->DumpName(s);
342     s->PutChar('.');
343   } else {
344     // The top most section prints the module basename
345     const char *name = NULL;
346     ModuleSP module_sp(GetModule());
347 
348     if (m_obj_file) {
349       const FileSpec &file_spec = m_obj_file->GetFileSpec();
350       name = file_spec.GetFilename().AsCString();
351     }
352     if ((!name || !name[0]) && module_sp)
353       name = module_sp->GetFileSpec().GetFilename().AsCString();
354     if (name && name[0])
355       s->Printf("%s.", name);
356   }
357   m_name.Dump(s);
358 }
359 
360 bool Section::IsDescendant(const Section *section) {
361   if (this == section)
362     return true;
363   SectionSP parent_sp(GetParent());
364   if (parent_sp)
365     return parent_sp->IsDescendant(section);
366   return false;
367 }
368 
369 bool Section::Slide(addr_t slide_amount, bool slide_children) {
370   if (m_file_addr != LLDB_INVALID_ADDRESS) {
371     if (slide_amount == 0)
372       return true;
373 
374     m_file_addr += slide_amount;
375 
376     if (slide_children)
377       m_children.Slide(slide_amount, slide_children);
378 
379     return true;
380   }
381   return false;
382 }
383 
384 //------------------------------------------------------------------
385 /// Get the permissions as OR'ed bits from lldb::Permissions
386 //------------------------------------------------------------------
387 uint32_t Section::GetPermissions() const {
388   uint32_t permissions = 0;
389   if (m_readable)
390     permissions |= ePermissionsReadable;
391   if (m_writable)
392     permissions |= ePermissionsWritable;
393   if (m_executable)
394     permissions |= ePermissionsExecutable;
395   return permissions;
396 }
397 
398 //------------------------------------------------------------------
399 /// Set the permissions using bits OR'ed from lldb::Permissions
400 //------------------------------------------------------------------
401 void Section::SetPermissions(uint32_t permissions) {
402   m_readable = (permissions & ePermissionsReadable) != 0;
403   m_writable = (permissions & ePermissionsWritable) != 0;
404   m_executable = (permissions & ePermissionsExecutable) != 0;
405 }
406 
407 lldb::offset_t Section::GetSectionData(void *dst, lldb::offset_t dst_len,
408                                        lldb::offset_t offset) {
409   if (m_obj_file)
410     return m_obj_file->ReadSectionData(this, offset, dst, dst_len);
411   return 0;
412 }
413 
414 lldb::offset_t Section::GetSectionData(DataExtractor &section_data) {
415   if (m_obj_file)
416     return m_obj_file->ReadSectionData(this, section_data);
417   return 0;
418 }
419 
420 #pragma mark SectionList
421 
422 SectionList::SectionList() : m_sections() {}
423 
424 SectionList::~SectionList() {}
425 
426 SectionList &SectionList::operator=(const SectionList &rhs) {
427   if (this != &rhs)
428     m_sections = rhs.m_sections;
429   return *this;
430 }
431 
432 size_t SectionList::AddSection(const lldb::SectionSP &section_sp) {
433   if (section_sp) {
434     size_t section_index = m_sections.size();
435     m_sections.push_back(section_sp);
436     return section_index;
437   }
438 
439   return std::numeric_limits<size_t>::max();
440 }
441 
442 // Warning, this can be slow as it's removing items from a std::vector.
443 bool SectionList::DeleteSection(size_t idx) {
444   if (idx < m_sections.size()) {
445     m_sections.erase(m_sections.begin() + idx);
446     return true;
447   }
448   return false;
449 }
450 
451 size_t SectionList::FindSectionIndex(const Section *sect) {
452   iterator sect_iter;
453   iterator begin = m_sections.begin();
454   iterator end = m_sections.end();
455   for (sect_iter = begin; sect_iter != end; ++sect_iter) {
456     if (sect_iter->get() == sect) {
457       // The secton was already in this section list
458       return std::distance(begin, sect_iter);
459     }
460   }
461   return UINT32_MAX;
462 }
463 
464 size_t SectionList::AddUniqueSection(const lldb::SectionSP &sect_sp) {
465   size_t sect_idx = FindSectionIndex(sect_sp.get());
466   if (sect_idx == UINT32_MAX) {
467     sect_idx = AddSection(sect_sp);
468   }
469   return sect_idx;
470 }
471 
472 bool SectionList::ReplaceSection(user_id_t sect_id,
473                                  const lldb::SectionSP &sect_sp,
474                                  uint32_t depth) {
475   iterator sect_iter, end = m_sections.end();
476   for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) {
477     if ((*sect_iter)->GetID() == sect_id) {
478       *sect_iter = sect_sp;
479       return true;
480     } else if (depth > 0) {
481       if ((*sect_iter)
482               ->GetChildren()
483               .ReplaceSection(sect_id, sect_sp, depth - 1))
484         return true;
485     }
486   }
487   return false;
488 }
489 
490 size_t SectionList::GetNumSections(uint32_t depth) const {
491   size_t count = m_sections.size();
492   if (depth > 0) {
493     const_iterator sect_iter, end = m_sections.end();
494     for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) {
495       count += (*sect_iter)->GetChildren().GetNumSections(depth - 1);
496     }
497   }
498   return count;
499 }
500 
501 SectionSP SectionList::GetSectionAtIndex(size_t idx) const {
502   SectionSP sect_sp;
503   if (idx < m_sections.size())
504     sect_sp = m_sections[idx];
505   return sect_sp;
506 }
507 
508 SectionSP
509 SectionList::FindSectionByName(ConstString section_dstr) const {
510   SectionSP sect_sp;
511   // Check if we have a valid section string
512   if (section_dstr && !m_sections.empty()) {
513     const_iterator sect_iter;
514     const_iterator end = m_sections.end();
515     for (sect_iter = m_sections.begin();
516          sect_iter != end && sect_sp.get() == NULL; ++sect_iter) {
517       Section *child_section = sect_iter->get();
518       if (child_section) {
519         if (child_section->GetName() == section_dstr) {
520           sect_sp = *sect_iter;
521         } else {
522           sect_sp =
523               child_section->GetChildren().FindSectionByName(section_dstr);
524         }
525       }
526     }
527   }
528   return sect_sp;
529 }
530 
531 SectionSP SectionList::FindSectionByID(user_id_t sect_id) const {
532   SectionSP sect_sp;
533   if (sect_id) {
534     const_iterator sect_iter;
535     const_iterator end = m_sections.end();
536     for (sect_iter = m_sections.begin();
537          sect_iter != end && sect_sp.get() == NULL; ++sect_iter) {
538       if ((*sect_iter)->GetID() == sect_id) {
539         sect_sp = *sect_iter;
540         break;
541       } else {
542         sect_sp = (*sect_iter)->GetChildren().FindSectionByID(sect_id);
543       }
544     }
545   }
546   return sect_sp;
547 }
548 
549 SectionSP SectionList::FindSectionByType(SectionType sect_type,
550                                          bool check_children,
551                                          size_t start_idx) const {
552   SectionSP sect_sp;
553   size_t num_sections = m_sections.size();
554   for (size_t idx = start_idx; idx < num_sections; ++idx) {
555     if (m_sections[idx]->GetType() == sect_type) {
556       sect_sp = m_sections[idx];
557       break;
558     } else if (check_children) {
559       sect_sp = m_sections[idx]->GetChildren().FindSectionByType(
560           sect_type, check_children, 0);
561       if (sect_sp)
562         break;
563     }
564   }
565   return sect_sp;
566 }
567 
568 SectionSP SectionList::FindSectionContainingFileAddress(addr_t vm_addr,
569                                                         uint32_t depth) const {
570   SectionSP sect_sp;
571   const_iterator sect_iter;
572   const_iterator end = m_sections.end();
573   for (sect_iter = m_sections.begin();
574        sect_iter != end && sect_sp.get() == NULL; ++sect_iter) {
575     Section *sect = sect_iter->get();
576     if (sect->ContainsFileAddress(vm_addr)) {
577       // The file address is in this section. We need to make sure one of our
578       // child sections doesn't contain this address as well as obeying the
579       // depth limit that was passed in.
580       if (depth > 0)
581         sect_sp = sect->GetChildren().FindSectionContainingFileAddress(
582             vm_addr, depth - 1);
583 
584       if (sect_sp.get() == NULL && !sect->IsFake())
585         sect_sp = *sect_iter;
586     }
587   }
588   return sect_sp;
589 }
590 
591 bool SectionList::ContainsSection(user_id_t sect_id) const {
592   return FindSectionByID(sect_id).get() != NULL;
593 }
594 
595 void SectionList::Dump(Stream *s, Target *target, bool show_header,
596                        uint32_t depth) const {
597   bool target_has_loaded_sections =
598       target && !target->GetSectionLoadList().IsEmpty();
599   if (show_header && !m_sections.empty()) {
600     s->Indent();
601     s->Printf("SectID     Type             %s Address                          "
602               "   Perm File Off.  File Size  Flags "
603               "     Section Name\n",
604               target_has_loaded_sections ? "Load" : "File");
605     s->Indent();
606     s->PutCString("---------- ---------------- "
607                   "---------------------------------------  ---- ---------- "
608                   "---------- "
609                   "---------- ----------------------------\n");
610   }
611 
612   const_iterator sect_iter;
613   const_iterator end = m_sections.end();
614   for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) {
615     (*sect_iter)->Dump(s, target_has_loaded_sections ? target : NULL, depth);
616   }
617 
618   if (show_header && !m_sections.empty())
619     s->IndentLess();
620 }
621 
622 size_t SectionList::Slide(addr_t slide_amount, bool slide_children) {
623   size_t count = 0;
624   const_iterator pos, end = m_sections.end();
625   for (pos = m_sections.begin(); pos != end; ++pos) {
626     if ((*pos)->Slide(slide_amount, slide_children))
627       ++count;
628   }
629   return count;
630 }
631