1 //===-- ObjectFilePECOFF.cpp ----------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "ObjectFilePECOFF.h"
10 #include "PECallFrameInfo.h"
11 #include "WindowsMiniDump.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/ModuleSpec.h"
15 #include "lldb/Core/PluginManager.h"
16 #include "lldb/Core/Section.h"
17 #include "lldb/Interpreter/OptionValueDictionary.h"
18 #include "lldb/Interpreter/OptionValueProperties.h"
19 #include "lldb/Symbol/ObjectFile.h"
20 #include "lldb/Symbol/SaveCoreOptions.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/SectionLoadList.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Utility/ArchSpec.h"
25 #include "lldb/Utility/DataBufferHeap.h"
26 #include "lldb/Utility/FileSpec.h"
27 #include "lldb/Utility/FileSpecList.h"
28 #include "lldb/Utility/LLDBLog.h"
29 #include "lldb/Utility/Log.h"
30 #include "lldb/Utility/StreamString.h"
31 #include "lldb/Utility/Timer.h"
32 #include "lldb/Utility/UUID.h"
34 #include "llvm/BinaryFormat/COFF.h"
35 #include "llvm/Object/COFFImportFile.h"
36 #include "llvm/Support/CRC.h"
37 #include "llvm/Support/Error.h"
38 #include "llvm/Support/FormatAdapters.h"
39 #include "llvm/Support/MemoryBuffer.h"
40 #include "llvm/TargetParser/Host.h"
43 #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
44 #define IMAGE_NT_SIGNATURE 0x00004550 // PE00
45 #define OPT_HEADER_MAGIC_PE32 0x010b
46 #define OPT_HEADER_MAGIC_PE32_PLUS 0x020b
49 using namespace lldb_private
;
51 LLDB_PLUGIN_DEFINE(ObjectFilePECOFF
)
55 static constexpr OptionEnumValueElement g_abi_enums
[] = {
57 llvm::Triple::UnknownEnvironment
,
59 "Use default target (if it is Windows) or MSVC",
69 "MinGW / Itanium ABI",
73 #define LLDB_PROPERTIES_objectfilepecoff
74 #include "ObjectFilePECOFFProperties.inc"
77 #define LLDB_PROPERTIES_objectfilepecoff
78 #include "ObjectFilePECOFFPropertiesEnum.inc"
81 class PluginProperties
: public Properties
{
83 static llvm::StringRef
GetSettingName() {
84 return ObjectFilePECOFF::GetPluginNameStatic();
88 m_collection_sp
= std::make_shared
<OptionValueProperties
>(GetSettingName());
89 m_collection_sp
->Initialize(g_objectfilepecoff_properties
);
92 llvm::Triple::EnvironmentType
ABI() const {
93 return GetPropertyAtIndexAs
<llvm::Triple::EnvironmentType
>(
94 ePropertyABI
, llvm::Triple::UnknownEnvironment
);
97 OptionValueDictionary
*ModuleABIMap() const {
98 return m_collection_sp
->GetPropertyAtIndexAsOptionValueDictionary(
99 ePropertyModuleABIMap
);
105 static PluginProperties
&GetGlobalPluginProperties() {
106 static PluginProperties g_settings
;
110 static bool GetDebugLinkContents(const llvm::object::COFFObjectFile
&coff_obj
,
111 std::string
&gnu_debuglink_file
,
112 uint32_t &gnu_debuglink_crc
) {
113 static ConstString
g_sect_name_gnu_debuglink(".gnu_debuglink");
114 for (const auto §ion
: coff_obj
.sections()) {
115 auto name
= section
.getName();
117 llvm::consumeError(name
.takeError());
120 if (*name
== g_sect_name_gnu_debuglink
.GetStringRef()) {
121 auto content
= section
.getContents();
123 llvm::consumeError(content
.takeError());
127 content
->data(), content
->size(),
128 coff_obj
.isLittleEndian() ? eByteOrderLittle
: eByteOrderBig
, 4);
129 lldb::offset_t gnu_debuglink_offset
= 0;
130 gnu_debuglink_file
= data
.GetCStr(&gnu_debuglink_offset
);
131 // Align to the next 4-byte offset
132 gnu_debuglink_offset
= llvm::alignTo(gnu_debuglink_offset
, 4);
133 data
.GetU32(&gnu_debuglink_offset
, &gnu_debuglink_crc
, 1);
140 static UUID
GetCoffUUID(llvm::object::COFFObjectFile
&coff_obj
) {
141 const llvm::codeview::DebugInfo
*pdb_info
= nullptr;
142 llvm::StringRef pdb_file
;
144 // First, prefer to use the PDB build id. LLD generates this even for mingw
145 // targets without PDB output, and it does not get stripped either.
146 if (!coff_obj
.getDebugPDBInfo(pdb_info
, pdb_file
) && pdb_info
) {
147 if (pdb_info
->PDB70
.CVSignature
== llvm::OMF::Signature::PDB70
) {
148 UUID::CvRecordPdb70 info
;
149 memcpy(&info
.Uuid
, pdb_info
->PDB70
.Signature
, sizeof(info
.Uuid
));
150 info
.Age
= pdb_info
->PDB70
.Age
;
155 std::string gnu_debuglink_file
;
156 uint32_t gnu_debuglink_crc
;
158 // The GNU linker normally does not write a PDB build id (unless requested
159 // with the --build-id option), so we should fall back to using the crc
160 // from .gnu_debuglink if it exists, just like how ObjectFileELF does it.
161 if (!GetDebugLinkContents(coff_obj
, gnu_debuglink_file
, gnu_debuglink_crc
)) {
162 // If there is no .gnu_debuglink section, then this may be an object
163 // containing DWARF debug info for .gnu_debuglink, so calculate the crc of
164 // the object itself.
165 auto raw_data
= coff_obj
.getData();
167 "Calculating module crc32 %s with size %" PRIu64
" KiB",
168 FileSpec(coff_obj
.getFileName()).GetFilename().AsCString(),
169 static_cast<lldb::offset_t
>(raw_data
.size()) / 1024);
170 gnu_debuglink_crc
= llvm::crc32(0, llvm::arrayRefFromStringRef(raw_data
));
172 // Use 4 bytes of crc from the .gnu_debuglink section.
173 llvm::support::ulittle32_t
data(gnu_debuglink_crc
);
174 return UUID(&data
, sizeof(data
));
177 char ObjectFilePECOFF::ID
;
179 void ObjectFilePECOFF::Initialize() {
180 PluginManager::RegisterPlugin(GetPluginNameStatic(),
181 GetPluginDescriptionStatic(), CreateInstance
,
182 CreateMemoryInstance
, GetModuleSpecifications
,
183 SaveCore
, DebuggerInitialize
);
186 void ObjectFilePECOFF::DebuggerInitialize(Debugger
&debugger
) {
187 if (!PluginManager::GetSettingForObjectFilePlugin(
188 debugger
, PluginProperties::GetSettingName())) {
189 const bool is_global_setting
= true;
190 PluginManager::CreateSettingForObjectFilePlugin(
191 debugger
, GetGlobalPluginProperties().GetValueProperties(),
192 "Properties for the PE/COFF object-file plug-in.", is_global_setting
);
196 void ObjectFilePECOFF::Terminate() {
197 PluginManager::UnregisterPlugin(CreateInstance
);
200 llvm::StringRef
ObjectFilePECOFF::GetPluginDescriptionStatic() {
201 return "Portable Executable and Common Object File Format object file reader "
205 ObjectFile
*ObjectFilePECOFF::CreateInstance(
206 const lldb::ModuleSP
&module_sp
, DataBufferSP data_sp
,
207 lldb::offset_t data_offset
, const lldb_private::FileSpec
*file_p
,
208 lldb::offset_t file_offset
, lldb::offset_t length
) {
209 FileSpec file
= file_p
? *file_p
: FileSpec();
211 data_sp
= MapFileData(file
, length
, file_offset
);
217 if (!ObjectFilePECOFF::MagicBytesMatch(data_sp
))
220 // Update the data to contain the entire file if it doesn't already
221 if (data_sp
->GetByteSize() < length
) {
222 data_sp
= MapFileData(file
, length
, file_offset
);
227 auto objfile_up
= std::make_unique
<ObjectFilePECOFF
>(
228 module_sp
, data_sp
, data_offset
, file_p
, file_offset
, length
);
229 if (!objfile_up
|| !objfile_up
->ParseHeader())
232 // Cache coff binary.
233 if (!objfile_up
->CreateBinary())
235 return objfile_up
.release();
238 ObjectFile
*ObjectFilePECOFF::CreateMemoryInstance(
239 const lldb::ModuleSP
&module_sp
, lldb::WritableDataBufferSP data_sp
,
240 const lldb::ProcessSP
&process_sp
, lldb::addr_t header_addr
) {
241 if (!data_sp
|| !ObjectFilePECOFF::MagicBytesMatch(data_sp
))
243 auto objfile_up
= std::make_unique
<ObjectFilePECOFF
>(
244 module_sp
, data_sp
, process_sp
, header_addr
);
245 if (objfile_up
.get() && objfile_up
->ParseHeader()) {
246 return objfile_up
.release();
251 size_t ObjectFilePECOFF::GetModuleSpecifications(
252 const lldb_private::FileSpec
&file
, lldb::DataBufferSP
&data_sp
,
253 lldb::offset_t data_offset
, lldb::offset_t file_offset
,
254 lldb::offset_t length
, lldb_private::ModuleSpecList
&specs
) {
255 const size_t initial_count
= specs
.GetSize();
256 if (!data_sp
|| !ObjectFilePECOFF::MagicBytesMatch(data_sp
))
257 return initial_count
;
259 Log
*log
= GetLog(LLDBLog::Object
);
261 if (data_sp
->GetByteSize() < length
)
262 if (DataBufferSP full_sp
= MapFileData(file
, -1, file_offset
))
263 data_sp
= std::move(full_sp
);
264 auto binary
= llvm::object::createBinary(llvm::MemoryBufferRef(
265 toStringRef(data_sp
->GetData()), file
.GetFilename().GetStringRef()));
268 LLDB_LOG_ERROR(log
, binary
.takeError(),
269 "Failed to create binary for file ({1}): {0}", file
);
270 return initial_count
;
273 auto *COFFObj
= llvm::dyn_cast
<llvm::object::COFFObjectFile
>(binary
->get());
275 return initial_count
;
277 ModuleSpec
module_spec(file
);
278 ArchSpec
&spec
= module_spec
.GetArchitecture();
279 lldb_private::UUID
&uuid
= module_spec
.GetUUID();
281 uuid
= GetCoffUUID(*COFFObj
);
283 static llvm::Triple::EnvironmentType default_env
= [] {
284 auto def_target
= llvm::Triple(
285 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()));
286 if (def_target
.getOS() == llvm::Triple::Win32
&&
287 def_target
.getEnvironment() != llvm::Triple::UnknownEnvironment
)
288 return def_target
.getEnvironment();
289 return llvm::Triple::MSVC
;
292 // Check for a module-specific override.
293 OptionValueSP module_env_option
;
294 const auto *map
= GetGlobalPluginProperties().ModuleABIMap();
295 if (map
->GetNumValues() > 0) {
296 // Step 1: Try with the exact file name.
297 auto name
= file
.GetFilename();
298 module_env_option
= map
->GetValueForKey(name
);
299 if (!module_env_option
) {
300 // Step 2: Try with the file name in lowercase.
301 auto name_lower
= name
.GetStringRef().lower();
302 module_env_option
= map
->GetValueForKey(llvm::StringRef(name_lower
));
304 if (!module_env_option
) {
305 // Step 3: Try with the file name with ".debug" suffix stripped.
306 auto name_stripped
= name
.GetStringRef();
307 if (name_stripped
.consume_back_insensitive(".debug")) {
308 module_env_option
= map
->GetValueForKey(name_stripped
);
309 if (!module_env_option
) {
310 // Step 4: Try with the file name in lowercase with ".debug" suffix
312 auto name_lower
= name_stripped
.lower();
313 module_env_option
= map
->GetValueForKey(llvm::StringRef(name_lower
));
318 llvm::Triple::EnvironmentType env
;
319 if (module_env_option
)
321 module_env_option
->GetValueAs
<llvm::Triple::EnvironmentType
>().value_or(
322 static_cast<llvm::Triple::EnvironmentType
>(0));
324 env
= GetGlobalPluginProperties().ABI();
326 if (env
== llvm::Triple::UnknownEnvironment
)
329 switch (COFFObj
->getMachine()) {
331 spec
.SetTriple("x86_64-pc-windows");
332 spec
.GetTriple().setEnvironment(env
);
333 specs
.Append(module_spec
);
336 spec
.SetTriple("i386-pc-windows");
337 spec
.GetTriple().setEnvironment(env
);
338 specs
.Append(module_spec
);
341 spec
.SetTriple("armv7-pc-windows");
342 spec
.GetTriple().setEnvironment(env
);
343 specs
.Append(module_spec
);
347 spec
.SetTriple("aarch64-pc-windows");
348 spec
.GetTriple().setEnvironment(env
);
349 specs
.Append(module_spec
);
355 return specs
.GetSize() - initial_count
;
358 bool ObjectFilePECOFF::SaveCore(const lldb::ProcessSP
&process_sp
,
359 lldb_private::SaveCoreOptions
&options
,
360 lldb_private::Status
&error
) {
361 // Outfile and process_sp are validated by PluginManager::SaveCore
362 assert(options
.GetOutputFile().has_value());
364 return SaveMiniDump(process_sp
, options
, error
);
367 bool ObjectFilePECOFF::MagicBytesMatch(DataBufferSP data_sp
) {
368 DataExtractor
data(data_sp
, eByteOrderLittle
, 4);
369 lldb::offset_t offset
= 0;
370 uint16_t magic
= data
.GetU16(&offset
);
371 return magic
== IMAGE_DOS_SIGNATURE
;
374 lldb::SymbolType
ObjectFilePECOFF::MapSymbolType(uint16_t coff_symbol_type
) {
375 // TODO: We need to complete this mapping of COFF symbol types to LLDB ones.
376 // For now, here's a hack to make sure our function have types.
377 const auto complex_type
=
378 coff_symbol_type
>> llvm::COFF::SCT_COMPLEX_TYPE_SHIFT
;
379 if (complex_type
== llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION
) {
380 return lldb::eSymbolTypeCode
;
382 const auto base_type
= coff_symbol_type
& 0xff;
383 if (base_type
== llvm::COFF::IMAGE_SYM_TYPE_NULL
&&
384 complex_type
== llvm::COFF::IMAGE_SYM_DTYPE_NULL
) {
385 // Unknown type. LLD and GNU ld uses this for variables on MinGW, so
386 // consider these symbols to be data to enable printing.
387 return lldb::eSymbolTypeData
;
389 return lldb::eSymbolTypeInvalid
;
392 bool ObjectFilePECOFF::CreateBinary() {
396 Log
*log
= GetLog(LLDBLog::Object
);
398 auto binary
= llvm::object::createBinary(llvm::MemoryBufferRef(
399 toStringRef(m_data
.GetData()), m_file
.GetFilename().GetStringRef()));
401 LLDB_LOG_ERROR(log
, binary
.takeError(),
402 "Failed to create binary for file ({1}): {0}", m_file
);
406 // Make sure we only handle COFF format.
408 llvm::unique_dyn_cast
<llvm::object::COFFObjectFile
>(std::move(*binary
));
412 LLDB_LOG(log
, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",
413 this, GetModule().get(), GetModule()->GetSpecificationDescription(),
414 m_file
.GetPath(), m_binary
.get());
418 ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP
&module_sp
,
419 DataBufferSP data_sp
,
420 lldb::offset_t data_offset
,
421 const FileSpec
*file
,
422 lldb::offset_t file_offset
,
423 lldb::offset_t length
)
424 : ObjectFile(module_sp
, file
, file_offset
, length
, data_sp
, data_offset
),
425 m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(),
426 m_image_base(LLDB_INVALID_ADDRESS
), m_entry_point_address(),
429 ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP
&module_sp
,
430 WritableDataBufferSP header_data_sp
,
431 const lldb::ProcessSP
&process_sp
,
433 : ObjectFile(module_sp
, process_sp
, header_addr
, header_data_sp
),
434 m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(),
435 m_image_base(LLDB_INVALID_ADDRESS
), m_entry_point_address(),
438 ObjectFilePECOFF::~ObjectFilePECOFF() = default;
440 bool ObjectFilePECOFF::ParseHeader() {
441 ModuleSP
module_sp(GetModule());
443 std::lock_guard
<std::recursive_mutex
> guard(module_sp
->GetMutex());
444 m_sect_headers
.clear();
445 m_data
.SetByteOrder(eByteOrderLittle
);
446 lldb::offset_t offset
= 0;
448 if (ParseDOSHeader(m_data
, m_dos_header
)) {
449 offset
= m_dos_header
.e_lfanew
;
450 uint32_t pe_signature
= m_data
.GetU32(&offset
);
451 if (pe_signature
!= IMAGE_NT_SIGNATURE
)
453 if (ParseCOFFHeader(m_data
, &offset
, m_coff_header
)) {
454 if (m_coff_header
.hdrsize
> 0)
455 ParseCOFFOptionalHeader(&offset
);
456 ParseSectionHeaders(offset
);
458 m_data
.SetAddressByteSize(GetAddressByteSize());
465 bool ObjectFilePECOFF::SetLoadAddress(Target
&target
, addr_t value
,
466 bool value_is_offset
) {
467 bool changed
= false;
468 ModuleSP module_sp
= GetModule();
470 size_t num_loaded_sections
= 0;
471 SectionList
*section_list
= GetSectionList();
473 if (!value_is_offset
) {
474 value
-= m_image_base
;
477 const size_t num_sections
= section_list
->GetSize();
480 for (sect_idx
= 0; sect_idx
< num_sections
; ++sect_idx
) {
481 // Iterate through the object file sections to find all of the sections
482 // that have SHF_ALLOC in their flag bits.
483 SectionSP
section_sp(section_list
->GetSectionAtIndex(sect_idx
));
484 if (section_sp
&& !section_sp
->IsThreadSpecific()) {
485 if (target
.GetSectionLoadList().SetSectionLoadAddress(
486 section_sp
, section_sp
->GetFileAddress() + value
))
487 ++num_loaded_sections
;
490 changed
= num_loaded_sections
> 0;
496 ByteOrder
ObjectFilePECOFF::GetByteOrder() const { return eByteOrderLittle
; }
498 bool ObjectFilePECOFF::IsExecutable() const {
499 return (m_coff_header
.flags
& llvm::COFF::IMAGE_FILE_DLL
) == 0;
502 uint32_t ObjectFilePECOFF::GetAddressByteSize() const {
503 if (m_coff_header_opt
.magic
== OPT_HEADER_MAGIC_PE32_PLUS
)
505 else if (m_coff_header_opt
.magic
== OPT_HEADER_MAGIC_PE32
)
512 // Return true if an endian swap needs to occur when extracting data from this
514 bool ObjectFilePECOFF::NeedsEndianSwap() const {
515 #if defined(__LITTLE_ENDIAN__)
522 bool ObjectFilePECOFF::ParseDOSHeader(DataExtractor
&data
,
523 dos_header_t
&dos_header
) {
524 bool success
= false;
525 lldb::offset_t offset
= 0;
526 success
= data
.ValidOffsetForDataOfSize(0, sizeof(dos_header
));
529 dos_header
.e_magic
= data
.GetU16(&offset
); // Magic number
530 success
= dos_header
.e_magic
== IMAGE_DOS_SIGNATURE
;
533 dos_header
.e_cblp
= data
.GetU16(&offset
); // Bytes on last page of file
534 dos_header
.e_cp
= data
.GetU16(&offset
); // Pages in file
535 dos_header
.e_crlc
= data
.GetU16(&offset
); // Relocations
536 dos_header
.e_cparhdr
=
537 data
.GetU16(&offset
); // Size of header in paragraphs
538 dos_header
.e_minalloc
=
539 data
.GetU16(&offset
); // Minimum extra paragraphs needed
540 dos_header
.e_maxalloc
=
541 data
.GetU16(&offset
); // Maximum extra paragraphs needed
542 dos_header
.e_ss
= data
.GetU16(&offset
); // Initial (relative) SS value
543 dos_header
.e_sp
= data
.GetU16(&offset
); // Initial SP value
544 dos_header
.e_csum
= data
.GetU16(&offset
); // Checksum
545 dos_header
.e_ip
= data
.GetU16(&offset
); // Initial IP value
546 dos_header
.e_cs
= data
.GetU16(&offset
); // Initial (relative) CS value
547 dos_header
.e_lfarlc
=
548 data
.GetU16(&offset
); // File address of relocation table
549 dos_header
.e_ovno
= data
.GetU16(&offset
); // Overlay number
551 dos_header
.e_res
[0] = data
.GetU16(&offset
); // Reserved words
552 dos_header
.e_res
[1] = data
.GetU16(&offset
); // Reserved words
553 dos_header
.e_res
[2] = data
.GetU16(&offset
); // Reserved words
554 dos_header
.e_res
[3] = data
.GetU16(&offset
); // Reserved words
557 data
.GetU16(&offset
); // OEM identifier (for e_oeminfo)
558 dos_header
.e_oeminfo
=
559 data
.GetU16(&offset
); // OEM information; e_oemid specific
560 dos_header
.e_res2
[0] = data
.GetU16(&offset
); // Reserved words
561 dos_header
.e_res2
[1] = data
.GetU16(&offset
); // Reserved words
562 dos_header
.e_res2
[2] = data
.GetU16(&offset
); // Reserved words
563 dos_header
.e_res2
[3] = data
.GetU16(&offset
); // Reserved words
564 dos_header
.e_res2
[4] = data
.GetU16(&offset
); // Reserved words
565 dos_header
.e_res2
[5] = data
.GetU16(&offset
); // Reserved words
566 dos_header
.e_res2
[6] = data
.GetU16(&offset
); // Reserved words
567 dos_header
.e_res2
[7] = data
.GetU16(&offset
); // Reserved words
568 dos_header
.e_res2
[8] = data
.GetU16(&offset
); // Reserved words
569 dos_header
.e_res2
[9] = data
.GetU16(&offset
); // Reserved words
571 dos_header
.e_lfanew
=
572 data
.GetU32(&offset
); // File address of new exe header
576 memset(&dos_header
, 0, sizeof(dos_header
));
581 bool ObjectFilePECOFF::ParseCOFFHeader(DataExtractor
&data
,
582 lldb::offset_t
*offset_ptr
,
583 coff_header_t
&coff_header
) {
585 data
.ValidOffsetForDataOfSize(*offset_ptr
, sizeof(coff_header
));
587 coff_header
.machine
= data
.GetU16(offset_ptr
);
588 coff_header
.nsects
= data
.GetU16(offset_ptr
);
589 coff_header
.modtime
= data
.GetU32(offset_ptr
);
590 coff_header
.symoff
= data
.GetU32(offset_ptr
);
591 coff_header
.nsyms
= data
.GetU32(offset_ptr
);
592 coff_header
.hdrsize
= data
.GetU16(offset_ptr
);
593 coff_header
.flags
= data
.GetU16(offset_ptr
);
596 memset(&coff_header
, 0, sizeof(coff_header
));
600 bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t
*offset_ptr
) {
601 bool success
= false;
602 const lldb::offset_t end_offset
= *offset_ptr
+ m_coff_header
.hdrsize
;
603 if (*offset_ptr
< end_offset
) {
605 m_coff_header_opt
.magic
= m_data
.GetU16(offset_ptr
);
606 m_coff_header_opt
.major_linker_version
= m_data
.GetU8(offset_ptr
);
607 m_coff_header_opt
.minor_linker_version
= m_data
.GetU8(offset_ptr
);
608 m_coff_header_opt
.code_size
= m_data
.GetU32(offset_ptr
);
609 m_coff_header_opt
.data_size
= m_data
.GetU32(offset_ptr
);
610 m_coff_header_opt
.bss_size
= m_data
.GetU32(offset_ptr
);
611 m_coff_header_opt
.entry
= m_data
.GetU32(offset_ptr
);
612 m_coff_header_opt
.code_offset
= m_data
.GetU32(offset_ptr
);
614 const uint32_t addr_byte_size
= GetAddressByteSize();
616 if (*offset_ptr
< end_offset
) {
617 if (m_coff_header_opt
.magic
== OPT_HEADER_MAGIC_PE32
) {
619 m_coff_header_opt
.data_offset
= m_data
.GetU32(offset_ptr
);
621 m_coff_header_opt
.data_offset
= 0;
623 if (*offset_ptr
< end_offset
) {
624 m_coff_header_opt
.image_base
=
625 m_data
.GetMaxU64(offset_ptr
, addr_byte_size
);
626 m_coff_header_opt
.sect_alignment
= m_data
.GetU32(offset_ptr
);
627 m_coff_header_opt
.file_alignment
= m_data
.GetU32(offset_ptr
);
628 m_coff_header_opt
.major_os_system_version
= m_data
.GetU16(offset_ptr
);
629 m_coff_header_opt
.minor_os_system_version
= m_data
.GetU16(offset_ptr
);
630 m_coff_header_opt
.major_image_version
= m_data
.GetU16(offset_ptr
);
631 m_coff_header_opt
.minor_image_version
= m_data
.GetU16(offset_ptr
);
632 m_coff_header_opt
.major_subsystem_version
= m_data
.GetU16(offset_ptr
);
633 m_coff_header_opt
.minor_subsystem_version
= m_data
.GetU16(offset_ptr
);
634 m_coff_header_opt
.reserved1
= m_data
.GetU32(offset_ptr
);
635 m_coff_header_opt
.image_size
= m_data
.GetU32(offset_ptr
);
636 m_coff_header_opt
.header_size
= m_data
.GetU32(offset_ptr
);
637 m_coff_header_opt
.checksum
= m_data
.GetU32(offset_ptr
);
638 m_coff_header_opt
.subsystem
= m_data
.GetU16(offset_ptr
);
639 m_coff_header_opt
.dll_flags
= m_data
.GetU16(offset_ptr
);
640 m_coff_header_opt
.stack_reserve_size
=
641 m_data
.GetMaxU64(offset_ptr
, addr_byte_size
);
642 m_coff_header_opt
.stack_commit_size
=
643 m_data
.GetMaxU64(offset_ptr
, addr_byte_size
);
644 m_coff_header_opt
.heap_reserve_size
=
645 m_data
.GetMaxU64(offset_ptr
, addr_byte_size
);
646 m_coff_header_opt
.heap_commit_size
=
647 m_data
.GetMaxU64(offset_ptr
, addr_byte_size
);
648 m_coff_header_opt
.loader_flags
= m_data
.GetU32(offset_ptr
);
649 uint32_t num_data_dir_entries
= m_data
.GetU32(offset_ptr
);
650 m_coff_header_opt
.data_dirs
.clear();
651 m_coff_header_opt
.data_dirs
.resize(num_data_dir_entries
);
653 for (i
= 0; i
< num_data_dir_entries
; i
++) {
654 m_coff_header_opt
.data_dirs
[i
].vmaddr
= m_data
.GetU32(offset_ptr
);
655 m_coff_header_opt
.data_dirs
[i
].vmsize
= m_data
.GetU32(offset_ptr
);
658 m_image_base
= m_coff_header_opt
.image_base
;
662 // Make sure we are on track for section data which follows
663 *offset_ptr
= end_offset
;
667 uint32_t ObjectFilePECOFF::GetRVA(const Address
&addr
) const {
668 return addr
.GetFileAddress() - m_image_base
;
671 Address
ObjectFilePECOFF::GetAddress(uint32_t rva
) {
672 SectionList
*sect_list
= GetSectionList();
674 return Address(GetFileAddress(rva
));
676 return Address(GetFileAddress(rva
), sect_list
);
679 lldb::addr_t
ObjectFilePECOFF::GetFileAddress(uint32_t rva
) const {
680 return m_image_base
+ rva
;
683 DataExtractor
ObjectFilePECOFF::ReadImageData(uint32_t offset
, size_t size
) {
687 if (m_data
.ValidOffsetForDataOfSize(offset
, size
))
688 return DataExtractor(m_data
, offset
, size
);
690 ProcessSP
process_sp(m_process_wp
.lock());
693 auto data_up
= std::make_unique
<DataBufferHeap
>(size
, 0);
694 Status readmem_error
;
696 process_sp
->ReadMemory(m_image_base
+ offset
, data_up
->GetBytes(),
697 data_up
->GetByteSize(), readmem_error
);
698 if (bytes_read
== size
) {
699 DataBufferSP
buffer_sp(data_up
.release());
700 data
.SetData(buffer_sp
, 0, buffer_sp
->GetByteSize());
706 DataExtractor
ObjectFilePECOFF::ReadImageDataByRVA(uint32_t rva
, size_t size
) {
707 Address addr
= GetAddress(rva
);
708 SectionSP sect
= addr
.GetSection();
711 rva
= sect
->GetFileOffset() + addr
.GetOffset();
713 return ReadImageData(rva
, size
);
716 // ParseSectionHeaders
717 bool ObjectFilePECOFF::ParseSectionHeaders(
718 uint32_t section_header_data_offset
) {
719 const uint32_t nsects
= m_coff_header
.nsects
;
720 m_sect_headers
.clear();
723 const size_t section_header_byte_size
= nsects
* sizeof(section_header_t
);
724 DataExtractor section_header_data
=
725 ReadImageData(section_header_data_offset
, section_header_byte_size
);
727 lldb::offset_t offset
= 0;
728 if (section_header_data
.ValidOffsetForDataOfSize(
729 offset
, section_header_byte_size
)) {
730 m_sect_headers
.resize(nsects
);
732 for (uint32_t idx
= 0; idx
< nsects
; ++idx
) {
733 const void *name_data
= section_header_data
.GetData(&offset
, 8);
735 memcpy(m_sect_headers
[idx
].name
, name_data
, 8);
736 m_sect_headers
[idx
].vmsize
= section_header_data
.GetU32(&offset
);
737 m_sect_headers
[idx
].vmaddr
= section_header_data
.GetU32(&offset
);
738 m_sect_headers
[idx
].size
= section_header_data
.GetU32(&offset
);
739 m_sect_headers
[idx
].offset
= section_header_data
.GetU32(&offset
);
740 m_sect_headers
[idx
].reloff
= section_header_data
.GetU32(&offset
);
741 m_sect_headers
[idx
].lineoff
= section_header_data
.GetU32(&offset
);
742 m_sect_headers
[idx
].nreloc
= section_header_data
.GetU16(&offset
);
743 m_sect_headers
[idx
].nline
= section_header_data
.GetU16(&offset
);
744 m_sect_headers
[idx
].flags
= section_header_data
.GetU32(&offset
);
750 return !m_sect_headers
.empty();
753 llvm::StringRef
ObjectFilePECOFF::GetSectionName(const section_header_t
§
) {
754 llvm::StringRef
hdr_name(sect
.name
, std::size(sect
.name
));
755 hdr_name
= hdr_name
.split('\0').first
;
756 if (hdr_name
.consume_front("/")) {
757 lldb::offset_t stroff
;
758 if (!to_integer(hdr_name
, stroff
, 10))
760 lldb::offset_t string_file_offset
=
761 m_coff_header
.symoff
+ (m_coff_header
.nsyms
* 18) + stroff
;
762 if (const char *name
= m_data
.GetCStr(&string_file_offset
))
769 void ObjectFilePECOFF::ParseSymtab(Symtab
&symtab
) {
770 SectionList
*sect_list
= GetSectionList();
771 rva_symbol_list_t sorted_exports
= AppendFromExportTable(sect_list
, symtab
);
772 AppendFromCOFFSymbolTable(sect_list
, symtab
, sorted_exports
);
775 static bool RVASymbolListCompareRVA(const std::pair
<uint32_t, uint32_t> &a
,
776 const std::pair
<uint32_t, uint32_t> &b
) {
777 return a
.first
< b
.first
;
780 void ObjectFilePECOFF::AppendFromCOFFSymbolTable(
781 SectionList
*sect_list
, Symtab
&symtab
,
782 const ObjectFilePECOFF::rva_symbol_list_t
&sorted_exports
) {
783 const uint32_t num_syms
= m_binary
->getNumberOfSymbols();
786 // Check that this is not a bigobj; we do not support bigobj.
787 if (m_binary
->getSymbolTableEntrySize() !=
788 sizeof(llvm::object::coff_symbol16
))
791 Log
*log
= GetLog(LLDBLog::Object
);
792 symtab
.Reserve(symtab
.GetNumSymbols() + num_syms
);
793 for (const auto &sym_ref
: m_binary
->symbols()) {
794 const auto coff_sym_ref
= m_binary
->getCOFFSymbol(sym_ref
);
795 auto name_or_error
= sym_ref
.getName();
796 if (!name_or_error
) {
797 LLDB_LOG_ERROR(log
, name_or_error
.takeError(),
798 "ObjectFilePECOFF::AppendFromCOFFSymbolTable - failed to "
799 "get symbol table entry name: {0}");
802 const llvm::StringRef sym_name
= *name_or_error
;
804 symbol
.GetMangled().SetValue(ConstString(sym_name
));
805 int16_t section_number
=
806 static_cast<int16_t>(coff_sym_ref
.getSectionNumber());
807 if (section_number
>= 1) {
808 symbol
.GetAddressRef() = Address(
809 sect_list
->FindSectionByID(section_number
), coff_sym_ref
.getValue());
810 const auto symbol_type
= MapSymbolType(coff_sym_ref
.getType());
811 symbol
.SetType(symbol_type
);
813 // Check for duplicate of exported symbols:
814 const uint32_t symbol_rva
= symbol
.GetAddressRef().GetFileAddress() -
815 m_coff_header_opt
.image_base
;
816 const auto &first_match
= std::lower_bound(
817 sorted_exports
.begin(), sorted_exports
.end(),
818 std::make_pair(symbol_rva
, 0), RVASymbolListCompareRVA
);
819 for (auto it
= first_match
;
820 it
!= sorted_exports
.end() && it
->first
== symbol_rva
; ++it
) {
821 Symbol
*exported
= symtab
.SymbolAtIndex(it
->second
);
822 if (symbol_type
!= lldb::eSymbolTypeInvalid
)
823 exported
->SetType(symbol_type
);
824 if (exported
->GetMangled() == symbol
.GetMangled()) {
825 symbol
.SetExternal(true);
826 // We don't want the symbol to be duplicated (e.g. when running
827 // `disas -n func`), but we also don't want to erase this entry (to
828 // preserve the original symbol order), so we mark it as additional.
829 symbol
.SetType(lldb::eSymbolTypeAdditional
);
831 // It is possible for a symbol to be exported in a different name
832 // from its original. In this case keep both entries so lookup using
833 // either names will work. If this symbol has an invalid type, replace
834 // it with the type from the export symbol.
835 if (symbol
.GetType() == lldb::eSymbolTypeInvalid
)
836 symbol
.SetType(exported
->GetType());
839 } else if (section_number
== llvm::COFF::IMAGE_SYM_ABSOLUTE
) {
840 symbol
.GetAddressRef() = Address(coff_sym_ref
.getValue());
841 symbol
.SetType(lldb::eSymbolTypeAbsolute
);
843 symtab
.AddSymbol(symbol
);
847 ObjectFilePECOFF::rva_symbol_list_t
848 ObjectFilePECOFF::AppendFromExportTable(SectionList
*sect_list
,
850 const auto *export_table
= m_binary
->getExportTable();
853 const uint32_t num_syms
= export_table
->AddressTableEntries
;
857 Log
*log
= GetLog(LLDBLog::Object
);
858 rva_symbol_list_t export_list
;
859 symtab
.Reserve(symtab
.GetNumSymbols() + num_syms
);
860 // Read each export table entry, ordered by ordinal instead of by name.
861 for (const auto &entry
: m_binary
->export_directories()) {
862 llvm::StringRef sym_name
;
863 if (auto err
= entry
.getSymbolName(sym_name
)) {
867 "ObjectFilePECOFF::AppendFromExportTable - failed to get export "
868 "table entry name: {0}",
869 llvm::fmt_consume(std::move(err
)));
871 llvm::consumeError(std::move(err
));
875 // Note: symbol name may be empty if it is only exported by ordinal.
876 symbol
.GetMangled().SetValue(ConstString(sym_name
));
879 llvm::cantFail(entry
.getOrdinal(ordinal
));
880 symbol
.SetID(ordinal
);
883 llvm::cantFail(entry
.isForwarder(is_forwarder
));
885 // Forwarder exports are redirected by the loader transparently, but keep
886 // it in symtab and make a note using the symbol name.
887 llvm::StringRef forwarder_name
;
888 if (auto err
= entry
.getForwardTo(forwarder_name
)) {
890 log
->Format(__FILE__
, __func__
,
891 "ObjectFilePECOFF::AppendFromExportTable - failed to get "
892 "forwarder name of forwarder export '{0}': {1}",
893 sym_name
, llvm::fmt_consume(std::move(err
)));
895 llvm::consumeError(std::move(err
));
898 llvm::SmallString
<256> new_name
= {symbol
.GetDisplayName().GetStringRef(),
899 " (forwarded to ", forwarder_name
,
901 symbol
.GetMangled().SetDemangledName(ConstString(new_name
.str()));
902 symbol
.SetDemangledNameIsSynthesized(true);
905 uint32_t function_rva
;
906 if (auto err
= entry
.getExportRVA(function_rva
)) {
908 log
->Format(__FILE__
, __func__
,
909 "ObjectFilePECOFF::AppendFromExportTable - failed to get "
910 "address of export entry '{0}': {1}",
911 sym_name
, llvm::fmt_consume(std::move(err
)));
913 llvm::consumeError(std::move(err
));
916 // Skip the symbol if it doesn't look valid.
917 if (function_rva
== 0 && sym_name
.empty())
919 symbol
.GetAddressRef() =
920 Address(m_coff_header_opt
.image_base
+ function_rva
, sect_list
);
922 // An exported symbol may be either code or data. Guess by checking whether
923 // the section containing the symbol is executable.
924 symbol
.SetType(lldb::eSymbolTypeData
);
926 if (auto section_sp
= symbol
.GetAddressRef().GetSection())
927 if (section_sp
->GetPermissions() & ePermissionsExecutable
)
928 symbol
.SetType(lldb::eSymbolTypeCode
);
929 symbol
.SetExternal(true);
930 uint32_t idx
= symtab
.AddSymbol(symbol
);
931 export_list
.push_back(std::make_pair(function_rva
, idx
));
933 std::stable_sort(export_list
.begin(), export_list
.end(),
934 RVASymbolListCompareRVA
);
938 std::unique_ptr
<CallFrameInfo
> ObjectFilePECOFF::CreateCallFrameInfo() {
939 if (llvm::COFF::EXCEPTION_TABLE
>= m_coff_header_opt
.data_dirs
.size())
942 data_directory data_dir_exception
=
943 m_coff_header_opt
.data_dirs
[llvm::COFF::EXCEPTION_TABLE
];
944 if (!data_dir_exception
.vmaddr
)
947 if (m_coff_header
.machine
!= llvm::COFF::IMAGE_FILE_MACHINE_AMD64
)
950 return std::make_unique
<PECallFrameInfo
>(*this, data_dir_exception
.vmaddr
,
951 data_dir_exception
.vmsize
);
954 bool ObjectFilePECOFF::IsStripped() {
955 // TODO: determine this for COFF
959 SectionType
ObjectFilePECOFF::GetSectionType(llvm::StringRef sect_name
,
960 const section_header_t
§
) {
961 ConstString
const_sect_name(sect_name
);
962 static ConstString
g_code_sect_name(".code");
963 static ConstString
g_CODE_sect_name("CODE");
964 static ConstString
g_data_sect_name(".data");
965 static ConstString
g_DATA_sect_name("DATA");
966 static ConstString
g_bss_sect_name(".bss");
967 static ConstString
g_BSS_sect_name("BSS");
969 if (sect
.flags
& llvm::COFF::IMAGE_SCN_CNT_CODE
&&
970 ((const_sect_name
== g_code_sect_name
) ||
971 (const_sect_name
== g_CODE_sect_name
))) {
972 return eSectionTypeCode
;
974 if (sect
.flags
& llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
&&
975 ((const_sect_name
== g_data_sect_name
) ||
976 (const_sect_name
== g_DATA_sect_name
))) {
977 if (sect
.size
== 0 && sect
.offset
== 0)
978 return eSectionTypeZeroFill
;
980 return eSectionTypeData
;
982 if (sect
.flags
& llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
&&
983 ((const_sect_name
== g_bss_sect_name
) ||
984 (const_sect_name
== g_BSS_sect_name
))) {
986 return eSectionTypeZeroFill
;
988 return eSectionTypeData
;
991 SectionType section_type
=
992 llvm::StringSwitch
<SectionType
>(sect_name
)
993 .Case(".debug", eSectionTypeDebug
)
994 .Case(".stabstr", eSectionTypeDataCString
)
995 .Case(".reloc", eSectionTypeOther
)
996 .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev
)
997 .Case(".debug_aranges", eSectionTypeDWARFDebugAranges
)
998 .Case(".debug_frame", eSectionTypeDWARFDebugFrame
)
999 .Case(".debug_info", eSectionTypeDWARFDebugInfo
)
1000 .Case(".debug_line", eSectionTypeDWARFDebugLine
)
1001 .Case(".debug_loc", eSectionTypeDWARFDebugLoc
)
1002 .Case(".debug_loclists", eSectionTypeDWARFDebugLocLists
)
1003 .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo
)
1004 .Case(".debug_names", eSectionTypeDWARFDebugNames
)
1005 .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames
)
1006 .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes
)
1007 .Case(".debug_ranges", eSectionTypeDWARFDebugRanges
)
1008 .Case(".debug_str", eSectionTypeDWARFDebugStr
)
1009 .Case(".debug_types", eSectionTypeDWARFDebugTypes
)
1010 // .eh_frame can be truncated to 8 chars.
1011 .Cases(".eh_frame", ".eh_fram", eSectionTypeEHFrame
)
1012 .Case(".gosymtab", eSectionTypeGoSymtab
)
1013 .Case("swiftast", eSectionTypeSwiftModules
)
1014 .Default(eSectionTypeInvalid
);
1015 if (section_type
!= eSectionTypeInvalid
)
1016 return section_type
;
1018 if (sect
.flags
& llvm::COFF::IMAGE_SCN_CNT_CODE
)
1019 return eSectionTypeCode
;
1020 if (sect
.flags
& llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
)
1021 return eSectionTypeData
;
1022 if (sect
.flags
& llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
) {
1024 return eSectionTypeZeroFill
;
1026 return eSectionTypeData
;
1028 return eSectionTypeOther
;
1031 size_t ObjectFilePECOFF::GetSectionDataSize(Section
*section
) {
1032 // For executables, SizeOfRawData (getFileSize()) is aligned by
1033 // FileAlignment and the actual section size is in VirtualSize
1034 // (getByteSize()). See the comment on
1035 // llvm::object::COFFObjectFile::getSectionSize().
1036 if (m_binary
->getPE32Header() || m_binary
->getPE32PlusHeader())
1037 return std::min(section
->GetByteSize(), section
->GetFileSize());
1038 return section
->GetFileSize();
1041 void ObjectFilePECOFF::CreateSections(SectionList
&unified_section_list
) {
1044 m_sections_up
= std::make_unique
<SectionList
>();
1045 ModuleSP
module_sp(GetModule());
1047 std::lock_guard
<std::recursive_mutex
> guard(module_sp
->GetMutex());
1049 SectionSP header_sp
= std::make_shared
<Section
>(
1050 module_sp
, this, ~user_id_t(0), ConstString("PECOFF header"),
1051 eSectionTypeOther
, m_coff_header_opt
.image_base
,
1052 m_coff_header_opt
.header_size
,
1053 /*file_offset*/ 0, m_coff_header_opt
.header_size
,
1054 m_coff_header_opt
.sect_alignment
,
1056 header_sp
->SetPermissions(ePermissionsReadable
);
1057 m_sections_up
->AddSection(header_sp
);
1058 unified_section_list
.AddSection(header_sp
);
1060 const uint32_t nsects
= m_sect_headers
.size();
1061 for (uint32_t idx
= 0; idx
< nsects
; ++idx
) {
1062 llvm::StringRef sect_name
= GetSectionName(m_sect_headers
[idx
]);
1063 ConstString
const_sect_name(sect_name
);
1064 SectionType section_type
= GetSectionType(sect_name
, m_sect_headers
[idx
]);
1066 SectionSP
section_sp(new Section(
1067 module_sp
, // Module to which this section belongs
1068 this, // Object file to which this section belongs
1069 idx
+ 1, // Section ID is the 1 based section index.
1070 const_sect_name
, // Name of this section
1072 m_coff_header_opt
.image_base
+
1073 m_sect_headers
[idx
].vmaddr
, // File VM address == addresses as
1074 // they are found in the object file
1075 m_sect_headers
[idx
].vmsize
, // VM size in bytes of this section
1077 .offset
, // Offset to the data for this section in the file
1079 .size
, // Size in bytes of this section as found in the file
1080 m_coff_header_opt
.sect_alignment
, // Section alignment
1081 m_sect_headers
[idx
].flags
)); // Flags for this section
1083 uint32_t permissions
= 0;
1084 if (m_sect_headers
[idx
].flags
& llvm::COFF::IMAGE_SCN_MEM_EXECUTE
)
1085 permissions
|= ePermissionsExecutable
;
1086 if (m_sect_headers
[idx
].flags
& llvm::COFF::IMAGE_SCN_MEM_READ
)
1087 permissions
|= ePermissionsReadable
;
1088 if (m_sect_headers
[idx
].flags
& llvm::COFF::IMAGE_SCN_MEM_WRITE
)
1089 permissions
|= ePermissionsWritable
;
1090 section_sp
->SetPermissions(permissions
);
1092 m_sections_up
->AddSection(section_sp
);
1093 unified_section_list
.AddSection(section_sp
);
1098 UUID
ObjectFilePECOFF::GetUUID() {
1099 if (m_uuid
.IsValid())
1102 if (!CreateBinary())
1105 m_uuid
= GetCoffUUID(*m_binary
);
1109 std::optional
<FileSpec
> ObjectFilePECOFF::GetDebugLink() {
1110 std::string gnu_debuglink_file
;
1111 uint32_t gnu_debuglink_crc
;
1112 if (GetDebugLinkContents(*m_binary
, gnu_debuglink_file
, gnu_debuglink_crc
))
1113 return FileSpec(gnu_debuglink_file
);
1114 return std::nullopt
;
1117 uint32_t ObjectFilePECOFF::ParseDependentModules() {
1118 ModuleSP
module_sp(GetModule());
1122 std::lock_guard
<std::recursive_mutex
> guard(module_sp
->GetMutex());
1123 if (m_deps_filespec
)
1124 return m_deps_filespec
->GetSize();
1126 // Cache coff binary if it is not done yet.
1127 if (!CreateBinary())
1130 Log
*log
= GetLog(LLDBLog::Object
);
1131 LLDB_LOG(log
, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",
1132 this, GetModule().get(), GetModule()->GetSpecificationDescription(),
1133 m_file
.GetPath(), m_binary
.get());
1135 m_deps_filespec
= FileSpecList();
1137 for (const auto &entry
: m_binary
->import_directories()) {
1138 llvm::StringRef dll_name
;
1139 // Report a bogus entry.
1140 if (llvm::Error e
= entry
.getName(dll_name
)) {
1142 "ObjectFilePECOFF::ParseDependentModules() - failed to get "
1143 "import directory entry name: %s",
1144 llvm::toString(std::move(e
)).c_str());
1148 // At this moment we only have the base name of the DLL. The full path can
1149 // only be seen after the dynamic loading. Our best guess is Try to get it
1150 // with the help of the object file's directory.
1151 llvm::SmallString
<128> dll_fullpath
;
1152 FileSpec
dll_specs(dll_name
);
1153 dll_specs
.SetDirectory(m_file
.GetDirectory());
1155 if (!llvm::sys::fs::real_path(dll_specs
.GetPath(), dll_fullpath
))
1156 m_deps_filespec
->EmplaceBack(dll_fullpath
);
1158 // Known DLLs or DLL not found in the object file directory.
1159 m_deps_filespec
->EmplaceBack(dll_name
);
1162 return m_deps_filespec
->GetSize();
1165 uint32_t ObjectFilePECOFF::GetDependentModules(FileSpecList
&files
) {
1166 auto num_modules
= ParseDependentModules();
1167 auto original_size
= files
.GetSize();
1169 for (unsigned i
= 0; i
< num_modules
; ++i
)
1170 files
.AppendIfUnique(m_deps_filespec
->GetFileSpecAtIndex(i
));
1172 return files
.GetSize() - original_size
;
1175 lldb_private::Address
ObjectFilePECOFF::GetEntryPointAddress() {
1176 if (m_entry_point_address
.IsValid())
1177 return m_entry_point_address
;
1179 if (!ParseHeader() || !IsExecutable())
1180 return m_entry_point_address
;
1182 SectionList
*section_list
= GetSectionList();
1183 addr_t file_addr
= m_coff_header_opt
.entry
+ m_coff_header_opt
.image_base
;
1186 m_entry_point_address
.SetOffset(file_addr
);
1188 m_entry_point_address
.ResolveAddressUsingFileSections(file_addr
,
1190 return m_entry_point_address
;
1193 Address
ObjectFilePECOFF::GetBaseAddress() {
1194 return Address(GetSectionList()->GetSectionAtIndex(0), 0);
1199 // Dump the specifics of the runtime file container (such as any headers
1200 // segments, sections, etc).
1201 void ObjectFilePECOFF::Dump(Stream
*s
) {
1202 ModuleSP
module_sp(GetModule());
1204 std::lock_guard
<std::recursive_mutex
> guard(module_sp
->GetMutex());
1205 s
->Printf("%p: ", static_cast<void *>(this));
1207 s
->PutCString("ObjectFilePECOFF");
1209 ArchSpec header_arch
= GetArchitecture();
1211 *s
<< ", file = '" << m_file
1212 << "', arch = " << header_arch
.GetArchitectureName() << "\n";
1214 SectionList
*sections
= GetSectionList();
1216 sections
->Dump(s
->AsRawOstream(), s
->GetIndentLevel(), nullptr, true,
1220 m_symtab_up
->Dump(s
, nullptr, eSortOrderNone
);
1222 if (m_dos_header
.e_magic
)
1223 DumpDOSHeader(s
, m_dos_header
);
1224 if (m_coff_header
.machine
) {
1225 DumpCOFFHeader(s
, m_coff_header
);
1226 if (m_coff_header
.hdrsize
)
1227 DumpOptCOFFHeader(s
, m_coff_header_opt
);
1230 DumpSectionHeaders(s
);
1233 DumpDependentModules(s
);
1240 // Dump the MS-DOS header to the specified output stream
1241 void ObjectFilePECOFF::DumpDOSHeader(Stream
*s
, const dos_header_t
&header
) {
1242 s
->PutCString("MSDOS Header\n");
1243 s
->Printf(" e_magic = 0x%4.4x\n", header
.e_magic
);
1244 s
->Printf(" e_cblp = 0x%4.4x\n", header
.e_cblp
);
1245 s
->Printf(" e_cp = 0x%4.4x\n", header
.e_cp
);
1246 s
->Printf(" e_crlc = 0x%4.4x\n", header
.e_crlc
);
1247 s
->Printf(" e_cparhdr = 0x%4.4x\n", header
.e_cparhdr
);
1248 s
->Printf(" e_minalloc = 0x%4.4x\n", header
.e_minalloc
);
1249 s
->Printf(" e_maxalloc = 0x%4.4x\n", header
.e_maxalloc
);
1250 s
->Printf(" e_ss = 0x%4.4x\n", header
.e_ss
);
1251 s
->Printf(" e_sp = 0x%4.4x\n", header
.e_sp
);
1252 s
->Printf(" e_csum = 0x%4.4x\n", header
.e_csum
);
1253 s
->Printf(" e_ip = 0x%4.4x\n", header
.e_ip
);
1254 s
->Printf(" e_cs = 0x%4.4x\n", header
.e_cs
);
1255 s
->Printf(" e_lfarlc = 0x%4.4x\n", header
.e_lfarlc
);
1256 s
->Printf(" e_ovno = 0x%4.4x\n", header
.e_ovno
);
1257 s
->Printf(" e_res[4] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n",
1258 header
.e_res
[0], header
.e_res
[1], header
.e_res
[2], header
.e_res
[3]);
1259 s
->Printf(" e_oemid = 0x%4.4x\n", header
.e_oemid
);
1260 s
->Printf(" e_oeminfo = 0x%4.4x\n", header
.e_oeminfo
);
1261 s
->Printf(" e_res2[10] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, "
1262 "0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n",
1263 header
.e_res2
[0], header
.e_res2
[1], header
.e_res2
[2],
1264 header
.e_res2
[3], header
.e_res2
[4], header
.e_res2
[5],
1265 header
.e_res2
[6], header
.e_res2
[7], header
.e_res2
[8],
1267 s
->Printf(" e_lfanew = 0x%8.8x\n", header
.e_lfanew
);
1272 // Dump the COFF header to the specified output stream
1273 void ObjectFilePECOFF::DumpCOFFHeader(Stream
*s
, const coff_header_t
&header
) {
1274 s
->PutCString("COFF Header\n");
1275 s
->Printf(" machine = 0x%4.4x\n", header
.machine
);
1276 s
->Printf(" nsects = 0x%4.4x\n", header
.nsects
);
1277 s
->Printf(" modtime = 0x%8.8x\n", header
.modtime
);
1278 s
->Printf(" symoff = 0x%8.8x\n", header
.symoff
);
1279 s
->Printf(" nsyms = 0x%8.8x\n", header
.nsyms
);
1280 s
->Printf(" hdrsize = 0x%4.4x\n", header
.hdrsize
);
1283 // DumpOptCOFFHeader
1285 // Dump the optional COFF header to the specified output stream
1286 void ObjectFilePECOFF::DumpOptCOFFHeader(Stream
*s
,
1287 const coff_opt_header_t
&header
) {
1288 s
->PutCString("Optional COFF Header\n");
1289 s
->Printf(" magic = 0x%4.4x\n", header
.magic
);
1290 s
->Printf(" major_linker_version = 0x%2.2x\n",
1291 header
.major_linker_version
);
1292 s
->Printf(" minor_linker_version = 0x%2.2x\n",
1293 header
.minor_linker_version
);
1294 s
->Printf(" code_size = 0x%8.8x\n", header
.code_size
);
1295 s
->Printf(" data_size = 0x%8.8x\n", header
.data_size
);
1296 s
->Printf(" bss_size = 0x%8.8x\n", header
.bss_size
);
1297 s
->Printf(" entry = 0x%8.8x\n", header
.entry
);
1298 s
->Printf(" code_offset = 0x%8.8x\n", header
.code_offset
);
1299 s
->Printf(" data_offset = 0x%8.8x\n", header
.data_offset
);
1300 s
->Printf(" image_base = 0x%16.16" PRIx64
"\n",
1302 s
->Printf(" sect_alignment = 0x%8.8x\n", header
.sect_alignment
);
1303 s
->Printf(" file_alignment = 0x%8.8x\n", header
.file_alignment
);
1304 s
->Printf(" major_os_system_version = 0x%4.4x\n",
1305 header
.major_os_system_version
);
1306 s
->Printf(" minor_os_system_version = 0x%4.4x\n",
1307 header
.minor_os_system_version
);
1308 s
->Printf(" major_image_version = 0x%4.4x\n",
1309 header
.major_image_version
);
1310 s
->Printf(" minor_image_version = 0x%4.4x\n",
1311 header
.minor_image_version
);
1312 s
->Printf(" major_subsystem_version = 0x%4.4x\n",
1313 header
.major_subsystem_version
);
1314 s
->Printf(" minor_subsystem_version = 0x%4.4x\n",
1315 header
.minor_subsystem_version
);
1316 s
->Printf(" reserved1 = 0x%8.8x\n", header
.reserved1
);
1317 s
->Printf(" image_size = 0x%8.8x\n", header
.image_size
);
1318 s
->Printf(" header_size = 0x%8.8x\n", header
.header_size
);
1319 s
->Printf(" checksum = 0x%8.8x\n", header
.checksum
);
1320 s
->Printf(" subsystem = 0x%4.4x\n", header
.subsystem
);
1321 s
->Printf(" dll_flags = 0x%4.4x\n", header
.dll_flags
);
1322 s
->Printf(" stack_reserve_size = 0x%16.16" PRIx64
"\n",
1323 header
.stack_reserve_size
);
1324 s
->Printf(" stack_commit_size = 0x%16.16" PRIx64
"\n",
1325 header
.stack_commit_size
);
1326 s
->Printf(" heap_reserve_size = 0x%16.16" PRIx64
"\n",
1327 header
.heap_reserve_size
);
1328 s
->Printf(" heap_commit_size = 0x%16.16" PRIx64
"\n",
1329 header
.heap_commit_size
);
1330 s
->Printf(" loader_flags = 0x%8.8x\n", header
.loader_flags
);
1331 s
->Printf(" num_data_dir_entries = 0x%8.8x\n",
1332 (uint32_t)header
.data_dirs
.size());
1334 for (i
= 0; i
< header
.data_dirs
.size(); i
++) {
1335 s
->Printf(" data_dirs[%2u] vmaddr = 0x%8.8x, vmsize = 0x%8.8x\n", i
,
1336 header
.data_dirs
[i
].vmaddr
, header
.data_dirs
[i
].vmsize
);
1339 // DumpSectionHeader
1341 // Dump a single ELF section header to the specified output stream
1342 void ObjectFilePECOFF::DumpSectionHeader(Stream
*s
,
1343 const section_header_t
&sh
) {
1344 std::string name
= std::string(GetSectionName(sh
));
1345 s
->Printf("%-16s 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%4.4x "
1346 "0x%4.4x 0x%8.8x\n",
1347 name
.c_str(), sh
.vmaddr
, sh
.vmsize
, sh
.offset
, sh
.size
, sh
.reloff
,
1348 sh
.lineoff
, sh
.nreloc
, sh
.nline
, sh
.flags
);
1351 // DumpSectionHeaders
1353 // Dump all of the ELF section header to the specified output stream
1354 void ObjectFilePECOFF::DumpSectionHeaders(Stream
*s
) {
1356 s
->PutCString("Section Headers\n");
1357 s
->PutCString("IDX name vm addr vm size file off file "
1358 "size reloc off line off nreloc nline flags\n");
1359 s
->PutCString("==== ---------------- ---------- ---------- ---------- "
1360 "---------- ---------- ---------- ------ ------ ----------\n");
1363 SectionHeaderCollIter pos
, end
= m_sect_headers
.end();
1365 for (pos
= m_sect_headers
.begin(); pos
!= end
; ++pos
, ++idx
) {
1366 s
->Printf("[%2u] ", idx
);
1367 ObjectFilePECOFF::DumpSectionHeader(s
, *pos
);
1371 // DumpDependentModules
1373 // Dump all of the dependent modules to the specified output stream
1374 void ObjectFilePECOFF::DumpDependentModules(lldb_private::Stream
*s
) {
1375 auto num_modules
= ParseDependentModules();
1376 if (num_modules
> 0) {
1377 s
->PutCString("Dependent Modules\n");
1378 for (unsigned i
= 0; i
< num_modules
; ++i
) {
1379 auto spec
= m_deps_filespec
->GetFileSpecAtIndex(i
);
1380 s
->Printf(" %s\n", spec
.GetFilename().GetCString());
1385 bool ObjectFilePECOFF::IsWindowsSubsystem() {
1386 switch (m_coff_header_opt
.subsystem
) {
1387 case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE
:
1388 case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI
:
1389 case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI
:
1390 case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE_WINDOWS
:
1391 case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI
:
1392 case llvm::COFF::IMAGE_SUBSYSTEM_XBOX
:
1393 case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION
:
1400 ArchSpec
ObjectFilePECOFF::GetArchitecture() {
1401 uint16_t machine
= m_coff_header
.machine
;
1405 case llvm::COFF::IMAGE_FILE_MACHINE_AMD64
:
1406 case llvm::COFF::IMAGE_FILE_MACHINE_I386
:
1407 case llvm::COFF::IMAGE_FILE_MACHINE_POWERPC
:
1408 case llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP
:
1409 case llvm::COFF::IMAGE_FILE_MACHINE_ARM
:
1410 case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT
:
1411 case llvm::COFF::IMAGE_FILE_MACHINE_THUMB
:
1412 case llvm::COFF::IMAGE_FILE_MACHINE_ARM64
:
1414 arch
.SetArchitecture(eArchTypeCOFF
, machine
, LLDB_INVALID_CPUTYPE
,
1415 IsWindowsSubsystem() ? llvm::Triple::Win32
1416 : llvm::Triple::UnknownOS
);
1422 ObjectFile::Type
ObjectFilePECOFF::CalculateType() {
1423 if (m_coff_header
.machine
!= 0) {
1424 if ((m_coff_header
.flags
& llvm::COFF::IMAGE_FILE_DLL
) == 0)
1425 return eTypeExecutable
;
1427 return eTypeSharedLibrary
;
1429 return eTypeExecutable
;
1432 ObjectFile::Strata
ObjectFilePECOFF::CalculateStrata() { return eStrataUser
; }