1//===-- ObjectFileXCOFF.cpp
2//-------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include "ObjectFileXCOFF.h"
11#include "lldb/Core/Module.h"
12#include "lldb/Core/ModuleSpec.h"
13#include "lldb/Core/PluginManager.h"
14#include "lldb/Core/Progress.h"
15#include "lldb/Core/Section.h"
16#include "lldb/Host/FileSystem.h"
17#include "lldb/Symbol/SymbolContext.h"
18#include "lldb/Target/Process.h"
19#include "lldb/Target/Target.h"
20#include "lldb/Utility/ArchSpec.h"
21#include "lldb/Utility/DataBufferHeap.h"
22#include "lldb/Utility/FileSpecList.h"
23#include "lldb/Utility/LLDBLog.h"
24#include "lldb/Utility/Log.h"
25#include "lldb/Utility/RangeMap.h"
26#include "lldb/Utility/Status.h"
27#include "lldb/Utility/Stream.h"
28#include "llvm/ADT/StringRef.h"
29#include "llvm/BinaryFormat/XCOFF.h"
30#include "llvm/Object/XCOFFObjectFile.h"
31#include "llvm/Support/MemoryBuffer.h"
32#include <algorithm>
33#include <cassert>
34#include <cstring>
35#include <unordered_map>
36
37using namespace llvm;
38using namespace lldb;
39using namespace lldb_private;
40
41LLDB_PLUGIN_DEFINE(ObjectFileXCOFF)
42// FIXME: target 64bit at this moment.
43
44// Static methods.
45void ObjectFileXCOFF::Initialize() {
46 PluginManager::RegisterPlugin(name: GetPluginNameStatic(),
47 description: GetPluginDescriptionStatic(), create_callback: CreateInstance,
48 create_memory_callback: CreateMemoryInstance, get_module_specifications: GetModuleSpecifications);
49}
50
51void ObjectFileXCOFF::Terminate() {
52 PluginManager::UnregisterPlugin(create_callback: CreateInstance);
53}
54
55ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp,
56 DataBufferSP data_sp,
57 lldb::offset_t data_offset,
58 const lldb_private::FileSpec *file,
59 lldb::offset_t file_offset,
60 lldb::offset_t length) {
61 if (!data_sp) {
62 data_sp = MapFileData(file: *file, Size: length, Offset: file_offset);
63 if (!data_sp)
64 return nullptr;
65 data_offset = 0;
66 }
67 if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, offset: data_offset, length))
68 return nullptr;
69 // Update the data to contain the entire file if it doesn't already
70 if (data_sp->GetByteSize() < length) {
71 data_sp = MapFileData(file: *file, Size: length, Offset: file_offset);
72 if (!data_sp)
73 return nullptr;
74 data_offset = 0;
75 }
76 auto objfile_up = std::make_unique<ObjectFileXCOFF>(
77 args: module_sp, args&: data_sp, args&: data_offset, args&: file, args&: file_offset, args&: length);
78 if (!objfile_up)
79 return nullptr;
80
81 // Cache xcoff binary.
82 if (!objfile_up->CreateBinary())
83 return nullptr;
84
85 if (!objfile_up->ParseHeader())
86 return nullptr;
87
88 return objfile_up.release();
89}
90
91bool ObjectFileXCOFF::CreateBinary() {
92 if (m_binary)
93 return true;
94
95 Log *log = GetLog(mask: LLDBLog::Object);
96
97 auto memory_ref = llvm::MemoryBufferRef(toStringRef(Input: m_data.GetData()),
98 m_file.GetFilename().GetStringRef());
99 llvm::file_magic magic = llvm::identify_magic(magic: memory_ref.getBuffer());
100
101 auto binary = llvm::object::ObjectFile::createObjectFile(Object: memory_ref, Type: magic);
102 if (!binary) {
103 LLDB_LOG_ERROR(log, binary.takeError(),
104 "Failed to create binary for file ({1}): {0}", m_file);
105 return false;
106 }
107 // Make sure we only handle XCOFF format.
108 m_binary =
109 llvm::unique_dyn_cast<llvm::object::XCOFFObjectFile>(Val: std::move(*binary));
110 if (!m_binary)
111 return false;
112
113 LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",
114 this, GetModule().get(), GetModule()->GetSpecificationDescription(),
115 m_file.GetPath(), m_binary.get());
116
117 return true;
118}
119
120ObjectFile *ObjectFileXCOFF::CreateMemoryInstance(
121 const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp,
122 const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
123 return nullptr;
124}
125
126size_t ObjectFileXCOFF::GetModuleSpecifications(
127 const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
128 lldb::offset_t data_offset, lldb::offset_t file_offset,
129 lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
130 const size_t initial_count = specs.GetSize();
131
132 if (ObjectFileXCOFF::MagicBytesMatch(data_sp, offset: 0, length: data_sp->GetByteSize())) {
133 ArchSpec arch_spec =
134 ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);
135 ModuleSpec spec(file, arch_spec);
136 spec.GetArchitecture().SetArchitecture(arch_type: eArchTypeXCOFF, cpu: XCOFF::TCPU_PPC64,
137 LLDB_INVALID_CPUTYPE,
138 os: llvm::Triple::AIX);
139 specs.Append(spec);
140 }
141 return specs.GetSize() - initial_count;
142}
143
144static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) {
145 switch (magic) {
146 case XCOFF::XCOFF32:
147 return sizeof(struct llvm::object::XCOFFFileHeader32);
148 break;
149 case XCOFF::XCOFF64:
150 return sizeof(struct llvm::object::XCOFFFileHeader64);
151 break;
152
153 default:
154 break;
155 }
156 return 0;
157}
158
159bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp,
160 lldb::addr_t data_offset,
161 lldb::addr_t data_length) {
162 lldb_private::DataExtractor data;
163 data.SetData(data_sp, offset: data_offset, length: data_length);
164 // Need to set this as XCOFF is only compatible with Big Endian
165 data.SetByteOrder(eByteOrderBig);
166 lldb::offset_t offset = 0;
167 uint16_t magic = data.GetU16(offset_ptr: &offset);
168 return XCOFFHeaderSizeFromMagic(magic) != 0;
169}
170
171bool ObjectFileXCOFF::ParseHeader() {
172 if (m_binary->is64Bit())
173 return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64;
174 return m_binary->fileHeader32()->Magic == XCOFF::XCOFF32;
175}
176
177ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; }
178
179bool ObjectFileXCOFF::IsExecutable() const { return true; }
180
181uint32_t ObjectFileXCOFF::GetAddressByteSize() const {
182 if (m_binary->is64Bit())
183 return 8;
184 return 4;
185}
186
187AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) {
188 return AddressClass::eUnknown;
189}
190
191void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {}
192
193bool ObjectFileXCOFF::IsStripped() { return false; }
194
195void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {
196
197 if (m_sections_up)
198 return;
199
200 m_sections_up = std::make_unique<SectionList>();
201 if (m_binary->is64Bit())
202 CreateSectionsWithBitness<XCOFF64>(unified_section_list);
203 else
204 CreateSectionsWithBitness<XCOFF32>(unified_section_list);
205}
206
207template <typename T>
208static auto GetSections(llvm::object::XCOFFObjectFile *binary) {
209 if constexpr (T::Is64Bit)
210 return binary->sections64();
211 else
212 return binary->sections32();
213}
214
215template <typename T>
216void ObjectFileXCOFF::CreateSectionsWithBitness(
217 SectionList &unified_section_list) {
218 ModuleSP module_sp(GetModule());
219 if (!module_sp)
220 return;
221
222 std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
223
224 int idx = 0;
225 for (const typename T::SectionHeader &section :
226 GetSections<T>(m_binary.get())) {
227
228 ConstString const_sect_name(section.Name);
229
230 SectionType section_type = lldb::eSectionTypeOther;
231 if (section.Flags & XCOFF::STYP_TEXT)
232 section_type = eSectionTypeCode;
233 else if (section.Flags & XCOFF::STYP_DATA)
234 section_type = eSectionTypeData;
235 else if (section.Flags & XCOFF::STYP_BSS)
236 section_type = eSectionTypeZeroFill;
237 else if (section.Flags & XCOFF::STYP_DWARF) {
238 section_type = llvm::StringSwitch<SectionType>(section.Name)
239 .Case(S: ".dwinfo", Value: eSectionTypeDWARFDebugInfo)
240 .Case(S: ".dwline", Value: eSectionTypeDWARFDebugLine)
241 .Case(S: ".dwabrev", Value: eSectionTypeDWARFDebugAbbrev)
242 .Case(S: ".dwrnges", Value: eSectionTypeDWARFDebugRanges)
243 .Default(Value: eSectionTypeInvalid);
244 }
245
246 SectionSP section_sp(new Section(
247 module_sp, this, ++idx, const_sect_name, section_type,
248 section.VirtualAddress, section.SectionSize,
249 section.FileOffsetToRawData, section.SectionSize, 0, section.Flags));
250
251 uint32_t permissions = ePermissionsReadable;
252 if (section.Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS))
253 permissions |= ePermissionsWritable;
254 if (section.Flags & XCOFF::STYP_TEXT)
255 permissions |= ePermissionsExecutable;
256
257 section_sp->SetPermissions(permissions);
258 m_sections_up->AddSection(section_sp);
259 unified_section_list.AddSection(section_sp);
260 }
261}
262
263void ObjectFileXCOFF::Dump(Stream *s) {}
264
265ArchSpec ObjectFileXCOFF::GetArchitecture() {
266 ArchSpec arch_spec =
267 ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);
268 return arch_spec;
269}
270
271UUID ObjectFileXCOFF::GetUUID() { return UUID(); }
272
273uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { return 0; }
274
275ObjectFile::Type ObjectFileXCOFF::CalculateType() {
276
277 const auto flags = m_binary->is64Bit() ? m_binary->fileHeader64()->Flags
278 : m_binary->fileHeader32()->Flags;
279
280 if (flags & XCOFF::F_EXEC)
281 return eTypeExecutable;
282 else if (flags & XCOFF::F_SHROBJ)
283 return eTypeSharedLibrary;
284 return eTypeUnknown;
285}
286
287ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; }
288
289lldb::WritableDataBufferSP
290ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size,
291 uint64_t Offset) {
292 return FileSystem::Instance().CreateWritableDataBuffer(path: file.GetPath(), size: Size,
293 offset: Offset);
294}
295
296ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,
297 DataBufferSP data_sp,
298 lldb::offset_t data_offset,
299 const FileSpec *file,
300 lldb::offset_t file_offset,
301 lldb::offset_t length)
302 : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) {
303 if (file)
304 m_file = *file;
305}
306
307ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,
308 DataBufferSP header_data_sp,
309 const lldb::ProcessSP &process_sp,
310 addr_t header_addr)
311 : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {}
312

source code of lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp