LLDB mainline
ObjectFileXCOFF.cpp
Go to the documentation of this file.
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"
14#include "lldb/Core/Progress.h"
15#include "lldb/Core/Section.h"
18#include "lldb/Target/Process.h"
19#include "lldb/Target/Target.h"
24#include "lldb/Utility/Log.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
42// FIXME: target 64bit at this moment.
43
44// Static methods.
50
54
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, length, file_offset);
63 if (!data_sp)
64 return nullptr;
65 data_offset = 0;
66 }
67 if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, 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, length, file_offset);
72 if (!data_sp)
73 return nullptr;
74 data_offset = 0;
75 }
76 auto objfile_up = std::make_unique<ObjectFileXCOFF>(
77 module_sp, data_sp, data_offset, file, file_offset, 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
92 if (m_binary)
93 return true;
94
96
97 auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data.GetData()),
98 m_file.GetFilename().GetStringRef());
99 llvm::file_magic magic = llvm::identify_magic(memory_ref.getBuffer());
100
101 auto binary = llvm::object::ObjectFile::createObjectFile(memory_ref, 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>(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
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
127 const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
128 lldb::offset_t data_offset, lldb::offset_t file_offset,
130 const size_t initial_count = specs.GetSize();
131
132 if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, 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(eArchTypeXCOFF, XCOFF::TCPU_PPC64,
138 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
160 lldb::addr_t data_offset,
161 lldb::addr_t data_length) {
163 data.SetData(data_sp, data_offset, data_length);
164 // Need to set this as XCOFF is only compatible with Big Endian
166 lldb::offset_t offset = 0;
167 uint16_t magic = data.GetU16(&offset);
168 return XCOFFHeaderSizeFromMagic(magic) != 0;
169}
170
172 if (m_binary->is64Bit())
173 return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64;
174 return m_binary->fileHeader32()->Magic == XCOFF::XCOFF32;
175}
176
178
179bool ObjectFileXCOFF::IsExecutable() const { return true; }
180
182 if (m_binary->is64Bit())
183 return 8;
184 return 4;
185}
186
190
191static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type) {
192 switch (sym_type) {
193 case llvm::object::SymbolRef::ST_Function:
195 case llvm::object::SymbolRef::ST_Data:
197 case llvm::object::SymbolRef::ST_File:
199 default:
201 }
202}
203
205 Log *log = GetLog(LLDBLog::Object);
206 SectionList *sectionList = GetSectionList();
207
208 for (const auto &symbol_ref : m_binary->symbols()) {
209 llvm::object::XCOFFSymbolRef xcoff_sym_ref(symbol_ref);
210
211 llvm::Expected<llvm::StringRef> name_or_err = xcoff_sym_ref.getName();
212 if (!name_or_err) {
213 LLDB_LOG_ERROR(log, name_or_err.takeError(),
214 "Unable to extract name from the xcoff symbol ref object");
215 continue;
216 }
217
218 llvm::StringRef symbolName = name_or_err.get();
219 // Remove the . prefix added during compilation. This prefix is usually
220 // added to differentiate between reference to the code and function
221 // descriptor. For instance, Adding .func will only allow user to put bp on
222 // .func, which is not known to the user, instead of func.
223 llvm::StringRef name_no_dot =
224 symbolName.starts_with(".") ? symbolName.drop_front() : symbolName;
225 auto storageClass = xcoff_sym_ref.getStorageClass();
226 // C_HIDEXT symbols are not needed to be exposed, with the exception of TOC
227 // which is responsible for storing references to global data
228 if (storageClass == XCOFF::C_HIDEXT && symbolName != "TOC") {
229
230 // Zero or muliple aux entries may suggest ambiguous data
231 if (xcoff_sym_ref.getNumberOfAuxEntries() != 1)
232 continue;
233
234 auto aux_csect_or_err = xcoff_sym_ref.getXCOFFCsectAuxRef();
235 if (!aux_csect_or_err) {
236 LLDB_LOG_ERROR(log, aux_csect_or_err.takeError(),
237 "Unable to access xcoff csect aux ref object");
238 continue;
239 }
240
241 const llvm::object::XCOFFCsectAuxRef csect_aux = aux_csect_or_err.get();
242
243 // Only add hidden ext entries which come under Program Code, skip others
244 // as they are not useful as debugging data.
245 if (csect_aux.getStorageMappingClass() != XCOFF::XMC_PR)
246 continue;
247
248 // This does not apply to 32-bit,
249 // Only add csect symbols identified by the aux entry, as they are
250 // needed to reference section information. Skip others
251 if (m_binary->is64Bit())
252 if (csect_aux.getAuxType64() != XCOFF::AUX_CSECT)
253 continue;
254 }
255
256 Symbol symbol;
257 symbol.GetMangled().SetValue(ConstString(name_no_dot));
258
259 int16_t sectionNumber = xcoff_sym_ref.getSectionNumber();
260 // Note that XCOFF section headers are numbered from 1 and not 0.
261 size_t sectionIndex = static_cast<size_t>(sectionNumber - 1);
262 if (sectionNumber > 0) {
263 if (sectionIndex < sectionList->GetSize()) {
264
265 lldb::SectionSP section_sp =
266 sectionList->GetSectionAtIndex(sectionIndex);
267 if (!section_sp || section_sp->GetFileAddress() == LLDB_INVALID_ADDRESS)
268 continue;
269
270 lldb::addr_t file_addr = section_sp->GetFileAddress();
271 lldb::addr_t symbolValue = xcoff_sym_ref.getValue();
272 if (symbolValue < file_addr)
273 continue;
274
275 symbol.GetAddressRef() = Address(section_sp, symbolValue - file_addr);
276 }
277 }
278
279 Expected<llvm::object::SymbolRef::Type> sym_type_or_err =
280 symbol_ref.getType();
281 if (!sym_type_or_err) {
282 LLDB_LOG_ERROR(log, sym_type_or_err.takeError(),
283 "Unable to access xcoff symbol type");
284 continue;
285 }
286
287 symbol.SetType(MapSymbolType(sym_type_or_err.get()));
288
289 lldb_symtab.AddSymbol(symbol);
290 }
291}
292
293bool ObjectFileXCOFF::IsStripped() { return false; }
294
295void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {
296
297 if (m_sections_up)
298 return;
299
300 m_sections_up = std::make_unique<SectionList>();
301 if (m_binary->is64Bit())
302 CreateSectionsWithBitness<XCOFF64>(unified_section_list);
303 else
304 CreateSectionsWithBitness<XCOFF32>(unified_section_list);
305}
306
307template <typename T>
308static auto GetSections(llvm::object::XCOFFObjectFile *binary) {
309 if constexpr (T::Is64Bit)
310 return binary->sections64();
311 else
312 return binary->sections32();
313}
314
315template <typename T>
317 SectionList &unified_section_list) {
318 ModuleSP module_sp(GetModule());
319 if (!module_sp)
320 return;
321
322 std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
323
324 int idx = 0;
325 for (const typename T::SectionHeader &section :
326 GetSections<T>(m_binary.get())) {
327
328 ConstString const_sect_name(section.Name);
329
331 if (section.Flags & XCOFF::STYP_TEXT)
332 section_type = eSectionTypeCode;
333 else if (section.Flags & XCOFF::STYP_DATA)
334 section_type = eSectionTypeData;
335 else if (section.Flags & XCOFF::STYP_BSS)
336 section_type = eSectionTypeZeroFill;
337 else if (section.Flags & XCOFF::STYP_DWARF) {
338 section_type = llvm::StringSwitch<SectionType>(section.Name)
339 .Case(".dwinfo", eSectionTypeDWARFDebugInfo)
340 .Case(".dwline", eSectionTypeDWARFDebugLine)
341 .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev)
342 .Case(".dwrnges", eSectionTypeDWARFDebugRanges)
343 .Default(eSectionTypeInvalid);
344 }
345
346 SectionSP section_sp(new Section(
347 module_sp, this, ++idx, const_sect_name, section_type,
348 section.VirtualAddress, section.SectionSize,
349 section.FileOffsetToRawData, section.SectionSize, 0, section.Flags));
350
351 uint32_t permissions = ePermissionsReadable;
352 if (section.Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS))
353 permissions |= ePermissionsWritable;
354 if (section.Flags & XCOFF::STYP_TEXT)
355 permissions |= ePermissionsExecutable;
356
357 section_sp->SetPermissions(permissions);
358 m_sections_up->AddSection(section_sp);
359 unified_section_list.AddSection(section_sp);
360 }
361}
362
364
366 ArchSpec arch_spec =
367 ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);
368 return arch_spec;
369}
370
372
374
376
377 const auto flags = m_binary->is64Bit() ? m_binary->fileHeader64()->Flags
378 : m_binary->fileHeader32()->Flags;
379
380 if (flags & XCOFF::F_EXEC)
381 return eTypeExecutable;
382 else if (flags & XCOFF::F_SHROBJ)
383 return eTypeSharedLibrary;
384 return eTypeUnknown;
385}
386
388
391 uint64_t Offset) {
393 Offset);
394}
395
397 DataBufferSP data_sp,
398 lldb::offset_t data_offset,
399 const FileSpec *file,
400 lldb::offset_t file_offset,
401 lldb::offset_t length)
402 : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) {
403 if (file)
404 m_file = *file;
405}
406
408 DataBufferSP header_data_sp,
409 const lldb::ProcessSP &process_sp,
410 addr_t header_addr)
411 : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:369
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:392
static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type)
static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic)
static auto GetSections(llvm::object::XCOFFObjectFile *binary)
#define LLDB_PLUGIN_DEFINE(PluginName)
Generic XCOFF object file reader.
ObjectFile::Type CalculateType() override
The object file should be able to calculate its type by looking at its file header and possibly the s...
bool ParseHeader() override
Attempts to parse the object header.
uint32_t GetAddressByteSize() const override
Gets the address size in bytes for the current object file.
static lldb::WritableDataBufferSP MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, uint64_t Offset)
lldb_private::ArchSpec GetArchitecture() override
Get the ArchSpec for this object file.
uint32_t GetDependentModules(lldb_private::FileSpecList &files) override
Extract the dependent modules from an object file.
void ParseSymtab(lldb_private::Symtab &symtab) override
Parse the symbol table into the provides symbol table object.
static llvm::StringRef GetPluginNameStatic()
ObjectFile::Strata CalculateStrata() override
The object file should be able to calculate the strata of the object file.
static lldb_private::ObjectFile * CreateMemoryInstance(const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header_addr)
static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, lldb_private::ModuleSpecList &specs)
static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, lldb::addr_t length)
lldb::ByteOrder GetByteOrder() const override
Gets whether endian swapping should occur when extracting data from this object file.
void CreateSections(lldb_private::SectionList &unified_section_list) override
lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override
Get the address type given a file address in an object file.
static llvm::StringRef GetPluginDescriptionStatic()
static void Initialize()
bool IsExecutable() const override
Tells whether this object file is capable of being the main executable for a process.
lldb_private::UUID GetUUID() override
Gets the UUID for this object file.
ObjectFileXCOFF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, lldb::offset_t offset, lldb::offset_t length)
void CreateSectionsWithBitness(lldb_private::SectionList &unified_section_list)
static void Terminate()
static lldb_private::ObjectFile * CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length)
bool IsStripped() override
Detect if this object file has been stripped of local symbols.
void Dump(lldb_private::Stream *s) override
Dump a description of this object to a Stream.
std::unique_ptr< llvm::object::XCOFFObjectFile > m_binary
A section + offset based address class.
Definition Address.h:62
An architecture specification class.
Definition ArchSpec.h:31
bool SetArchitecture(ArchitectureType arch_type, uint32_t cpu, uint32_t sub, uint32_t os=0)
Change the architecture object type, CPU type and OS type.
Definition ArchSpec.cpp:845
A uniqued constant string class.
Definition ConstString.h:40
An data extractor class.
void SetByteOrder(lldb::ByteOrder byte_order)
Set the byte_order value.
uint16_t GetU16(lldb::offset_t *offset_ptr) const
Extract a uint16_t value from *offset_ptr.
lldb::offset_t SetData(const void *bytes, lldb::offset_t length, lldb::ByteOrder byte_order)
Set data with a buffer that is caller owned.
A file collection class.
A file utility class.
Definition FileSpec.h:57
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:374
std::shared_ptr< WritableDataBuffer > CreateWritableDataBuffer(const llvm::Twine &path, uint64_t size=0, uint64_t offset=0)
static FileSystem & Instance()
void SetValue(ConstString name)
Set the string value in this object.
Definition Mangled.cpp:124
lldb::ModuleSP GetModule() const
Get const accessor for the module pointer.
void Append(const ModuleSpec &spec)
Definition ModuleSpec.h:308
ArchSpec & GetArchitecture()
Definition ModuleSpec.h:89
DataExtractor m_data
The data for this object file so things can be parsed lazily.
Definition ObjectFile.h:784
std::unique_ptr< lldb_private::SectionList > m_sections_up
Definition ObjectFile.h:788
static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size, uint64_t Offset)
ObjectFile(const lldb::ModuleSP &module_sp, const FileSpec *file_spec_ptr, lldb::offset_t file_offset, lldb::offset_t length, lldb::DataBufferSP data_sp, lldb::offset_t data_offset)
Construct with a parent module, offset, and header data.
@ eTypeExecutable
A normal executable.
Definition ObjectFile.h:54
@ eTypeSharedLibrary
A shared library that can be used during execution.
Definition ObjectFile.h:62
virtual SectionList * GetSectionList(bool update_module_section_list=true)
Gets the section list for the currently selected architecture (and object for archives).
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
size_t AddSection(const lldb::SectionSP &section_sp)
Definition Section.cpp:482
lldb::SectionSP GetSectionAtIndex(size_t idx) const
Definition Section.cpp:551
A stream class that can stream formatted output to a file.
Definition Stream.h:28
void SetType(lldb::SymbolType type)
Definition Symbol.h:171
Mangled & GetMangled()
Definition Symbol.h:147
Address & GetAddressRef()
Definition Symbol.h:73
uint32_t AddSymbol(const Symbol &symbol)
Definition Symtab.cpp:64
Represents UUID's of various sizes.
Definition UUID.h:27
#define LLDB_INVALID_CPUTYPE
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
uint64_t offset_t
Definition lldb-types.h:85
std::shared_ptr< lldb_private::Process > ProcessSP
SymbolType
Symbol types.
@ eSymbolTypeSourceFile
ByteOrder
Byte ordering definitions.
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::Section > SectionSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
@ eSectionTypeInvalid
@ eSectionTypeZeroFill
@ eSectionTypeDWARFDebugInfo
@ eSectionTypeDWARFDebugRanges
@ eSectionTypeDWARFDebugLine
@ eSectionTypeDWARFDebugAbbrev
std::shared_ptr< lldb_private::Module > ModuleSP