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"
25#include "lldb/Utility/Log.h"
27#include "lldb/Utility/Status.h"
28#include "lldb/Utility/Stream.h"
29#include "llvm/ADT/StringRef.h"
30#include "llvm/BinaryFormat/XCOFF.h"
31#include "llvm/Object/XCOFFObjectFile.h"
32#include "llvm/Support/MemoryBuffer.h"
33#include <algorithm>
34#include <cassert>
35#include <cstring>
36#include <unordered_map>
37
38using namespace llvm;
39using namespace lldb;
40using namespace lldb_private;
41
43// FIXME: target 64bit at this moment.
44
45// Static methods.
51
55
57 DataExtractorSP extractor_sp,
58 lldb::offset_t data_offset,
59 const lldb_private::FileSpec *file,
60 lldb::offset_t file_offset,
61 lldb::offset_t length) {
62 if (!extractor_sp || !extractor_sp->HasData()) {
63 DataBufferSP data_sp = MapFileData(*file, length, file_offset);
64 if (!data_sp)
65 return nullptr;
66 data_offset = 0;
67 extractor_sp = std::make_shared<lldb_private::DataExtractor>(data_sp);
68 }
69 if (!ObjectFileXCOFF::MagicBytesMatch(extractor_sp->GetSharedDataBuffer(),
70 data_offset, length))
71 return nullptr;
72 // Update the data to contain the entire file if it doesn't already
73 if (extractor_sp->GetByteSize() < length) {
74 DataBufferSP data_sp = MapFileData(*file, length, file_offset);
75 if (!data_sp)
76 return nullptr;
77 data_offset = 0;
78 extractor_sp = std::make_shared<lldb_private::DataExtractor>(data_sp);
79 }
80 auto objfile_up = std::make_unique<ObjectFileXCOFF>(
81 module_sp, extractor_sp, data_offset, file, file_offset, length);
82 if (!objfile_up)
83 return nullptr;
84
85 // Cache xcoff binary.
86 if (!objfile_up->CreateBinary())
87 return nullptr;
88
89 if (!objfile_up->ParseHeader())
90 return nullptr;
91
92 return objfile_up.release();
93}
94
96 if (m_binary)
97 return true;
98
100
101 auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data_nsp->GetData()),
102 m_file.GetFilename().GetStringRef());
103 llvm::file_magic magic = llvm::identify_magic(memory_ref.getBuffer());
104
105 auto binary = llvm::object::ObjectFile::createObjectFile(memory_ref, magic);
106 if (!binary) {
107 LLDB_LOG_ERROR(log, binary.takeError(),
108 "Failed to create binary for file ({1}): {0}", m_file);
109 return false;
110 }
111 // Make sure we only handle XCOFF format.
112 m_binary =
113 llvm::unique_dyn_cast<llvm::object::XCOFFObjectFile>(std::move(*binary));
114 if (!m_binary)
115 return false;
116
117 LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",
118 this, GetModule().get(), GetModule()->GetSpecificationDescription(),
119 m_file.GetPath(), m_binary.get());
120
121 return true;
122}
123
125 const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp,
126 const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
127 return nullptr;
128}
129
131 const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
132 lldb::offset_t data_offset, lldb::offset_t file_offset,
134 const size_t initial_count = specs.GetSize();
135
136 if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {
137 ArchSpec arch_spec =
138 ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);
139 ModuleSpec spec(file, arch_spec);
140 spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64,
142 llvm::Triple::AIX);
143 specs.Append(spec);
144 }
145 return specs.GetSize() - initial_count;
146}
147
148static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) {
149 switch (magic) {
150 case XCOFF::XCOFF32:
151 return sizeof(struct llvm::object::XCOFFFileHeader32);
152 break;
153 case XCOFF::XCOFF64:
154 return sizeof(struct llvm::object::XCOFFFileHeader64);
155 break;
156
157 default:
158 break;
159 }
160 return 0;
161}
162
164 lldb::addr_t data_offset,
165 lldb::addr_t data_length) {
167 extractor.SetData(data_sp, data_offset, data_length);
168 // Need to set this as XCOFF is only compatible with Big Endian
169 extractor.SetByteOrder(eByteOrderBig);
170 lldb::offset_t offset = 0;
171 uint16_t magic = extractor.GetU16(&offset);
172 return XCOFFHeaderSizeFromMagic(magic) != 0;
173}
174
176 if (m_binary->is64Bit())
177 return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64;
178 return m_binary->fileHeader32()->Magic == XCOFF::XCOFF32;
179}
180
182
183bool ObjectFileXCOFF::IsExecutable() const { return true; }
184
186 if (m_binary->is64Bit())
187 return 8;
188 return 4;
189}
190
194
195static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type) {
196 switch (sym_type) {
197 case llvm::object::SymbolRef::ST_Function:
199 case llvm::object::SymbolRef::ST_Data:
201 case llvm::object::SymbolRef::ST_File:
203 default:
205 }
206}
207
209 Log *log = GetLog(LLDBLog::Object);
210 SectionList *sectionList = GetSectionList();
211
212 for (const auto &symbol_ref : m_binary->symbols()) {
213 llvm::object::XCOFFSymbolRef xcoff_sym_ref(symbol_ref);
214
215 llvm::Expected<llvm::StringRef> name_or_err = xcoff_sym_ref.getName();
216 if (!name_or_err) {
217 LLDB_LOG_ERROR(log, name_or_err.takeError(),
218 "Unable to extract name from the xcoff symbol ref object");
219 continue;
220 }
221
222 llvm::StringRef symbolName = name_or_err.get();
223 // Remove the . prefix added during compilation. This prefix is usually
224 // added to differentiate between reference to the code and function
225 // descriptor. For instance, Adding .func will only allow user to put bp on
226 // .func, which is not known to the user, instead of func.
227 llvm::StringRef name_no_dot =
228 symbolName.starts_with(".") ? symbolName.drop_front() : symbolName;
229 auto storageClass = xcoff_sym_ref.getStorageClass();
230 // C_HIDEXT symbols are not needed to be exposed, with the exception of TOC
231 // which is responsible for storing references to global data
232 if (storageClass == XCOFF::C_HIDEXT && symbolName != "TOC") {
233
234 // Zero or muliple aux entries may suggest ambiguous data
235 if (xcoff_sym_ref.getNumberOfAuxEntries() != 1)
236 continue;
237
238 auto aux_csect_or_err = xcoff_sym_ref.getXCOFFCsectAuxRef();
239 if (!aux_csect_or_err) {
240 LLDB_LOG_ERROR(log, aux_csect_or_err.takeError(),
241 "Unable to access xcoff csect aux ref object");
242 continue;
243 }
244
245 const llvm::object::XCOFFCsectAuxRef csect_aux = aux_csect_or_err.get();
246
247 // Only add hidden ext entries which come under Program Code, skip others
248 // as they are not useful as debugging data.
249 if (csect_aux.getStorageMappingClass() != XCOFF::XMC_PR)
250 continue;
251
252 // This does not apply to 32-bit,
253 // Only add csect symbols identified by the aux entry, as they are
254 // needed to reference section information. Skip others
255 if (m_binary->is64Bit())
256 if (csect_aux.getAuxType64() != XCOFF::AUX_CSECT)
257 continue;
258 }
259
260 Symbol symbol;
261 symbol.GetMangled().SetValue(ConstString(name_no_dot));
262
263 int16_t sectionNumber = xcoff_sym_ref.getSectionNumber();
264 // Note that XCOFF section headers are numbered from 1 and not 0.
265 size_t sectionIndex = static_cast<size_t>(sectionNumber - 1);
266 if (sectionNumber > 0) {
267 if (sectionIndex < sectionList->GetSize()) {
268
269 lldb::SectionSP section_sp =
270 sectionList->GetSectionAtIndex(sectionIndex);
271 if (!section_sp || section_sp->GetFileAddress() == LLDB_INVALID_ADDRESS)
272 continue;
273
274 lldb::addr_t file_addr = section_sp->GetFileAddress();
275 lldb::addr_t symbolValue = xcoff_sym_ref.getValue();
276 if (symbolValue < file_addr)
277 continue;
278
279 symbol.GetAddressRef() = Address(section_sp, symbolValue - file_addr);
280 }
281 }
282
283 Expected<llvm::object::SymbolRef::Type> sym_type_or_err =
284 symbol_ref.getType();
285 if (!sym_type_or_err) {
286 LLDB_LOG_ERROR(log, sym_type_or_err.takeError(),
287 "Unable to access xcoff symbol type");
288 continue;
289 }
290
291 symbol.SetType(MapSymbolType(sym_type_or_err.get()));
292
293 lldb_symtab.AddSymbol(symbol);
294 }
295}
296
297bool ObjectFileXCOFF::IsStripped() { return false; }
298
299void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {
300
301 if (m_sections_up)
302 return;
303
304 m_sections_up = std::make_unique<SectionList>();
305 if (m_binary->is64Bit())
306 CreateSectionsWithBitness<XCOFF64>(unified_section_list);
307 else
308 CreateSectionsWithBitness<XCOFF32>(unified_section_list);
309}
310
311template <typename T>
312static auto GetSections(llvm::object::XCOFFObjectFile *binary) {
313 if constexpr (T::Is64Bit)
314 return binary->sections64();
315 else
316 return binary->sections32();
317}
318
319template <typename T>
321 SectionList &unified_section_list) {
322 ModuleSP module_sp(GetModule());
323 if (!module_sp)
324 return;
325
326 std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
327
328 int idx = 0;
329 for (const typename T::SectionHeader &section :
330 GetSections<T>(m_binary.get())) {
331
332 ConstString const_sect_name(section.Name);
333
335 if (section.Flags & XCOFF::STYP_TEXT)
336 section_type = eSectionTypeCode;
337 else if (section.Flags & XCOFF::STYP_DATA)
338 section_type = eSectionTypeData;
339 else if (section.Flags & XCOFF::STYP_BSS)
340 section_type = eSectionTypeZeroFill;
341 else if (section.Flags & XCOFF::STYP_DWARF) {
342 section_type = llvm::StringSwitch<SectionType>(section.Name)
343 .Case(".dwinfo", eSectionTypeDWARFDebugInfo)
344 .Case(".dwline", eSectionTypeDWARFDebugLine)
345 .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev)
346 .Case(".dwrnges", eSectionTypeDWARFDebugRanges)
347 .Default(eSectionTypeInvalid);
348 }
349
350 SectionSP section_sp(new Section(
351 module_sp, this, ++idx, const_sect_name, section_type,
352 section.VirtualAddress, section.SectionSize,
353 section.FileOffsetToRawData, section.SectionSize, 0, section.Flags));
354
355 uint32_t permissions = ePermissionsReadable;
356 if (section.Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS))
357 permissions |= ePermissionsWritable;
358 if (section.Flags & XCOFF::STYP_TEXT)
359 permissions |= ePermissionsExecutable;
360
361 section_sp->SetPermissions(permissions);
362 m_sections_up->AddSection(section_sp);
363 unified_section_list.AddSection(section_sp);
364 }
365}
366
368
370 ArchSpec arch_spec =
371 ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);
372 return arch_spec;
373}
374
376
378
380
381 const auto flags = m_binary->is64Bit() ? m_binary->fileHeader64()->Flags
382 : m_binary->fileHeader32()->Flags;
383
384 if (flags & XCOFF::F_EXEC)
385 return eTypeExecutable;
386 else if (flags & XCOFF::F_SHROBJ)
387 return eTypeSharedLibrary;
388 return eTypeUnknown;
389}
390
392
395 uint64_t Offset) {
397 Offset);
398}
399
401 DataExtractorSP extractor_sp,
402 lldb::offset_t data_offset,
403 const FileSpec *file,
404 lldb::offset_t file_offset,
405 lldb::offset_t length)
406 : ObjectFile(module_sp, file, file_offset, length, extractor_sp,
407 data_offset) {
408 if (file)
409 m_file = *file;
410}
411
413 DataBufferSP header_data_sp,
414 const lldb::ProcessSP &process_sp,
415 addr_t header_addr)
416 : ObjectFile(
417 module_sp, process_sp, header_addr,
418 std::make_shared<lldb_private::DataExtractor>(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()
static lldb_private::ObjectFile * CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length)
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.
void CreateSectionsWithBitness(lldb_private::SectionList &unified_section_list)
static void Terminate()
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.
ObjectFileXCOFF(const lldb::ModuleSP &module_sp, lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, lldb::offset_t offset, lldb::offset_t length)
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:326
ArchSpec & GetArchitecture()
Definition ModuleSpec.h:91
std::unique_ptr< lldb_private::SectionList > m_sections_up
Definition ObjectFile.h:799
static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size, uint64_t Offset)
DataExtractorNSP m_data_nsp
The data for this object file so things can be parsed lazily.
Definition ObjectFile.h:792
@ eTypeExecutable
A normal executable.
Definition ObjectFile.h:55
@ eTypeSharedLibrary
A shared library that can be used during execution.
Definition ObjectFile.h:63
virtual SectionList * GetSectionList(bool update_module_section_list=true)
Gets the section list for the currently selected architecture (and object for archives).
ObjectFile(const lldb::ModuleSP &module_sp, const FileSpec *file_spec_ptr, lldb::offset_t file_offset, lldb::offset_t length, lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset)
Construct with a parent module, offset, and header data.
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:488
lldb::SectionSP GetSectionAtIndex(size_t idx) const
Definition Section.cpp:557
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::DataExtractor > DataExtractorSP
std::shared_ptr< lldb_private::Module > ModuleSP