1cfca06d7SDimitry Andric //===-- Section.cpp -------------------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9f034231aSEd Maste #include "lldb/Core/Section.h"
1094994d37SDimitry Andric #include "lldb/Core/Address.h"
11f034231aSEd Maste #include "lldb/Core/Module.h"
12f034231aSEd Maste #include "lldb/Symbol/ObjectFile.h"
13866dcdacSEd Maste #include "lldb/Target/SectionLoadList.h"
14f034231aSEd Maste #include "lldb/Target/Target.h"
1594994d37SDimitry Andric #include "lldb/Utility/FileSpec.h"
1694994d37SDimitry Andric #include "lldb/Utility/VMRange.h"
17f034231aSEd Maste
18344a3780SDimitry Andric #include <cinttypes>
1994994d37SDimitry Andric #include <limits>
2094994d37SDimitry Andric #include <utility>
2174a628f7SDimitry Andric
2274a628f7SDimitry Andric namespace lldb_private {
2374a628f7SDimitry Andric class DataExtractor;
2474a628f7SDimitry Andric }
25f034231aSEd Maste using namespace lldb;
26f034231aSEd Maste using namespace lldb_private;
27f034231aSEd Maste
GetTypeAsCString() const28f73363f1SDimitry Andric const char *Section::GetTypeAsCString() const {
29f73363f1SDimitry Andric switch (m_type) {
3074a628f7SDimitry Andric case eSectionTypeInvalid:
3174a628f7SDimitry Andric return "invalid";
3274a628f7SDimitry Andric case eSectionTypeCode:
3374a628f7SDimitry Andric return "code";
3474a628f7SDimitry Andric case eSectionTypeContainer:
3574a628f7SDimitry Andric return "container";
3674a628f7SDimitry Andric case eSectionTypeData:
3774a628f7SDimitry Andric return "data";
3874a628f7SDimitry Andric case eSectionTypeDataCString:
3974a628f7SDimitry Andric return "data-cstr";
4074a628f7SDimitry Andric case eSectionTypeDataCStringPointers:
4174a628f7SDimitry Andric return "data-cstr-ptr";
4274a628f7SDimitry Andric case eSectionTypeDataSymbolAddress:
4374a628f7SDimitry Andric return "data-symbol-addr";
4474a628f7SDimitry Andric case eSectionTypeData4:
4574a628f7SDimitry Andric return "data-4-byte";
4674a628f7SDimitry Andric case eSectionTypeData8:
4774a628f7SDimitry Andric return "data-8-byte";
4874a628f7SDimitry Andric case eSectionTypeData16:
4974a628f7SDimitry Andric return "data-16-byte";
5074a628f7SDimitry Andric case eSectionTypeDataPointers:
5174a628f7SDimitry Andric return "data-ptrs";
5274a628f7SDimitry Andric case eSectionTypeDebug:
5374a628f7SDimitry Andric return "debug";
5474a628f7SDimitry Andric case eSectionTypeZeroFill:
5574a628f7SDimitry Andric return "zero-fill";
5674a628f7SDimitry Andric case eSectionTypeDataObjCMessageRefs:
5774a628f7SDimitry Andric return "objc-message-refs";
5874a628f7SDimitry Andric case eSectionTypeDataObjCCFStrings:
5974a628f7SDimitry Andric return "objc-cfstrings";
6074a628f7SDimitry Andric case eSectionTypeDWARFDebugAbbrev:
6174a628f7SDimitry Andric return "dwarf-abbrev";
6294994d37SDimitry Andric case eSectionTypeDWARFDebugAbbrevDwo:
6394994d37SDimitry Andric return "dwarf-abbrev-dwo";
6474a628f7SDimitry Andric case eSectionTypeDWARFDebugAddr:
6574a628f7SDimitry Andric return "dwarf-addr";
6674a628f7SDimitry Andric case eSectionTypeDWARFDebugAranges:
6774a628f7SDimitry Andric return "dwarf-aranges";
68ef5d0b5eSDimitry Andric case eSectionTypeDWARFDebugCuIndex:
69ef5d0b5eSDimitry Andric return "dwarf-cu-index";
70cfca06d7SDimitry Andric case eSectionTypeDWARFDebugTuIndex:
71cfca06d7SDimitry Andric return "dwarf-tu-index";
7274a628f7SDimitry Andric case eSectionTypeDWARFDebugFrame:
7374a628f7SDimitry Andric return "dwarf-frame";
7474a628f7SDimitry Andric case eSectionTypeDWARFDebugInfo:
7574a628f7SDimitry Andric return "dwarf-info";
7694994d37SDimitry Andric case eSectionTypeDWARFDebugInfoDwo:
7794994d37SDimitry Andric return "dwarf-info-dwo";
7874a628f7SDimitry Andric case eSectionTypeDWARFDebugLine:
7974a628f7SDimitry Andric return "dwarf-line";
8094994d37SDimitry Andric case eSectionTypeDWARFDebugLineStr:
8194994d37SDimitry Andric return "dwarf-line-str";
8274a628f7SDimitry Andric case eSectionTypeDWARFDebugLoc:
8374a628f7SDimitry Andric return "dwarf-loc";
84706b4fc4SDimitry Andric case eSectionTypeDWARFDebugLocDwo:
85706b4fc4SDimitry Andric return "dwarf-loc-dwo";
8694994d37SDimitry Andric case eSectionTypeDWARFDebugLocLists:
8794994d37SDimitry Andric return "dwarf-loclists";
88706b4fc4SDimitry Andric case eSectionTypeDWARFDebugLocListsDwo:
89706b4fc4SDimitry Andric return "dwarf-loclists-dwo";
9074a628f7SDimitry Andric case eSectionTypeDWARFDebugMacInfo:
9174a628f7SDimitry Andric return "dwarf-macinfo";
9274a628f7SDimitry Andric case eSectionTypeDWARFDebugMacro:
9374a628f7SDimitry Andric return "dwarf-macro";
9474a628f7SDimitry Andric case eSectionTypeDWARFDebugPubNames:
9574a628f7SDimitry Andric return "dwarf-pubnames";
9674a628f7SDimitry Andric case eSectionTypeDWARFDebugPubTypes:
9774a628f7SDimitry Andric return "dwarf-pubtypes";
9874a628f7SDimitry Andric case eSectionTypeDWARFDebugRanges:
9974a628f7SDimitry Andric return "dwarf-ranges";
10094994d37SDimitry Andric case eSectionTypeDWARFDebugRngLists:
10194994d37SDimitry Andric return "dwarf-rnglists";
102706b4fc4SDimitry Andric case eSectionTypeDWARFDebugRngListsDwo:
103706b4fc4SDimitry Andric return "dwarf-rnglists-dwo";
10474a628f7SDimitry Andric case eSectionTypeDWARFDebugStr:
10574a628f7SDimitry Andric return "dwarf-str";
10694994d37SDimitry Andric case eSectionTypeDWARFDebugStrDwo:
10794994d37SDimitry Andric return "dwarf-str-dwo";
10874a628f7SDimitry Andric case eSectionTypeDWARFDebugStrOffsets:
10974a628f7SDimitry Andric return "dwarf-str-offsets";
11094994d37SDimitry Andric case eSectionTypeDWARFDebugStrOffsetsDwo:
11194994d37SDimitry Andric return "dwarf-str-offsets-dwo";
112f73363f1SDimitry Andric case eSectionTypeDWARFDebugTypes:
113f73363f1SDimitry Andric return "dwarf-types";
1145f29bb8aSDimitry Andric case eSectionTypeDWARFDebugTypesDwo:
1155f29bb8aSDimitry Andric return "dwarf-types-dwo";
116f73363f1SDimitry Andric case eSectionTypeDWARFDebugNames:
117f73363f1SDimitry Andric return "dwarf-names";
11874a628f7SDimitry Andric case eSectionTypeELFSymbolTable:
11974a628f7SDimitry Andric return "elf-symbol-table";
12074a628f7SDimitry Andric case eSectionTypeELFDynamicSymbols:
12174a628f7SDimitry Andric return "elf-dynamic-symbols";
12274a628f7SDimitry Andric case eSectionTypeELFRelocationEntries:
12374a628f7SDimitry Andric return "elf-relocation-entries";
12474a628f7SDimitry Andric case eSectionTypeELFDynamicLinkInfo:
12574a628f7SDimitry Andric return "elf-dynamic-link-info";
12674a628f7SDimitry Andric case eSectionTypeDWARFAppleNames:
12774a628f7SDimitry Andric return "apple-names";
12874a628f7SDimitry Andric case eSectionTypeDWARFAppleTypes:
12974a628f7SDimitry Andric return "apple-types";
13074a628f7SDimitry Andric case eSectionTypeDWARFAppleNamespaces:
13174a628f7SDimitry Andric return "apple-namespaces";
13274a628f7SDimitry Andric case eSectionTypeDWARFAppleObjC:
13374a628f7SDimitry Andric return "apple-objc";
13474a628f7SDimitry Andric case eSectionTypeEHFrame:
13574a628f7SDimitry Andric return "eh-frame";
13674a628f7SDimitry Andric case eSectionTypeARMexidx:
13774a628f7SDimitry Andric return "ARM.exidx";
13874a628f7SDimitry Andric case eSectionTypeARMextab:
13974a628f7SDimitry Andric return "ARM.extab";
14074a628f7SDimitry Andric case eSectionTypeCompactUnwind:
14174a628f7SDimitry Andric return "compact-unwind";
14274a628f7SDimitry Andric case eSectionTypeGoSymtab:
14374a628f7SDimitry Andric return "go-symtab";
14474a628f7SDimitry Andric case eSectionTypeAbsoluteAddress:
14574a628f7SDimitry Andric return "absolute";
146f73363f1SDimitry Andric case eSectionTypeDWARFGNUDebugAltLink:
147f73363f1SDimitry Andric return "dwarf-gnu-debugaltlink";
1487fa27ce4SDimitry Andric case eSectionTypeCTF:
1497fa27ce4SDimitry Andric return "ctf";
15074a628f7SDimitry Andric case eSectionTypeOther:
15174a628f7SDimitry Andric return "regular";
152b1c73532SDimitry Andric case eSectionTypeSwiftModules:
153b1c73532SDimitry Andric return "swift-modules";
15474a628f7SDimitry Andric }
15574a628f7SDimitry Andric return "unknown";
15674a628f7SDimitry Andric }
15774a628f7SDimitry Andric
Section(const ModuleSP & module_sp,ObjectFile * obj_file,user_id_t sect_id,ConstString name,SectionType sect_type,addr_t file_addr,addr_t byte_size,lldb::offset_t file_offset,lldb::offset_t file_size,uint32_t log2align,uint32_t flags,uint32_t target_byte_size)15814f1b3e8SDimitry Andric Section::Section(const ModuleSP &module_sp, ObjectFile *obj_file,
1595f29bb8aSDimitry Andric user_id_t sect_id, ConstString name,
16014f1b3e8SDimitry Andric SectionType sect_type, addr_t file_addr, addr_t byte_size,
16114f1b3e8SDimitry Andric lldb::offset_t file_offset, lldb::offset_t file_size,
16214f1b3e8SDimitry Andric uint32_t log2align, uint32_t flags,
16314f1b3e8SDimitry Andric uint32_t target_byte_size /*=1*/)
16414f1b3e8SDimitry Andric : ModuleChild(module_sp), UserID(sect_id), Flags(flags),
16514f1b3e8SDimitry Andric m_obj_file(obj_file), m_type(sect_type), m_parent_wp(), m_name(name),
16614f1b3e8SDimitry Andric m_file_addr(file_addr), m_byte_size(byte_size),
16714f1b3e8SDimitry Andric m_file_offset(file_offset), m_file_size(file_size),
16814f1b3e8SDimitry Andric m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false),
16914f1b3e8SDimitry Andric m_thread_specific(false), m_readable(false), m_writable(false),
170ef5d0b5eSDimitry Andric m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) {
171f034231aSEd Maste }
172f034231aSEd Maste
Section(const lldb::SectionSP & parent_section_sp,const ModuleSP & module_sp,ObjectFile * obj_file,user_id_t sect_id,ConstString name,SectionType sect_type,addr_t file_addr,addr_t byte_size,lldb::offset_t file_offset,lldb::offset_t file_size,uint32_t log2align,uint32_t flags,uint32_t target_byte_size)17314f1b3e8SDimitry Andric Section::Section(const lldb::SectionSP &parent_section_sp,
17414f1b3e8SDimitry Andric const ModuleSP &module_sp, ObjectFile *obj_file,
1755f29bb8aSDimitry Andric user_id_t sect_id, ConstString name,
17614f1b3e8SDimitry Andric SectionType sect_type, addr_t file_addr, addr_t byte_size,
17714f1b3e8SDimitry Andric lldb::offset_t file_offset, lldb::offset_t file_size,
17814f1b3e8SDimitry Andric uint32_t log2align, uint32_t flags,
179f3fbd1c0SDimitry Andric uint32_t target_byte_size /*=1*/)
18014f1b3e8SDimitry Andric : ModuleChild(module_sp), UserID(sect_id), Flags(flags),
18114f1b3e8SDimitry Andric m_obj_file(obj_file), m_type(sect_type), m_parent_wp(), m_name(name),
18214f1b3e8SDimitry Andric m_file_addr(file_addr), m_byte_size(byte_size),
18314f1b3e8SDimitry Andric m_file_offset(file_offset), m_file_size(file_size),
18414f1b3e8SDimitry Andric m_log2align(log2align), m_children(), m_fake(false), m_encrypted(false),
18514f1b3e8SDimitry Andric m_thread_specific(false), m_readable(false), m_writable(false),
186ef5d0b5eSDimitry Andric m_executable(false), m_relocated(false), m_target_byte_size(target_byte_size) {
187f034231aSEd Maste if (parent_section_sp)
188f034231aSEd Maste m_parent_wp = parent_section_sp;
189f034231aSEd Maste }
190f034231aSEd Maste
191145449b1SDimitry Andric Section::~Section() = default;
192f034231aSEd Maste
GetFileAddress() const19314f1b3e8SDimitry Andric addr_t Section::GetFileAddress() const {
194f034231aSEd Maste SectionSP parent_sp(GetParent());
19514f1b3e8SDimitry Andric if (parent_sp) {
196f73363f1SDimitry Andric // This section has a parent which means m_file_addr is an offset into the
197f73363f1SDimitry Andric // parent section, so the file address for this section is the file address
198f73363f1SDimitry Andric // of the parent plus the offset
199f034231aSEd Maste return parent_sp->GetFileAddress() + m_file_addr;
200f034231aSEd Maste }
201f034231aSEd Maste // This section has no parent, so m_file_addr is the file base address
202f034231aSEd Maste return m_file_addr;
203f034231aSEd Maste }
204f034231aSEd Maste
SetFileAddress(lldb::addr_t file_addr)20514f1b3e8SDimitry Andric bool Section::SetFileAddress(lldb::addr_t file_addr) {
206f034231aSEd Maste SectionSP parent_sp(GetParent());
20714f1b3e8SDimitry Andric if (parent_sp) {
208f034231aSEd Maste if (m_file_addr >= file_addr)
209f034231aSEd Maste return parent_sp->SetFileAddress(m_file_addr - file_addr);
210f034231aSEd Maste return false;
21114f1b3e8SDimitry Andric } else {
212f034231aSEd Maste // This section has no parent, so m_file_addr is the file base address
213f034231aSEd Maste m_file_addr = file_addr;
214f034231aSEd Maste return true;
215f034231aSEd Maste }
216f034231aSEd Maste }
217f034231aSEd Maste
GetOffset() const21814f1b3e8SDimitry Andric lldb::addr_t Section::GetOffset() const {
219f034231aSEd Maste // This section has a parent which means m_file_addr is an offset.
220f034231aSEd Maste SectionSP parent_sp(GetParent());
221f034231aSEd Maste if (parent_sp)
222f034231aSEd Maste return m_file_addr;
223f034231aSEd Maste
224f034231aSEd Maste // This section has no parent, so there is no offset to be had
225f034231aSEd Maste return 0;
226f034231aSEd Maste }
227f034231aSEd Maste
GetLoadBaseAddress(Target * target) const22814f1b3e8SDimitry Andric addr_t Section::GetLoadBaseAddress(Target *target) const {
229f034231aSEd Maste addr_t load_base_addr = LLDB_INVALID_ADDRESS;
230f034231aSEd Maste SectionSP parent_sp(GetParent());
23114f1b3e8SDimitry Andric if (parent_sp) {
232f034231aSEd Maste load_base_addr = parent_sp->GetLoadBaseAddress(target);
233f034231aSEd Maste if (load_base_addr != LLDB_INVALID_ADDRESS)
234f034231aSEd Maste load_base_addr += GetOffset();
235f034231aSEd Maste }
23614f1b3e8SDimitry Andric if (load_base_addr == LLDB_INVALID_ADDRESS) {
23714f1b3e8SDimitry Andric load_base_addr = target->GetSectionLoadList().GetSectionLoadAddress(
23814f1b3e8SDimitry Andric const_cast<Section *>(this)->shared_from_this());
239f034231aSEd Maste }
240f034231aSEd Maste return load_base_addr;
241f034231aSEd Maste }
242f034231aSEd Maste
ResolveContainedAddress(addr_t offset,Address & so_addr,bool allow_section_end) const243f1d04915SDimitry Andric bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr,
244f1d04915SDimitry Andric bool allow_section_end) const {
245f034231aSEd Maste const size_t num_children = m_children.GetSize();
24614f1b3e8SDimitry Andric for (size_t i = 0; i < num_children; i++) {
247f034231aSEd Maste Section *child_section = m_children.GetSectionAtIndex(i).get();
248f034231aSEd Maste
249f034231aSEd Maste addr_t child_offset = child_section->GetOffset();
25014f1b3e8SDimitry Andric if (child_offset <= offset &&
251f1d04915SDimitry Andric offset - child_offset <
252f1d04915SDimitry Andric child_section->GetByteSize() + (allow_section_end ? 1 : 0))
25314f1b3e8SDimitry Andric return child_section->ResolveContainedAddress(offset - child_offset,
254f1d04915SDimitry Andric so_addr, allow_section_end);
255f034231aSEd Maste }
256f034231aSEd Maste so_addr.SetOffset(offset);
257f034231aSEd Maste so_addr.SetSection(const_cast<Section *>(this)->shared_from_this());
258f034231aSEd Maste
259cfca06d7SDimitry Andric // Ensure that there are no orphaned (i.e., moduleless) sections.
260f034231aSEd Maste assert(GetModule().get());
261f034231aSEd Maste return true;
262f034231aSEd Maste }
263f034231aSEd Maste
ContainsFileAddress(addr_t vm_addr) const26414f1b3e8SDimitry Andric bool Section::ContainsFileAddress(addr_t vm_addr) const {
265f034231aSEd Maste const addr_t file_addr = GetFileAddress();
266ead24645SDimitry Andric if (file_addr != LLDB_INVALID_ADDRESS && !IsThreadSpecific()) {
26714f1b3e8SDimitry Andric if (file_addr <= vm_addr) {
268205afe67SEd Maste const addr_t offset = (vm_addr - file_addr) * m_target_byte_size;
269f034231aSEd Maste return offset < GetByteSize();
270f034231aSEd Maste }
271f034231aSEd Maste }
272f034231aSEd Maste return false;
273f034231aSEd Maste }
274f034231aSEd Maste
Dump(llvm::raw_ostream & s,unsigned indent,Target * target,uint32_t depth) const275cfca06d7SDimitry Andric void Section::Dump(llvm::raw_ostream &s, unsigned indent, Target *target,
276cfca06d7SDimitry Andric uint32_t depth) const {
277cfca06d7SDimitry Andric s.indent(indent);
278ac9a064cSDimitry Andric s << llvm::format("0x%16.16" PRIx64 " %-22s ", GetID(), GetTypeAsCString());
279f034231aSEd Maste bool resolved = true;
280f034231aSEd Maste addr_t addr = LLDB_INVALID_ADDRESS;
281f034231aSEd Maste
282f034231aSEd Maste if (GetByteSize() == 0)
283cfca06d7SDimitry Andric s.indent(39);
28414f1b3e8SDimitry Andric else {
285f034231aSEd Maste if (target)
286f034231aSEd Maste addr = GetLoadBaseAddress(target);
287f034231aSEd Maste
28814f1b3e8SDimitry Andric if (addr == LLDB_INVALID_ADDRESS) {
289f034231aSEd Maste if (target)
290f034231aSEd Maste resolved = false;
291f034231aSEd Maste addr = GetFileAddress();
292f034231aSEd Maste }
293f034231aSEd Maste
294f034231aSEd Maste VMRange range(addr, addr + m_byte_size);
295cfca06d7SDimitry Andric range.Dump(s, 0);
296f034231aSEd Maste }
297f034231aSEd Maste
298cfca06d7SDimitry Andric s << llvm::format("%c %c%c%c 0x%8.8" PRIx64 " 0x%8.8" PRIx64 " 0x%8.8x ",
29914f1b3e8SDimitry Andric resolved ? ' ' : '*', m_readable ? 'r' : '-',
300cfca06d7SDimitry Andric m_writable ? 'w' : '-', m_executable ? 'x' : '-',
301cfca06d7SDimitry Andric m_file_offset, m_file_size, Get());
302f034231aSEd Maste
303f034231aSEd Maste DumpName(s);
304f034231aSEd Maste
305cfca06d7SDimitry Andric s << "\n";
306f034231aSEd Maste
307f034231aSEd Maste if (depth > 0)
308cfca06d7SDimitry Andric m_children.Dump(s, indent, target, false, depth - 1);
309f034231aSEd Maste }
310f034231aSEd Maste
DumpName(llvm::raw_ostream & s) const311cfca06d7SDimitry Andric void Section::DumpName(llvm::raw_ostream &s) const {
312f034231aSEd Maste SectionSP parent_sp(GetParent());
31314f1b3e8SDimitry Andric if (parent_sp) {
314f034231aSEd Maste parent_sp->DumpName(s);
315cfca06d7SDimitry Andric s << '.';
31614f1b3e8SDimitry Andric } else {
317f034231aSEd Maste // The top most section prints the module basename
3185f29bb8aSDimitry Andric const char *name = nullptr;
319f034231aSEd Maste ModuleSP module_sp(GetModule());
320f034231aSEd Maste
321f73363f1SDimitry Andric if (m_obj_file) {
322f73363f1SDimitry Andric const FileSpec &file_spec = m_obj_file->GetFileSpec();
323f034231aSEd Maste name = file_spec.GetFilename().AsCString();
324f73363f1SDimitry Andric }
325f034231aSEd Maste if ((!name || !name[0]) && module_sp)
326f034231aSEd Maste name = module_sp->GetFileSpec().GetFilename().AsCString();
327f034231aSEd Maste if (name && name[0])
328cfca06d7SDimitry Andric s << name << '.';
329f034231aSEd Maste }
330cfca06d7SDimitry Andric s << m_name;
331f034231aSEd Maste }
332f034231aSEd Maste
IsDescendant(const Section * section)33314f1b3e8SDimitry Andric bool Section::IsDescendant(const Section *section) {
334f034231aSEd Maste if (this == section)
335f034231aSEd Maste return true;
336f034231aSEd Maste SectionSP parent_sp(GetParent());
337f034231aSEd Maste if (parent_sp)
338f034231aSEd Maste return parent_sp->IsDescendant(section);
339f034231aSEd Maste return false;
340f034231aSEd Maste }
341f034231aSEd Maste
Slide(addr_t slide_amount,bool slide_children)34214f1b3e8SDimitry Andric bool Section::Slide(addr_t slide_amount, bool slide_children) {
34314f1b3e8SDimitry Andric if (m_file_addr != LLDB_INVALID_ADDRESS) {
344f034231aSEd Maste if (slide_amount == 0)
345f034231aSEd Maste return true;
346f034231aSEd Maste
347f034231aSEd Maste m_file_addr += slide_amount;
348f034231aSEd Maste
349f034231aSEd Maste if (slide_children)
350f034231aSEd Maste m_children.Slide(slide_amount, slide_children);
351f034231aSEd Maste
352f034231aSEd Maste return true;
353f034231aSEd Maste }
354f034231aSEd Maste return false;
355f034231aSEd Maste }
356f034231aSEd Maste
357f3fbd1c0SDimitry Andric /// Get the permissions as OR'ed bits from lldb::Permissions
GetPermissions() const35814f1b3e8SDimitry Andric uint32_t Section::GetPermissions() const {
359f3fbd1c0SDimitry Andric uint32_t permissions = 0;
360f3fbd1c0SDimitry Andric if (m_readable)
361f3fbd1c0SDimitry Andric permissions |= ePermissionsReadable;
362f3fbd1c0SDimitry Andric if (m_writable)
363f3fbd1c0SDimitry Andric permissions |= ePermissionsWritable;
364f3fbd1c0SDimitry Andric if (m_executable)
365f3fbd1c0SDimitry Andric permissions |= ePermissionsExecutable;
366f3fbd1c0SDimitry Andric return permissions;
367f3fbd1c0SDimitry Andric }
368f3fbd1c0SDimitry Andric
369f3fbd1c0SDimitry Andric /// Set the permissions using bits OR'ed from lldb::Permissions
SetPermissions(uint32_t permissions)37014f1b3e8SDimitry Andric void Section::SetPermissions(uint32_t permissions) {
371f3fbd1c0SDimitry Andric m_readable = (permissions & ePermissionsReadable) != 0;
372f3fbd1c0SDimitry Andric m_writable = (permissions & ePermissionsWritable) != 0;
373f3fbd1c0SDimitry Andric m_executable = (permissions & ePermissionsExecutable) != 0;
374f3fbd1c0SDimitry Andric }
375f3fbd1c0SDimitry Andric
GetSectionData(void * dst,lldb::offset_t dst_len,lldb::offset_t offset)37614f1b3e8SDimitry Andric lldb::offset_t Section::GetSectionData(void *dst, lldb::offset_t dst_len,
37714f1b3e8SDimitry Andric lldb::offset_t offset) {
378e81d9d49SDimitry Andric if (m_obj_file)
37914f1b3e8SDimitry Andric return m_obj_file->ReadSectionData(this, offset, dst, dst_len);
380e81d9d49SDimitry Andric return 0;
381e81d9d49SDimitry Andric }
382e81d9d49SDimitry Andric
GetSectionData(DataExtractor & section_data)383ef5d0b5eSDimitry Andric lldb::offset_t Section::GetSectionData(DataExtractor §ion_data) {
384e81d9d49SDimitry Andric if (m_obj_file)
385e81d9d49SDimitry Andric return m_obj_file->ReadSectionData(this, section_data);
386e81d9d49SDimitry Andric return 0;
387e81d9d49SDimitry Andric }
388e81d9d49SDimitry Andric
ContainsOnlyDebugInfo() const389c0981da4SDimitry Andric bool Section::ContainsOnlyDebugInfo() const {
390c0981da4SDimitry Andric switch (m_type) {
391c0981da4SDimitry Andric case eSectionTypeInvalid:
392c0981da4SDimitry Andric case eSectionTypeCode:
393c0981da4SDimitry Andric case eSectionTypeContainer:
394c0981da4SDimitry Andric case eSectionTypeData:
395c0981da4SDimitry Andric case eSectionTypeDataCString:
396c0981da4SDimitry Andric case eSectionTypeDataCStringPointers:
397c0981da4SDimitry Andric case eSectionTypeDataSymbolAddress:
398c0981da4SDimitry Andric case eSectionTypeData4:
399c0981da4SDimitry Andric case eSectionTypeData8:
400c0981da4SDimitry Andric case eSectionTypeData16:
401c0981da4SDimitry Andric case eSectionTypeDataPointers:
402c0981da4SDimitry Andric case eSectionTypeZeroFill:
403c0981da4SDimitry Andric case eSectionTypeDataObjCMessageRefs:
404c0981da4SDimitry Andric case eSectionTypeDataObjCCFStrings:
405c0981da4SDimitry Andric case eSectionTypeELFSymbolTable:
406c0981da4SDimitry Andric case eSectionTypeELFDynamicSymbols:
407c0981da4SDimitry Andric case eSectionTypeELFRelocationEntries:
408c0981da4SDimitry Andric case eSectionTypeELFDynamicLinkInfo:
409c0981da4SDimitry Andric case eSectionTypeEHFrame:
410c0981da4SDimitry Andric case eSectionTypeARMexidx:
411c0981da4SDimitry Andric case eSectionTypeARMextab:
412c0981da4SDimitry Andric case eSectionTypeCompactUnwind:
413c0981da4SDimitry Andric case eSectionTypeGoSymtab:
414c0981da4SDimitry Andric case eSectionTypeAbsoluteAddress:
415c0981da4SDimitry Andric case eSectionTypeOther:
416145449b1SDimitry Andric // Used for "__dof_cache" in mach-o or ".debug" for COFF which isn't debug
417145449b1SDimitry Andric // information that we parse at all. This was causing system files with no
418145449b1SDimitry Andric // debug info to show debug info byte sizes in the "statistics dump" output
419145449b1SDimitry Andric // for each module. New "eSectionType" enums should be created for dedicated
420145449b1SDimitry Andric // debug info that has a predefined format if we wish for these sections to
421145449b1SDimitry Andric // show up as debug info.
422145449b1SDimitry Andric case eSectionTypeDebug:
423c0981da4SDimitry Andric return false;
424c0981da4SDimitry Andric
425c0981da4SDimitry Andric case eSectionTypeDWARFDebugAbbrev:
426c0981da4SDimitry Andric case eSectionTypeDWARFDebugAbbrevDwo:
427c0981da4SDimitry Andric case eSectionTypeDWARFDebugAddr:
428c0981da4SDimitry Andric case eSectionTypeDWARFDebugAranges:
429c0981da4SDimitry Andric case eSectionTypeDWARFDebugCuIndex:
430c0981da4SDimitry Andric case eSectionTypeDWARFDebugTuIndex:
431c0981da4SDimitry Andric case eSectionTypeDWARFDebugFrame:
432c0981da4SDimitry Andric case eSectionTypeDWARFDebugInfo:
433c0981da4SDimitry Andric case eSectionTypeDWARFDebugInfoDwo:
434c0981da4SDimitry Andric case eSectionTypeDWARFDebugLine:
435c0981da4SDimitry Andric case eSectionTypeDWARFDebugLineStr:
436c0981da4SDimitry Andric case eSectionTypeDWARFDebugLoc:
437c0981da4SDimitry Andric case eSectionTypeDWARFDebugLocDwo:
438c0981da4SDimitry Andric case eSectionTypeDWARFDebugLocLists:
439c0981da4SDimitry Andric case eSectionTypeDWARFDebugLocListsDwo:
440c0981da4SDimitry Andric case eSectionTypeDWARFDebugMacInfo:
441c0981da4SDimitry Andric case eSectionTypeDWARFDebugMacro:
442c0981da4SDimitry Andric case eSectionTypeDWARFDebugPubNames:
443c0981da4SDimitry Andric case eSectionTypeDWARFDebugPubTypes:
444c0981da4SDimitry Andric case eSectionTypeDWARFDebugRanges:
445c0981da4SDimitry Andric case eSectionTypeDWARFDebugRngLists:
446c0981da4SDimitry Andric case eSectionTypeDWARFDebugRngListsDwo:
447c0981da4SDimitry Andric case eSectionTypeDWARFDebugStr:
448c0981da4SDimitry Andric case eSectionTypeDWARFDebugStrDwo:
449c0981da4SDimitry Andric case eSectionTypeDWARFDebugStrOffsets:
450c0981da4SDimitry Andric case eSectionTypeDWARFDebugStrOffsetsDwo:
451c0981da4SDimitry Andric case eSectionTypeDWARFDebugTypes:
452c0981da4SDimitry Andric case eSectionTypeDWARFDebugTypesDwo:
453c0981da4SDimitry Andric case eSectionTypeDWARFDebugNames:
454c0981da4SDimitry Andric case eSectionTypeDWARFAppleNames:
455c0981da4SDimitry Andric case eSectionTypeDWARFAppleTypes:
456c0981da4SDimitry Andric case eSectionTypeDWARFAppleNamespaces:
457c0981da4SDimitry Andric case eSectionTypeDWARFAppleObjC:
458c0981da4SDimitry Andric case eSectionTypeDWARFGNUDebugAltLink:
4597fa27ce4SDimitry Andric case eSectionTypeCTF:
460b1c73532SDimitry Andric case eSectionTypeSwiftModules:
461c0981da4SDimitry Andric return true;
462c0981da4SDimitry Andric }
463c0981da4SDimitry Andric return false;
464c0981da4SDimitry Andric }
465c0981da4SDimitry Andric
466c0981da4SDimitry Andric
467f034231aSEd Maste #pragma mark SectionList
468f034231aSEd Maste
operator =(const SectionList & rhs)46914f1b3e8SDimitry Andric SectionList &SectionList::operator=(const SectionList &rhs) {
470f034231aSEd Maste if (this != &rhs)
471f034231aSEd Maste m_sections = rhs.m_sections;
472f034231aSEd Maste return *this;
473f034231aSEd Maste }
474f034231aSEd Maste
AddSection(const lldb::SectionSP & section_sp)47514f1b3e8SDimitry Andric size_t SectionList::AddSection(const lldb::SectionSP §ion_sp) {
47614f1b3e8SDimitry Andric if (section_sp) {
477f034231aSEd Maste size_t section_index = m_sections.size();
478f034231aSEd Maste m_sections.push_back(section_sp);
479f034231aSEd Maste return section_index;
480f034231aSEd Maste }
481f034231aSEd Maste
4820cac4ca3SEd Maste return std::numeric_limits<size_t>::max();
4830cac4ca3SEd Maste }
4840cac4ca3SEd Maste
485f034231aSEd Maste // Warning, this can be slow as it's removing items from a std::vector.
DeleteSection(size_t idx)48614f1b3e8SDimitry Andric bool SectionList::DeleteSection(size_t idx) {
48714f1b3e8SDimitry Andric if (idx < m_sections.size()) {
488f034231aSEd Maste m_sections.erase(m_sections.begin() + idx);
489f034231aSEd Maste return true;
490f034231aSEd Maste }
491f034231aSEd Maste return false;
492f034231aSEd Maste }
493f034231aSEd Maste
FindSectionIndex(const Section * sect)49414f1b3e8SDimitry Andric size_t SectionList::FindSectionIndex(const Section *sect) {
495f034231aSEd Maste iterator sect_iter;
496f034231aSEd Maste iterator begin = m_sections.begin();
497f034231aSEd Maste iterator end = m_sections.end();
49814f1b3e8SDimitry Andric for (sect_iter = begin; sect_iter != end; ++sect_iter) {
49914f1b3e8SDimitry Andric if (sect_iter->get() == sect) {
500f034231aSEd Maste // The secton was already in this section list
501f034231aSEd Maste return std::distance(begin, sect_iter);
502f034231aSEd Maste }
503f034231aSEd Maste }
504f034231aSEd Maste return UINT32_MAX;
505f034231aSEd Maste }
506f034231aSEd Maste
AddUniqueSection(const lldb::SectionSP & sect_sp)50714f1b3e8SDimitry Andric size_t SectionList::AddUniqueSection(const lldb::SectionSP §_sp) {
508f034231aSEd Maste size_t sect_idx = FindSectionIndex(sect_sp.get());
50914f1b3e8SDimitry Andric if (sect_idx == UINT32_MAX) {
510f034231aSEd Maste sect_idx = AddSection(sect_sp);
511f034231aSEd Maste }
512f034231aSEd Maste return sect_idx;
513f034231aSEd Maste }
514f034231aSEd Maste
ReplaceSection(user_id_t sect_id,const lldb::SectionSP & sect_sp,uint32_t depth)51514f1b3e8SDimitry Andric bool SectionList::ReplaceSection(user_id_t sect_id,
51614f1b3e8SDimitry Andric const lldb::SectionSP §_sp,
51714f1b3e8SDimitry Andric uint32_t depth) {
518f034231aSEd Maste iterator sect_iter, end = m_sections.end();
51914f1b3e8SDimitry Andric for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) {
52014f1b3e8SDimitry Andric if ((*sect_iter)->GetID() == sect_id) {
521f034231aSEd Maste *sect_iter = sect_sp;
522f034231aSEd Maste return true;
52314f1b3e8SDimitry Andric } else if (depth > 0) {
52414f1b3e8SDimitry Andric if ((*sect_iter)
52514f1b3e8SDimitry Andric ->GetChildren()
52614f1b3e8SDimitry Andric .ReplaceSection(sect_id, sect_sp, depth - 1))
527f034231aSEd Maste return true;
528f034231aSEd Maste }
529f034231aSEd Maste }
530f034231aSEd Maste return false;
531f034231aSEd Maste }
532f034231aSEd Maste
GetNumSections(uint32_t depth) const53314f1b3e8SDimitry Andric size_t SectionList::GetNumSections(uint32_t depth) const {
534f034231aSEd Maste size_t count = m_sections.size();
53514f1b3e8SDimitry Andric if (depth > 0) {
536f034231aSEd Maste const_iterator sect_iter, end = m_sections.end();
53714f1b3e8SDimitry Andric for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter) {
538f034231aSEd Maste count += (*sect_iter)->GetChildren().GetNumSections(depth - 1);
539f034231aSEd Maste }
540f034231aSEd Maste }
541f034231aSEd Maste return count;
542f034231aSEd Maste }
543f034231aSEd Maste
GetSectionAtIndex(size_t idx) const54414f1b3e8SDimitry Andric SectionSP SectionList::GetSectionAtIndex(size_t idx) const {
545f034231aSEd Maste SectionSP sect_sp;
546f034231aSEd Maste if (idx < m_sections.size())
547f034231aSEd Maste sect_sp = m_sections[idx];
548f034231aSEd Maste return sect_sp;
549f034231aSEd Maste }
550f034231aSEd Maste
551f034231aSEd Maste SectionSP
FindSectionByName(ConstString section_dstr) const5525f29bb8aSDimitry Andric SectionList::FindSectionByName(ConstString section_dstr) const {
553f034231aSEd Maste SectionSP sect_sp;
554f034231aSEd Maste // Check if we have a valid section string
55514f1b3e8SDimitry Andric if (section_dstr && !m_sections.empty()) {
556f034231aSEd Maste const_iterator sect_iter;
557f034231aSEd Maste const_iterator end = m_sections.end();
55814f1b3e8SDimitry Andric for (sect_iter = m_sections.begin();
5595f29bb8aSDimitry Andric sect_iter != end && sect_sp.get() == nullptr; ++sect_iter) {
560f034231aSEd Maste Section *child_section = sect_iter->get();
56114f1b3e8SDimitry Andric if (child_section) {
56214f1b3e8SDimitry Andric if (child_section->GetName() == section_dstr) {
563f034231aSEd Maste sect_sp = *sect_iter;
56414f1b3e8SDimitry Andric } else {
56514f1b3e8SDimitry Andric sect_sp =
56614f1b3e8SDimitry Andric child_section->GetChildren().FindSectionByName(section_dstr);
567f034231aSEd Maste }
568f034231aSEd Maste }
569f034231aSEd Maste }
5700cac4ca3SEd Maste }
571f034231aSEd Maste return sect_sp;
572f034231aSEd Maste }
573f034231aSEd Maste
FindSectionByID(user_id_t sect_id) const57414f1b3e8SDimitry Andric SectionSP SectionList::FindSectionByID(user_id_t sect_id) const {
575f034231aSEd Maste SectionSP sect_sp;
57614f1b3e8SDimitry Andric if (sect_id) {
577f034231aSEd Maste const_iterator sect_iter;
578f034231aSEd Maste const_iterator end = m_sections.end();
57914f1b3e8SDimitry Andric for (sect_iter = m_sections.begin();
5805f29bb8aSDimitry Andric sect_iter != end && sect_sp.get() == nullptr; ++sect_iter) {
58114f1b3e8SDimitry Andric if ((*sect_iter)->GetID() == sect_id) {
582f034231aSEd Maste sect_sp = *sect_iter;
583f034231aSEd Maste break;
58414f1b3e8SDimitry Andric } else {
585f034231aSEd Maste sect_sp = (*sect_iter)->GetChildren().FindSectionByID(sect_id);
586f034231aSEd Maste }
587f034231aSEd Maste }
588f034231aSEd Maste }
589f034231aSEd Maste return sect_sp;
590f034231aSEd Maste }
591f034231aSEd Maste
FindSectionByType(SectionType sect_type,bool check_children,size_t start_idx) const59214f1b3e8SDimitry Andric SectionSP SectionList::FindSectionByType(SectionType sect_type,
59314f1b3e8SDimitry Andric bool check_children,
59414f1b3e8SDimitry Andric size_t start_idx) const {
595f034231aSEd Maste SectionSP sect_sp;
596f034231aSEd Maste size_t num_sections = m_sections.size();
59714f1b3e8SDimitry Andric for (size_t idx = start_idx; idx < num_sections; ++idx) {
59814f1b3e8SDimitry Andric if (m_sections[idx]->GetType() == sect_type) {
599f034231aSEd Maste sect_sp = m_sections[idx];
600f034231aSEd Maste break;
60114f1b3e8SDimitry Andric } else if (check_children) {
60214f1b3e8SDimitry Andric sect_sp = m_sections[idx]->GetChildren().FindSectionByType(
60314f1b3e8SDimitry Andric sect_type, check_children, 0);
604f034231aSEd Maste if (sect_sp)
605f034231aSEd Maste break;
606f034231aSEd Maste }
607f034231aSEd Maste }
608f034231aSEd Maste return sect_sp;
609f034231aSEd Maste }
610f034231aSEd Maste
FindSectionContainingFileAddress(addr_t vm_addr,uint32_t depth) const61114f1b3e8SDimitry Andric SectionSP SectionList::FindSectionContainingFileAddress(addr_t vm_addr,
61214f1b3e8SDimitry Andric uint32_t depth) const {
613f034231aSEd Maste SectionSP sect_sp;
614f034231aSEd Maste const_iterator sect_iter;
615f034231aSEd Maste const_iterator end = m_sections.end();
61614f1b3e8SDimitry Andric for (sect_iter = m_sections.begin();
6175f29bb8aSDimitry Andric sect_iter != end && sect_sp.get() == nullptr; ++sect_iter) {
618f034231aSEd Maste Section *sect = sect_iter->get();
61914f1b3e8SDimitry Andric if (sect->ContainsFileAddress(vm_addr)) {
62014f1b3e8SDimitry Andric // The file address is in this section. We need to make sure one of our
621f73363f1SDimitry Andric // child sections doesn't contain this address as well as obeying the
622f73363f1SDimitry Andric // depth limit that was passed in.
623f034231aSEd Maste if (depth > 0)
62414f1b3e8SDimitry Andric sect_sp = sect->GetChildren().FindSectionContainingFileAddress(
62514f1b3e8SDimitry Andric vm_addr, depth - 1);
626f034231aSEd Maste
6275f29bb8aSDimitry Andric if (sect_sp.get() == nullptr && !sect->IsFake())
628f034231aSEd Maste sect_sp = *sect_iter;
629f034231aSEd Maste }
630f034231aSEd Maste }
631f034231aSEd Maste return sect_sp;
632f034231aSEd Maste }
633f034231aSEd Maste
ContainsSection(user_id_t sect_id) const63414f1b3e8SDimitry Andric bool SectionList::ContainsSection(user_id_t sect_id) const {
6355f29bb8aSDimitry Andric return FindSectionByID(sect_id).get() != nullptr;
636f034231aSEd Maste }
637f034231aSEd Maste
Dump(llvm::raw_ostream & s,unsigned indent,Target * target,bool show_header,uint32_t depth) const638cfca06d7SDimitry Andric void SectionList::Dump(llvm::raw_ostream &s, unsigned indent, Target *target,
639cfca06d7SDimitry Andric bool show_header, uint32_t depth) const {
64014f1b3e8SDimitry Andric bool target_has_loaded_sections =
64114f1b3e8SDimitry Andric target && !target->GetSectionLoadList().IsEmpty();
64214f1b3e8SDimitry Andric if (show_header && !m_sections.empty()) {
643cfca06d7SDimitry Andric s.indent(indent);
644cfca06d7SDimitry Andric s << llvm::formatv(
645cfca06d7SDimitry Andric "SectID Type {0} Address "
646ac9a064cSDimitry Andric " Perm File Off. File Size Flags Section Name\n",
647f3fbd1c0SDimitry Andric target_has_loaded_sections ? "Load" : "File");
648cfca06d7SDimitry Andric s.indent(indent);
649ac9a064cSDimitry Andric s << "------------------ ---------------------- "
650ac9a064cSDimitry Andric "--------------------------------------- ---- ---------- ---------- "
651cfca06d7SDimitry Andric "---------- ----------------------------\n";
652f034231aSEd Maste }
653f034231aSEd Maste
654cfca06d7SDimitry Andric for (const auto §ion_sp : m_sections)
655cfca06d7SDimitry Andric section_sp->Dump(s, indent, target_has_loaded_sections ? target : nullptr,
656cfca06d7SDimitry Andric depth);
657f034231aSEd Maste }
658f034231aSEd Maste
Slide(addr_t slide_amount,bool slide_children)65914f1b3e8SDimitry Andric size_t SectionList::Slide(addr_t slide_amount, bool slide_children) {
660f034231aSEd Maste size_t count = 0;
661f034231aSEd Maste const_iterator pos, end = m_sections.end();
66214f1b3e8SDimitry Andric for (pos = m_sections.begin(); pos != end; ++pos) {
663f034231aSEd Maste if ((*pos)->Slide(slide_amount, slide_children))
664f034231aSEd Maste ++count;
665f034231aSEd Maste }
666f034231aSEd Maste return count;
667f034231aSEd Maste }
668c0981da4SDimitry Andric
GetDebugInfoSize() const669c0981da4SDimitry Andric uint64_t SectionList::GetDebugInfoSize() const {
670c0981da4SDimitry Andric uint64_t debug_info_size = 0;
671c0981da4SDimitry Andric for (const auto §ion : m_sections) {
672c0981da4SDimitry Andric const SectionList &sub_sections = section->GetChildren();
673c0981da4SDimitry Andric if (sub_sections.GetSize() > 0)
674c0981da4SDimitry Andric debug_info_size += sub_sections.GetDebugInfoSize();
675c0981da4SDimitry Andric else if (section->ContainsOnlyDebugInfo())
676c0981da4SDimitry Andric debug_info_size += section->GetFileSize();
677c0981da4SDimitry Andric }
678c0981da4SDimitry Andric return debug_info_size;
679c0981da4SDimitry Andric }
6807fa27ce4SDimitry Andric
6817fa27ce4SDimitry Andric namespace llvm {
6827fa27ce4SDimitry Andric namespace json {
6837fa27ce4SDimitry Andric
fromJSON(const llvm::json::Value & value,lldb_private::JSONSection & section,llvm::json::Path path)6847fa27ce4SDimitry Andric bool fromJSON(const llvm::json::Value &value,
6857fa27ce4SDimitry Andric lldb_private::JSONSection §ion, llvm::json::Path path) {
6867fa27ce4SDimitry Andric llvm::json::ObjectMapper o(value, path);
6877fa27ce4SDimitry Andric return o && o.map("name", section.name) && o.map("type", section.type) &&
6887fa27ce4SDimitry Andric o.map("size", section.address) && o.map("size", section.size);
6897fa27ce4SDimitry Andric }
6907fa27ce4SDimitry Andric
fromJSON(const llvm::json::Value & value,lldb::SectionType & type,llvm::json::Path path)6917fa27ce4SDimitry Andric bool fromJSON(const llvm::json::Value &value, lldb::SectionType &type,
6927fa27ce4SDimitry Andric llvm::json::Path path) {
6937fa27ce4SDimitry Andric if (auto str = value.getAsString()) {
6947fa27ce4SDimitry Andric type = llvm::StringSwitch<lldb::SectionType>(*str)
6957fa27ce4SDimitry Andric .Case("code", eSectionTypeCode)
6967fa27ce4SDimitry Andric .Case("container", eSectionTypeContainer)
6977fa27ce4SDimitry Andric .Case("data", eSectionTypeData)
6987fa27ce4SDimitry Andric .Case("debug", eSectionTypeDebug)
6997fa27ce4SDimitry Andric .Default(eSectionTypeInvalid);
7007fa27ce4SDimitry Andric
7017fa27ce4SDimitry Andric if (type == eSectionTypeInvalid) {
7027fa27ce4SDimitry Andric path.report("invalid section type");
7037fa27ce4SDimitry Andric return false;
7047fa27ce4SDimitry Andric }
7057fa27ce4SDimitry Andric
7067fa27ce4SDimitry Andric return true;
7077fa27ce4SDimitry Andric }
7087fa27ce4SDimitry Andric path.report("expected string");
7097fa27ce4SDimitry Andric return false;
7107fa27ce4SDimitry Andric }
7117fa27ce4SDimitry Andric } // namespace json
7127fa27ce4SDimitry Andric } // namespace llvm
713