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