[Go to site: main page, start]

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::GetMagicBytes(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());
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 file_offset, lldb::offset_t length) {
132 if (!extractor_sp || !extractor_sp->HasData())
133 return {};
134
135 ModuleSpecList specs;
136 if (auto magic = ObjectFileXCOFF::GetMagicBytes(
137 extractor_sp, 0, extractor_sp->GetByteSize())) {
138 const uint32_t cpu_type =
139 (*magic == XCOFF::XCOFF64) ? XCOFF::TCPU_PPC64 : XCOFF::TCPU_PPC;
140 ArchSpec arch_spec =
142 ModuleSpec spec(file, arch_spec);
144 eArchTypeXCOFF, cpu_type, LLDB_INVALID_CPUTYPE, llvm::Triple::AIX);
145 specs.Append(spec);
146 }
147 return specs;
148}
149
150std::optional<XCOFF::MagicNumber>
152 lldb::addr_t data_offset,
153 lldb::addr_t data_length) {
154 DataExtractorSP magic_extractor_sp =
155 extractor_sp->GetSubsetExtractorSP(data_offset);
156 // Need to set this as XCOFF is only compatible with Big Endian
157 magic_extractor_sp->SetByteOrder(eByteOrderBig);
158 lldb::offset_t offset = 0;
159 uint16_t magic = magic_extractor_sp->GetU16(&offset);
160 // Validating magic
161 if (magic == XCOFF::XCOFF64 || magic == XCOFF::XCOFF32)
162 return static_cast<llvm::XCOFF::MagicNumber>(magic);
163
164 return std::nullopt;
165}
166
168 if (m_binary->is64Bit())
169 return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64;
170 return m_binary->fileHeader32()->Magic == XCOFF::XCOFF32;
171}
172
174
175bool ObjectFileXCOFF::IsExecutable() const { return true; }
176
178 if (m_binary->is64Bit())
179 return 8;
180 return 4;
181}
182
186
187static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type) {
188 switch (sym_type) {
189 case llvm::object::SymbolRef::ST_Function:
191 case llvm::object::SymbolRef::ST_Data:
193 case llvm::object::SymbolRef::ST_File:
195 default:
197 }
198}
199
201 Log *log = GetLog(LLDBLog::Object);
202 SectionList *sectionList = GetSectionList();
203
204 for (const auto &symbol_ref : m_binary->symbols()) {
205 llvm::object::XCOFFSymbolRef xcoff_sym_ref(symbol_ref);
206
207 llvm::Expected<llvm::StringRef> name_or_err = xcoff_sym_ref.getName();
208 if (!name_or_err) {
210 log, name_or_err.takeError(),
211 "Unable to extract name from the xcoff symbol ref object: {0}");
212 continue;
213 }
214
215 llvm::StringRef symbolName = name_or_err.get();
216 // Remove the . prefix added during compilation. This prefix is usually
217 // added to differentiate between reference to the code and function
218 // descriptor. For instance, Adding .func will only allow user to put bp on
219 // .func, which is not known to the user, instead of func.
220 llvm::StringRef name_no_dot =
221 symbolName.starts_with(".") ? symbolName.drop_front() : symbolName;
222 auto storageClass = xcoff_sym_ref.getStorageClass();
223 // C_HIDEXT symbols are not needed to be exposed, with the exception of TOC
224 // which is responsible for storing references to global data
225 if (storageClass == XCOFF::C_HIDEXT && symbolName != "TOC") {
226
227 // Zero or muliple aux entries may suggest ambiguous data
228 if (xcoff_sym_ref.getNumberOfAuxEntries() != 1)
229 continue;
230
231 auto aux_csect_or_err = xcoff_sym_ref.getXCOFFCsectAuxRef();
232 if (!aux_csect_or_err) {
233 LLDB_LOG_ERROR(log, aux_csect_or_err.takeError(),
234 "Unable to access xcoff csect aux ref object: {0}");
235 continue;
236 }
237
238 const llvm::object::XCOFFCsectAuxRef csect_aux = aux_csect_or_err.get();
239
240 // Only add hidden ext entries which come under Program Code, skip others
241 // as they are not useful as debugging data.
242 if (csect_aux.getStorageMappingClass() != XCOFF::XMC_PR)
243 continue;
244
245 // This does not apply to 32-bit,
246 // Only add csect symbols identified by the aux entry, as they are
247 // needed to reference section information. Skip others
248 if (m_binary->is64Bit())
249 if (csect_aux.getAuxType64() != XCOFF::AUX_CSECT)
250 continue;
251 }
252
253 Symbol symbol;
254 symbol.GetMangled().SetValue(ConstString(name_no_dot));
255
256 int16_t sectionNumber = xcoff_sym_ref.getSectionNumber();
257 // Note that XCOFF section headers are numbered from 1 and not 0.
258 size_t sectionIndex = static_cast<size_t>(sectionNumber - 1);
259 if (sectionNumber > 0) {
260 if (sectionIndex < sectionList->GetSize()) {
261
262 lldb::SectionSP section_sp =
263 sectionList->GetSectionAtIndex(sectionIndex);
264 if (!section_sp || section_sp->GetFileAddress() == LLDB_INVALID_ADDRESS)
265 continue;
266
267 lldb::addr_t file_addr = section_sp->GetFileAddress();
268 lldb::addr_t symbolValue = xcoff_sym_ref.getValue();
269 if (symbolValue < file_addr)
270 continue;
271
272 symbol.GetAddressRef() = Address(section_sp, symbolValue - file_addr);
273 }
274 }
275
276 Expected<llvm::object::SymbolRef::Type> sym_type_or_err =
277 symbol_ref.getType();
278 if (!sym_type_or_err) {
279 LLDB_LOG_ERROR(log, sym_type_or_err.takeError(),
280 "Unable to access xcoff symbol type: {0}");
281 continue;
282 }
283
284 symbol.SetType(MapSymbolType(sym_type_or_err.get()));
285
286 lldb_symtab.AddSymbol(symbol);
287 }
288}
289
290bool ObjectFileXCOFF::IsStripped() { return false; }
291
292void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {
293
294 if (m_sections_up)
295 return;
296
297 m_sections_up = std::make_unique<SectionList>();
298 if (m_binary->is64Bit())
299 CreateSectionsWithBitness<XCOFF64>(unified_section_list);
300 else
301 CreateSectionsWithBitness<XCOFF32>(unified_section_list);
302}
303
304template <typename T>
305static auto GetSections(llvm::object::XCOFFObjectFile *binary) {
306 if constexpr (T::Is64Bit)
307 return binary->sections64();
308 else
309 return binary->sections32();
310}
311
312template <typename T>
314 SectionList &unified_section_list) {
315 ModuleSP module_sp(GetModule());
316 if (!module_sp)
317 return;
318
319 std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
320
321 int idx = 0;
322 for (const typename T::SectionHeader &section :
323 GetSections<T>(m_binary.get())) {
324
325 ConstString const_sect_name(section.Name);
326
328 if (section.Flags & XCOFF::STYP_TEXT)
329 section_type = eSectionTypeCode;
330 else if (section.Flags & XCOFF::STYP_DATA)
331 section_type = eSectionTypeData;
332 else if (section.Flags & XCOFF::STYP_BSS)
333 section_type = eSectionTypeZeroFill;
334 else if (section.Flags & XCOFF::STYP_DWARF) {
335 section_type = llvm::StringSwitch<SectionType>(section.Name)
336 .Case(".dwinfo", eSectionTypeDWARFDebugInfo)
337 .Case(".dwline", eSectionTypeDWARFDebugLine)
338 .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev)
339 .Case(".dwrnges", eSectionTypeDWARFDebugRanges)
340 .Default(eSectionTypeInvalid);
341 }
342
343 SectionSP section_sp = std::make_shared<Section>(
344 module_sp, this, ++idx, const_sect_name, section_type,
345 section.VirtualAddress, section.SectionSize,
346 section.FileOffsetToRawData, section.SectionSize, 0, section.Flags);
347
348 uint32_t permissions = ePermissionsReadable;
349 if (section.Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS))
350 permissions |= ePermissionsWritable;
351 if (section.Flags & XCOFF::STYP_TEXT)
352 permissions |= ePermissionsExecutable;
353
354 section_sp->SetPermissions(permissions);
355 m_sections_up->AddSection(section_sp);
356 unified_section_list.AddSection(section_sp);
357 }
358}
359
361
363 const uint32_t cpu_type =
364 m_binary->is64Bit() ? XCOFF::TCPU_PPC64 : XCOFF::TCPU_PPC;
365 return (ArchSpec(eArchTypeXCOFF, cpu_type, LLDB_INVALID_CPUTYPE));
366}
367
369
371
373
374 const auto flags = m_binary->is64Bit() ? m_binary->fileHeader64()->Flags
375 : m_binary->fileHeader32()->Flags;
376
377 if (flags & XCOFF::F_EXEC)
378 return eTypeExecutable;
379 else if (flags & XCOFF::F_SHROBJ)
380 return eTypeSharedLibrary;
381 return eTypeUnknown;
382}
383
385
388 uint64_t Offset) {
390 Offset);
391}
392
394 DataExtractorSP extractor_sp,
395 lldb::offset_t data_offset,
396 const FileSpec *file,
397 lldb::offset_t file_offset,
398 lldb::offset_t length)
399 : ObjectFile(module_sp, file, file_offset, length, extractor_sp,
400 data_offset) {
401 if (file)
402 m_file = *file;
403}
404
406 DataBufferSP header_data_sp,
407 const lldb::ProcessSP &process_sp,
408 addr_t header_addr)
409 : ObjectFile(
410 module_sp, process_sp, header_addr,
411 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:375
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:405
static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type)
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()
static std::optional< llvm::XCOFF::MagicNumber > GetMagicBytes(lldb::DataExtractorSP &extractor_sp, lldb::addr_t offset, lldb::addr_t length)
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.
static lldb_private::ModuleSpecList GetModuleSpecifications(const lldb_private::FileSpec &file, lldb::DataExtractorSP &extractor_sp, lldb::offset_t file_offset, lldb::offset_t length)
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:32
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.
A uniqued constant string class.
Definition ConstString.h:40
An data extractor class.
A file collection class.
A file utility class.
Definition FileSpec.h:56
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:380
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:371
ArchSpec & GetArchitecture()
Definition ModuleSpec.h:93
std::unique_ptr< lldb_private::SectionList > m_sections_up
Definition ObjectFile.h:779
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:771
@ 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:483
lldb::SectionSP GetSectionAtIndex(size_t idx) const
Definition Section.cpp:555
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:61
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:338
uint64_t offset_t
Definition lldb-types.h:86
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