1 | //===-- ObjectFilePECOFF.cpp ----------------------------------------------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "ObjectFilePECOFF.h" |
10 | #include "PECallFrameInfo.h" |
11 | #include "WindowsMiniDump.h" |
12 | |
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/Target/Process.h" |
21 | #include "lldb/Target/SectionLoadList.h" |
22 | #include "lldb/Target/Target.h" |
23 | #include "lldb/Utility/ArchSpec.h" |
24 | #include "lldb/Utility/DataBufferHeap.h" |
25 | #include "lldb/Utility/FileSpec.h" |
26 | #include "lldb/Utility/FileSpecList.h" |
27 | #include "lldb/Utility/LLDBLog.h" |
28 | #include "lldb/Utility/Log.h" |
29 | #include "lldb/Utility/StreamString.h" |
30 | #include "lldb/Utility/Timer.h" |
31 | #include "lldb/Utility/UUID.h" |
32 | |
33 | #include "llvm/BinaryFormat/COFF.h" |
34 | #include "llvm/Object/COFFImportFile.h" |
35 | #include "llvm/Support/CRC.h" |
36 | #include "llvm/Support/Error.h" |
37 | #include "llvm/Support/FormatAdapters.h" |
38 | #include "llvm/Support/MemoryBuffer.h" |
39 | #include "llvm/TargetParser/Host.h" |
40 | #include <optional> |
41 | |
42 | #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ |
43 | #define IMAGE_NT_SIGNATURE 0x00004550 // PE00 |
44 | #define 0x010b |
45 | #define 0x020b |
46 | |
47 | using namespace lldb; |
48 | using namespace lldb_private; |
49 | |
50 | LLDB_PLUGIN_DEFINE(ObjectFilePECOFF) |
51 | |
52 | namespace { |
53 | |
54 | static constexpr OptionEnumValueElement g_abi_enums[] = { |
55 | { |
56 | .value: llvm::Triple::UnknownEnvironment, |
57 | .string_value: "default" , |
58 | .usage: "Use default target (if it is Windows) or MSVC" , |
59 | }, |
60 | { |
61 | .value: llvm::Triple::MSVC, |
62 | .string_value: "msvc" , |
63 | .usage: "MSVC ABI" , |
64 | }, |
65 | { |
66 | .value: llvm::Triple::GNU, |
67 | .string_value: "gnu" , |
68 | .usage: "MinGW / Itanium ABI" , |
69 | }, |
70 | }; |
71 | |
72 | #define LLDB_PROPERTIES_objectfilepecoff |
73 | #include "ObjectFilePECOFFProperties.inc" |
74 | |
75 | enum { |
76 | #define LLDB_PROPERTIES_objectfilepecoff |
77 | #include "ObjectFilePECOFFPropertiesEnum.inc" |
78 | }; |
79 | |
80 | class PluginProperties : public Properties { |
81 | public: |
82 | static llvm::StringRef GetSettingName() { |
83 | return ObjectFilePECOFF::GetPluginNameStatic(); |
84 | } |
85 | |
86 | PluginProperties() { |
87 | m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName()); |
88 | m_collection_sp->Initialize(g_objectfilepecoff_properties); |
89 | } |
90 | |
91 | llvm::Triple::EnvironmentType ABI() const { |
92 | return GetPropertyAtIndexAs<llvm::Triple::EnvironmentType>( |
93 | ePropertyABI, llvm::Triple::UnknownEnvironment); |
94 | } |
95 | |
96 | OptionValueDictionary *ModuleABIMap() const { |
97 | return m_collection_sp->GetPropertyAtIndexAsOptionValueDictionary( |
98 | ePropertyModuleABIMap); |
99 | } |
100 | }; |
101 | |
102 | } // namespace |
103 | |
104 | static PluginProperties &GetGlobalPluginProperties() { |
105 | static PluginProperties g_settings; |
106 | return g_settings; |
107 | } |
108 | |
109 | static bool GetDebugLinkContents(const llvm::object::COFFObjectFile &coff_obj, |
110 | std::string &gnu_debuglink_file, |
111 | uint32_t &gnu_debuglink_crc) { |
112 | static ConstString g_sect_name_gnu_debuglink(".gnu_debuglink" ); |
113 | for (const auto §ion : coff_obj.sections()) { |
114 | auto name = section.getName(); |
115 | if (!name) { |
116 | llvm::consumeError(Err: name.takeError()); |
117 | continue; |
118 | } |
119 | if (*name == g_sect_name_gnu_debuglink.GetStringRef()) { |
120 | auto content = section.getContents(); |
121 | if (!content) { |
122 | llvm::consumeError(Err: content.takeError()); |
123 | return false; |
124 | } |
125 | DataExtractor data( |
126 | content->data(), content->size(), |
127 | coff_obj.isLittleEndian() ? eByteOrderLittle : eByteOrderBig, 4); |
128 | lldb::offset_t gnu_debuglink_offset = 0; |
129 | gnu_debuglink_file = data.GetCStr(offset_ptr: &gnu_debuglink_offset); |
130 | // Align to the next 4-byte offset |
131 | gnu_debuglink_offset = llvm::alignTo(Value: gnu_debuglink_offset, Align: 4); |
132 | data.GetU32(offset_ptr: &gnu_debuglink_offset, dst: &gnu_debuglink_crc, count: 1); |
133 | return true; |
134 | } |
135 | } |
136 | return false; |
137 | } |
138 | |
139 | static UUID GetCoffUUID(llvm::object::COFFObjectFile &coff_obj) { |
140 | const llvm::codeview::DebugInfo *pdb_info = nullptr; |
141 | llvm::StringRef pdb_file; |
142 | |
143 | // First, prefer to use the PDB build id. LLD generates this even for mingw |
144 | // targets without PDB output, and it does not get stripped either. |
145 | if (!coff_obj.getDebugPDBInfo(Info&: pdb_info, PDBFileName&: pdb_file) && pdb_info) { |
146 | if (pdb_info->PDB70.CVSignature == llvm::OMF::Signature::PDB70) { |
147 | UUID::CvRecordPdb70 info; |
148 | memcpy(dest: &info.Uuid, src: pdb_info->PDB70.Signature, n: sizeof(info.Uuid)); |
149 | info.Age = pdb_info->PDB70.Age; |
150 | return UUID(info); |
151 | } |
152 | } |
153 | |
154 | std::string gnu_debuglink_file; |
155 | uint32_t gnu_debuglink_crc; |
156 | |
157 | // The GNU linker normally does not write a PDB build id (unless requested |
158 | // with the --build-id option), so we should fall back to using the crc |
159 | // from .gnu_debuglink if it exists, just like how ObjectFileELF does it. |
160 | if (!GetDebugLinkContents(coff_obj, gnu_debuglink_file, gnu_debuglink_crc)) { |
161 | // If there is no .gnu_debuglink section, then this may be an object |
162 | // containing DWARF debug info for .gnu_debuglink, so calculate the crc of |
163 | // the object itself. |
164 | auto raw_data = coff_obj.getData(); |
165 | LLDB_SCOPED_TIMERF( |
166 | "Calculating module crc32 %s with size %" PRIu64 " KiB" , |
167 | FileSpec(coff_obj.getFileName()).GetFilename().AsCString(), |
168 | static_cast<lldb::offset_t>(raw_data.size()) / 1024); |
169 | gnu_debuglink_crc = llvm::crc32(CRC: 0, Data: llvm::arrayRefFromStringRef(Input: raw_data)); |
170 | } |
171 | // Use 4 bytes of crc from the .gnu_debuglink section. |
172 | llvm::support::ulittle32_t data(gnu_debuglink_crc); |
173 | return UUID(&data, sizeof(data)); |
174 | } |
175 | |
176 | char ObjectFilePECOFF::ID; |
177 | |
178 | void ObjectFilePECOFF::Initialize() { |
179 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
180 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance, |
181 | create_memory_callback: CreateMemoryInstance, get_module_specifications: GetModuleSpecifications, |
182 | save_core: SaveCore, debugger_init_callback: DebuggerInitialize); |
183 | } |
184 | |
185 | void ObjectFilePECOFF::DebuggerInitialize(Debugger &debugger) { |
186 | if (!PluginManager::GetSettingForObjectFilePlugin( |
187 | debugger, setting_name: PluginProperties::GetSettingName())) { |
188 | const bool is_global_setting = true; |
189 | PluginManager::CreateSettingForObjectFilePlugin( |
190 | debugger, properties_sp: GetGlobalPluginProperties().GetValueProperties(), |
191 | description: "Properties for the PE/COFF object-file plug-in." , is_global_property: is_global_setting); |
192 | } |
193 | } |
194 | |
195 | void ObjectFilePECOFF::Terminate() { |
196 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
197 | } |
198 | |
199 | llvm::StringRef ObjectFilePECOFF::GetPluginDescriptionStatic() { |
200 | return "Portable Executable and Common Object File Format object file reader " |
201 | "(32 and 64 bit)" ; |
202 | } |
203 | |
204 | ObjectFile *ObjectFilePECOFF::CreateInstance( |
205 | const lldb::ModuleSP &module_sp, DataBufferSP data_sp, |
206 | lldb::offset_t data_offset, const lldb_private::FileSpec *file_p, |
207 | lldb::offset_t file_offset, lldb::offset_t length) { |
208 | FileSpec file = file_p ? *file_p : FileSpec(); |
209 | if (!data_sp) { |
210 | data_sp = MapFileData(file, Size: length, Offset: file_offset); |
211 | if (!data_sp) |
212 | return nullptr; |
213 | data_offset = 0; |
214 | } |
215 | |
216 | if (!ObjectFilePECOFF::MagicBytesMatch(data_sp)) |
217 | return nullptr; |
218 | |
219 | // Update the data to contain the entire file if it doesn't already |
220 | if (data_sp->GetByteSize() < length) { |
221 | data_sp = MapFileData(file, Size: length, Offset: file_offset); |
222 | if (!data_sp) |
223 | return nullptr; |
224 | } |
225 | |
226 | auto objfile_up = std::make_unique<ObjectFilePECOFF>( |
227 | args: module_sp, args&: data_sp, args&: data_offset, args&: file_p, args&: file_offset, args&: length); |
228 | if (!objfile_up || !objfile_up->ParseHeader()) |
229 | return nullptr; |
230 | |
231 | // Cache coff binary. |
232 | if (!objfile_up->CreateBinary()) |
233 | return nullptr; |
234 | return objfile_up.release(); |
235 | } |
236 | |
237 | ObjectFile *ObjectFilePECOFF::CreateMemoryInstance( |
238 | const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, |
239 | const lldb::ProcessSP &process_sp, lldb::addr_t ) { |
240 | if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)) |
241 | return nullptr; |
242 | auto objfile_up = std::make_unique<ObjectFilePECOFF>( |
243 | args: module_sp, args&: data_sp, args: process_sp, args&: header_addr); |
244 | if (objfile_up.get() && objfile_up->ParseHeader()) { |
245 | return objfile_up.release(); |
246 | } |
247 | return nullptr; |
248 | } |
249 | |
250 | size_t ObjectFilePECOFF::GetModuleSpecifications( |
251 | const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, |
252 | lldb::offset_t data_offset, lldb::offset_t file_offset, |
253 | lldb::offset_t length, lldb_private::ModuleSpecList &specs) { |
254 | const size_t initial_count = specs.GetSize(); |
255 | if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp)) |
256 | return initial_count; |
257 | |
258 | Log *log = GetLog(mask: LLDBLog::Object); |
259 | |
260 | if (data_sp->GetByteSize() < length) |
261 | if (DataBufferSP full_sp = MapFileData(file, Size: -1, Offset: file_offset)) |
262 | data_sp = std::move(full_sp); |
263 | auto binary = llvm::object::createBinary(Source: llvm::MemoryBufferRef( |
264 | toStringRef(Input: data_sp->GetData()), file.GetFilename().GetStringRef())); |
265 | |
266 | if (!binary) { |
267 | LLDB_LOG_ERROR(log, binary.takeError(), |
268 | "Failed to create binary for file ({1}): {0}" , file); |
269 | return initial_count; |
270 | } |
271 | |
272 | auto *COFFObj = llvm::dyn_cast<llvm::object::COFFObjectFile>(Val: binary->get()); |
273 | if (!COFFObj) |
274 | return initial_count; |
275 | |
276 | ModuleSpec module_spec(file); |
277 | ArchSpec &spec = module_spec.GetArchitecture(); |
278 | lldb_private::UUID &uuid = module_spec.GetUUID(); |
279 | if (!uuid.IsValid()) |
280 | uuid = GetCoffUUID(coff_obj&: *COFFObj); |
281 | |
282 | static llvm::Triple::EnvironmentType default_env = [] { |
283 | auto def_target = llvm::Triple( |
284 | llvm::Triple::normalize(Str: llvm::sys::getDefaultTargetTriple())); |
285 | if (def_target.getOS() == llvm::Triple::Win32 && |
286 | def_target.getEnvironment() != llvm::Triple::UnknownEnvironment) |
287 | return def_target.getEnvironment(); |
288 | return llvm::Triple::MSVC; |
289 | }(); |
290 | |
291 | // Check for a module-specific override. |
292 | OptionValueSP module_env_option; |
293 | const auto *map = GetGlobalPluginProperties().ModuleABIMap(); |
294 | if (map->GetNumValues() > 0) { |
295 | // Step 1: Try with the exact file name. |
296 | auto name = file.GetFilename(); |
297 | module_env_option = map->GetValueForKey(key: name); |
298 | if (!module_env_option) { |
299 | // Step 2: Try with the file name in lowercase. |
300 | auto name_lower = name.GetStringRef().lower(); |
301 | module_env_option = map->GetValueForKey(key: llvm::StringRef(name_lower)); |
302 | } |
303 | if (!module_env_option) { |
304 | // Step 3: Try with the file name with ".debug" suffix stripped. |
305 | auto name_stripped = name.GetStringRef(); |
306 | if (name_stripped.consume_back_insensitive(Suffix: ".debug" )) { |
307 | module_env_option = map->GetValueForKey(key: name_stripped); |
308 | if (!module_env_option) { |
309 | // Step 4: Try with the file name in lowercase with ".debug" suffix |
310 | // stripped. |
311 | auto name_lower = name_stripped.lower(); |
312 | module_env_option = map->GetValueForKey(key: llvm::StringRef(name_lower)); |
313 | } |
314 | } |
315 | } |
316 | } |
317 | llvm::Triple::EnvironmentType env; |
318 | if (module_env_option) |
319 | env = |
320 | module_env_option->GetValueAs<llvm::Triple::EnvironmentType>().value_or( |
321 | u: static_cast<llvm::Triple::EnvironmentType>(0)); |
322 | else |
323 | env = GetGlobalPluginProperties().ABI(); |
324 | |
325 | if (env == llvm::Triple::UnknownEnvironment) |
326 | env = default_env; |
327 | |
328 | switch (COFFObj->getMachine()) { |
329 | case MachineAmd64: |
330 | spec.SetTriple("x86_64-pc-windows" ); |
331 | spec.GetTriple().setEnvironment(env); |
332 | specs.Append(spec: module_spec); |
333 | break; |
334 | case MachineX86: |
335 | spec.SetTriple("i386-pc-windows" ); |
336 | spec.GetTriple().setEnvironment(env); |
337 | specs.Append(spec: module_spec); |
338 | break; |
339 | case MachineArmNt: |
340 | spec.SetTriple("armv7-pc-windows" ); |
341 | spec.GetTriple().setEnvironment(env); |
342 | specs.Append(spec: module_spec); |
343 | break; |
344 | case MachineArm64: |
345 | case MachineArm64X: |
346 | spec.SetTriple("aarch64-pc-windows" ); |
347 | spec.GetTriple().setEnvironment(env); |
348 | specs.Append(spec: module_spec); |
349 | break; |
350 | default: |
351 | break; |
352 | } |
353 | |
354 | return specs.GetSize() - initial_count; |
355 | } |
356 | |
357 | bool ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp, |
358 | const lldb_private::FileSpec &outfile, |
359 | lldb::SaveCoreStyle &core_style, |
360 | lldb_private::Status &error) { |
361 | core_style = eSaveCoreFull; |
362 | return SaveMiniDump(process_sp, outfile, error); |
363 | } |
364 | |
365 | bool ObjectFilePECOFF::MagicBytesMatch(DataBufferSP data_sp) { |
366 | DataExtractor data(data_sp, eByteOrderLittle, 4); |
367 | lldb::offset_t offset = 0; |
368 | uint16_t magic = data.GetU16(offset_ptr: &offset); |
369 | return magic == IMAGE_DOS_SIGNATURE; |
370 | } |
371 | |
372 | lldb::SymbolType ObjectFilePECOFF::MapSymbolType(uint16_t coff_symbol_type) { |
373 | // TODO: We need to complete this mapping of COFF symbol types to LLDB ones. |
374 | // For now, here's a hack to make sure our function have types. |
375 | const auto complex_type = |
376 | coff_symbol_type >> llvm::COFF::SCT_COMPLEX_TYPE_SHIFT; |
377 | if (complex_type == llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION) { |
378 | return lldb::eSymbolTypeCode; |
379 | } |
380 | const auto base_type = coff_symbol_type & 0xff; |
381 | if (base_type == llvm::COFF::IMAGE_SYM_TYPE_NULL && |
382 | complex_type == llvm::COFF::IMAGE_SYM_DTYPE_NULL) { |
383 | // Unknown type. LLD and GNU ld uses this for variables on MinGW, so |
384 | // consider these symbols to be data to enable printing. |
385 | return lldb::eSymbolTypeData; |
386 | } |
387 | return lldb::eSymbolTypeInvalid; |
388 | } |
389 | |
390 | bool ObjectFilePECOFF::CreateBinary() { |
391 | if (m_binary) |
392 | return true; |
393 | |
394 | Log *log = GetLog(mask: LLDBLog::Object); |
395 | |
396 | auto binary = llvm::object::createBinary(Source: llvm::MemoryBufferRef( |
397 | toStringRef(Input: m_data.GetData()), m_file.GetFilename().GetStringRef())); |
398 | if (!binary) { |
399 | LLDB_LOG_ERROR(log, binary.takeError(), |
400 | "Failed to create binary for file ({1}): {0}" , m_file); |
401 | return false; |
402 | } |
403 | |
404 | // Make sure we only handle COFF format. |
405 | m_binary = |
406 | llvm::unique_dyn_cast<llvm::object::COFFObjectFile>(Val: std::move(*binary)); |
407 | if (!m_binary) |
408 | return false; |
409 | |
410 | LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}" , |
411 | this, GetModule().get(), GetModule()->GetSpecificationDescription(), |
412 | m_file.GetPath(), m_binary.get()); |
413 | return true; |
414 | } |
415 | |
416 | ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, |
417 | DataBufferSP data_sp, |
418 | lldb::offset_t data_offset, |
419 | const FileSpec *file, |
420 | lldb::offset_t file_offset, |
421 | lldb::offset_t length) |
422 | : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), |
423 | m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(), |
424 | m_image_base(LLDB_INVALID_ADDRESS), m_entry_point_address(), |
425 | m_deps_filespec() {} |
426 | |
427 | ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, |
428 | WritableDataBufferSP , |
429 | const lldb::ProcessSP &process_sp, |
430 | addr_t ) |
431 | : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), |
432 | m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(), |
433 | m_image_base(LLDB_INVALID_ADDRESS), m_entry_point_address(), |
434 | m_deps_filespec() {} |
435 | |
436 | ObjectFilePECOFF::~ObjectFilePECOFF() = default; |
437 | |
438 | bool ObjectFilePECOFF::() { |
439 | ModuleSP module_sp(GetModule()); |
440 | if (module_sp) { |
441 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); |
442 | m_sect_headers.clear(); |
443 | m_data.SetByteOrder(eByteOrderLittle); |
444 | lldb::offset_t offset = 0; |
445 | |
446 | if (ParseDOSHeader(data&: m_data, dos_header&: m_dos_header)) { |
447 | offset = m_dos_header.e_lfanew; |
448 | uint32_t pe_signature = m_data.GetU32(offset_ptr: &offset); |
449 | if (pe_signature != IMAGE_NT_SIGNATURE) |
450 | return false; |
451 | if (ParseCOFFHeader(data&: m_data, offset_ptr: &offset, coff_header&: m_coff_header)) { |
452 | if (m_coff_header.hdrsize > 0) |
453 | ParseCOFFOptionalHeader(offset_ptr: &offset); |
454 | ParseSectionHeaders(offset); |
455 | } |
456 | m_data.SetAddressByteSize(GetAddressByteSize()); |
457 | return true; |
458 | } |
459 | } |
460 | return false; |
461 | } |
462 | |
463 | bool ObjectFilePECOFF::SetLoadAddress(Target &target, addr_t value, |
464 | bool value_is_offset) { |
465 | bool changed = false; |
466 | ModuleSP module_sp = GetModule(); |
467 | if (module_sp) { |
468 | size_t num_loaded_sections = 0; |
469 | SectionList *section_list = GetSectionList(); |
470 | if (section_list) { |
471 | if (!value_is_offset) { |
472 | value -= m_image_base; |
473 | } |
474 | |
475 | const size_t num_sections = section_list->GetSize(); |
476 | size_t sect_idx = 0; |
477 | |
478 | for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { |
479 | // Iterate through the object file sections to find all of the sections |
480 | // that have SHF_ALLOC in their flag bits. |
481 | SectionSP section_sp(section_list->GetSectionAtIndex(idx: sect_idx)); |
482 | if (section_sp && !section_sp->IsThreadSpecific()) { |
483 | if (target.GetSectionLoadList().SetSectionLoadAddress( |
484 | section_sp, load_addr: section_sp->GetFileAddress() + value)) |
485 | ++num_loaded_sections; |
486 | } |
487 | } |
488 | changed = num_loaded_sections > 0; |
489 | } |
490 | } |
491 | return changed; |
492 | } |
493 | |
494 | ByteOrder ObjectFilePECOFF::GetByteOrder() const { return eByteOrderLittle; } |
495 | |
496 | bool ObjectFilePECOFF::IsExecutable() const { |
497 | return (m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0; |
498 | } |
499 | |
500 | uint32_t ObjectFilePECOFF::GetAddressByteSize() const { |
501 | if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32_PLUS) |
502 | return 8; |
503 | else if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) |
504 | return 4; |
505 | return 4; |
506 | } |
507 | |
508 | // NeedsEndianSwap |
509 | // |
510 | // Return true if an endian swap needs to occur when extracting data from this |
511 | // file. |
512 | bool ObjectFilePECOFF::NeedsEndianSwap() const { |
513 | #if defined(__LITTLE_ENDIAN__) |
514 | return false; |
515 | #else |
516 | return true; |
517 | #endif |
518 | } |
519 | // ParseDOSHeader |
520 | bool ObjectFilePECOFF::(DataExtractor &data, |
521 | dos_header_t &) { |
522 | bool success = false; |
523 | lldb::offset_t offset = 0; |
524 | success = data.ValidOffsetForDataOfSize(offset: 0, length: sizeof(dos_header)); |
525 | |
526 | if (success) { |
527 | dos_header.e_magic = data.GetU16(offset_ptr: &offset); // Magic number |
528 | success = dos_header.e_magic == IMAGE_DOS_SIGNATURE; |
529 | |
530 | if (success) { |
531 | dos_header.e_cblp = data.GetU16(offset_ptr: &offset); // Bytes on last page of file |
532 | dos_header.e_cp = data.GetU16(offset_ptr: &offset); // Pages in file |
533 | dos_header.e_crlc = data.GetU16(offset_ptr: &offset); // Relocations |
534 | dos_header.e_cparhdr = |
535 | data.GetU16(offset_ptr: &offset); // Size of header in paragraphs |
536 | dos_header.e_minalloc = |
537 | data.GetU16(offset_ptr: &offset); // Minimum extra paragraphs needed |
538 | dos_header.e_maxalloc = |
539 | data.GetU16(offset_ptr: &offset); // Maximum extra paragraphs needed |
540 | dos_header.e_ss = data.GetU16(offset_ptr: &offset); // Initial (relative) SS value |
541 | dos_header.e_sp = data.GetU16(offset_ptr: &offset); // Initial SP value |
542 | dos_header.e_csum = data.GetU16(offset_ptr: &offset); // Checksum |
543 | dos_header.e_ip = data.GetU16(offset_ptr: &offset); // Initial IP value |
544 | dos_header.e_cs = data.GetU16(offset_ptr: &offset); // Initial (relative) CS value |
545 | dos_header.e_lfarlc = |
546 | data.GetU16(offset_ptr: &offset); // File address of relocation table |
547 | dos_header.e_ovno = data.GetU16(offset_ptr: &offset); // Overlay number |
548 | |
549 | dos_header.e_res[0] = data.GetU16(offset_ptr: &offset); // Reserved words |
550 | dos_header.e_res[1] = data.GetU16(offset_ptr: &offset); // Reserved words |
551 | dos_header.e_res[2] = data.GetU16(offset_ptr: &offset); // Reserved words |
552 | dos_header.e_res[3] = data.GetU16(offset_ptr: &offset); // Reserved words |
553 | |
554 | dos_header.e_oemid = |
555 | data.GetU16(offset_ptr: &offset); // OEM identifier (for e_oeminfo) |
556 | dos_header.e_oeminfo = |
557 | data.GetU16(offset_ptr: &offset); // OEM information; e_oemid specific |
558 | dos_header.e_res2[0] = data.GetU16(offset_ptr: &offset); // Reserved words |
559 | dos_header.e_res2[1] = data.GetU16(offset_ptr: &offset); // Reserved words |
560 | dos_header.e_res2[2] = data.GetU16(offset_ptr: &offset); // Reserved words |
561 | dos_header.e_res2[3] = data.GetU16(offset_ptr: &offset); // Reserved words |
562 | dos_header.e_res2[4] = data.GetU16(offset_ptr: &offset); // Reserved words |
563 | dos_header.e_res2[5] = data.GetU16(offset_ptr: &offset); // Reserved words |
564 | dos_header.e_res2[6] = data.GetU16(offset_ptr: &offset); // Reserved words |
565 | dos_header.e_res2[7] = data.GetU16(offset_ptr: &offset); // Reserved words |
566 | dos_header.e_res2[8] = data.GetU16(offset_ptr: &offset); // Reserved words |
567 | dos_header.e_res2[9] = data.GetU16(offset_ptr: &offset); // Reserved words |
568 | |
569 | dos_header.e_lfanew = |
570 | data.GetU32(offset_ptr: &offset); // File address of new exe header |
571 | } |
572 | } |
573 | if (!success) |
574 | memset(s: &dos_header, c: 0, n: sizeof(dos_header)); |
575 | return success; |
576 | } |
577 | |
578 | // ParserCOFFHeader |
579 | bool ObjectFilePECOFF::(DataExtractor &data, |
580 | lldb::offset_t *offset_ptr, |
581 | coff_header_t &) { |
582 | bool success = |
583 | data.ValidOffsetForDataOfSize(offset: *offset_ptr, length: sizeof(coff_header)); |
584 | if (success) { |
585 | coff_header.machine = data.GetU16(offset_ptr); |
586 | coff_header.nsects = data.GetU16(offset_ptr); |
587 | coff_header.modtime = data.GetU32(offset_ptr); |
588 | coff_header.symoff = data.GetU32(offset_ptr); |
589 | coff_header.nsyms = data.GetU32(offset_ptr); |
590 | coff_header.hdrsize = data.GetU16(offset_ptr); |
591 | coff_header.flags = data.GetU16(offset_ptr); |
592 | } |
593 | if (!success) |
594 | memset(s: &coff_header, c: 0, n: sizeof(coff_header)); |
595 | return success; |
596 | } |
597 | |
598 | bool ObjectFilePECOFF::(lldb::offset_t *offset_ptr) { |
599 | bool success = false; |
600 | const lldb::offset_t end_offset = *offset_ptr + m_coff_header.hdrsize; |
601 | if (*offset_ptr < end_offset) { |
602 | success = true; |
603 | m_coff_header_opt.magic = m_data.GetU16(offset_ptr); |
604 | m_coff_header_opt.major_linker_version = m_data.GetU8(offset_ptr); |
605 | m_coff_header_opt.minor_linker_version = m_data.GetU8(offset_ptr); |
606 | m_coff_header_opt.code_size = m_data.GetU32(offset_ptr); |
607 | m_coff_header_opt.data_size = m_data.GetU32(offset_ptr); |
608 | m_coff_header_opt.bss_size = m_data.GetU32(offset_ptr); |
609 | m_coff_header_opt.entry = m_data.GetU32(offset_ptr); |
610 | m_coff_header_opt.code_offset = m_data.GetU32(offset_ptr); |
611 | |
612 | const uint32_t addr_byte_size = GetAddressByteSize(); |
613 | |
614 | if (*offset_ptr < end_offset) { |
615 | if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) { |
616 | // PE32 only |
617 | m_coff_header_opt.data_offset = m_data.GetU32(offset_ptr); |
618 | } else |
619 | m_coff_header_opt.data_offset = 0; |
620 | |
621 | if (*offset_ptr < end_offset) { |
622 | m_coff_header_opt.image_base = |
623 | m_data.GetMaxU64(offset_ptr, byte_size: addr_byte_size); |
624 | m_coff_header_opt.sect_alignment = m_data.GetU32(offset_ptr); |
625 | m_coff_header_opt.file_alignment = m_data.GetU32(offset_ptr); |
626 | m_coff_header_opt.major_os_system_version = m_data.GetU16(offset_ptr); |
627 | m_coff_header_opt.minor_os_system_version = m_data.GetU16(offset_ptr); |
628 | m_coff_header_opt.major_image_version = m_data.GetU16(offset_ptr); |
629 | m_coff_header_opt.minor_image_version = m_data.GetU16(offset_ptr); |
630 | m_coff_header_opt.major_subsystem_version = m_data.GetU16(offset_ptr); |
631 | m_coff_header_opt.minor_subsystem_version = m_data.GetU16(offset_ptr); |
632 | m_coff_header_opt.reserved1 = m_data.GetU32(offset_ptr); |
633 | m_coff_header_opt.image_size = m_data.GetU32(offset_ptr); |
634 | m_coff_header_opt.header_size = m_data.GetU32(offset_ptr); |
635 | m_coff_header_opt.checksum = m_data.GetU32(offset_ptr); |
636 | m_coff_header_opt.subsystem = m_data.GetU16(offset_ptr); |
637 | m_coff_header_opt.dll_flags = m_data.GetU16(offset_ptr); |
638 | m_coff_header_opt.stack_reserve_size = |
639 | m_data.GetMaxU64(offset_ptr, byte_size: addr_byte_size); |
640 | m_coff_header_opt.stack_commit_size = |
641 | m_data.GetMaxU64(offset_ptr, byte_size: addr_byte_size); |
642 | m_coff_header_opt.heap_reserve_size = |
643 | m_data.GetMaxU64(offset_ptr, byte_size: addr_byte_size); |
644 | m_coff_header_opt.heap_commit_size = |
645 | m_data.GetMaxU64(offset_ptr, byte_size: addr_byte_size); |
646 | m_coff_header_opt.loader_flags = m_data.GetU32(offset_ptr); |
647 | uint32_t num_data_dir_entries = m_data.GetU32(offset_ptr); |
648 | m_coff_header_opt.data_dirs.clear(); |
649 | m_coff_header_opt.data_dirs.resize(new_size: num_data_dir_entries); |
650 | uint32_t i; |
651 | for (i = 0; i < num_data_dir_entries; i++) { |
652 | m_coff_header_opt.data_dirs[i].vmaddr = m_data.GetU32(offset_ptr); |
653 | m_coff_header_opt.data_dirs[i].vmsize = m_data.GetU32(offset_ptr); |
654 | } |
655 | |
656 | m_image_base = m_coff_header_opt.image_base; |
657 | } |
658 | } |
659 | } |
660 | // Make sure we are on track for section data which follows |
661 | *offset_ptr = end_offset; |
662 | return success; |
663 | } |
664 | |
665 | uint32_t ObjectFilePECOFF::GetRVA(const Address &addr) const { |
666 | return addr.GetFileAddress() - m_image_base; |
667 | } |
668 | |
669 | Address ObjectFilePECOFF::GetAddress(uint32_t rva) { |
670 | SectionList *sect_list = GetSectionList(); |
671 | if (!sect_list) |
672 | return Address(GetFileAddress(rva)); |
673 | |
674 | return Address(GetFileAddress(rva), sect_list); |
675 | } |
676 | |
677 | lldb::addr_t ObjectFilePECOFF::GetFileAddress(uint32_t rva) const { |
678 | return m_image_base + rva; |
679 | } |
680 | |
681 | DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) { |
682 | if (!size) |
683 | return {}; |
684 | |
685 | if (m_data.ValidOffsetForDataOfSize(offset, length: size)) |
686 | return DataExtractor(m_data, offset, size); |
687 | |
688 | ProcessSP process_sp(m_process_wp.lock()); |
689 | DataExtractor data; |
690 | if (process_sp) { |
691 | auto data_up = std::make_unique<DataBufferHeap>(args&: size, args: 0); |
692 | Status readmem_error; |
693 | size_t bytes_read = |
694 | process_sp->ReadMemory(vm_addr: m_image_base + offset, buf: data_up->GetBytes(), |
695 | size: data_up->GetByteSize(), error&: readmem_error); |
696 | if (bytes_read == size) { |
697 | DataBufferSP buffer_sp(data_up.release()); |
698 | data.SetData(data_sp: buffer_sp, offset: 0, length: buffer_sp->GetByteSize()); |
699 | } |
700 | } |
701 | return data; |
702 | } |
703 | |
704 | DataExtractor ObjectFilePECOFF::ReadImageDataByRVA(uint32_t rva, size_t size) { |
705 | Address addr = GetAddress(rva); |
706 | SectionSP sect = addr.GetSection(); |
707 | if (!sect) |
708 | return {}; |
709 | rva = sect->GetFileOffset() + addr.GetOffset(); |
710 | |
711 | return ReadImageData(offset: rva, size); |
712 | } |
713 | |
714 | // ParseSectionHeaders |
715 | bool ObjectFilePECOFF::( |
716 | uint32_t ) { |
717 | const uint32_t nsects = m_coff_header.nsects; |
718 | m_sect_headers.clear(); |
719 | |
720 | if (nsects > 0) { |
721 | const size_t = nsects * sizeof(section_header_t); |
722 | DataExtractor = |
723 | ReadImageData(offset: section_header_data_offset, size: section_header_byte_size); |
724 | |
725 | lldb::offset_t offset = 0; |
726 | if (section_header_data.ValidOffsetForDataOfSize( |
727 | offset, length: section_header_byte_size)) { |
728 | m_sect_headers.resize(new_size: nsects); |
729 | |
730 | for (uint32_t idx = 0; idx < nsects; ++idx) { |
731 | const void *name_data = section_header_data.GetData(offset_ptr: &offset, length: 8); |
732 | if (name_data) { |
733 | memcpy(dest: m_sect_headers[idx].name, src: name_data, n: 8); |
734 | m_sect_headers[idx].vmsize = section_header_data.GetU32(offset_ptr: &offset); |
735 | m_sect_headers[idx].vmaddr = section_header_data.GetU32(offset_ptr: &offset); |
736 | m_sect_headers[idx].size = section_header_data.GetU32(offset_ptr: &offset); |
737 | m_sect_headers[idx].offset = section_header_data.GetU32(offset_ptr: &offset); |
738 | m_sect_headers[idx].reloff = section_header_data.GetU32(offset_ptr: &offset); |
739 | m_sect_headers[idx].lineoff = section_header_data.GetU32(offset_ptr: &offset); |
740 | m_sect_headers[idx].nreloc = section_header_data.GetU16(offset_ptr: &offset); |
741 | m_sect_headers[idx].nline = section_header_data.GetU16(offset_ptr: &offset); |
742 | m_sect_headers[idx].flags = section_header_data.GetU32(offset_ptr: &offset); |
743 | } |
744 | } |
745 | } |
746 | } |
747 | |
748 | return !m_sect_headers.empty(); |
749 | } |
750 | |
751 | llvm::StringRef ObjectFilePECOFF::(const section_header_t §) { |
752 | llvm::StringRef hdr_name(sect.name, std::size(sect.name)); |
753 | hdr_name = hdr_name.split(Separator: '\0').first; |
754 | if (hdr_name.consume_front(Prefix: "/" )) { |
755 | lldb::offset_t stroff; |
756 | if (!to_integer(S: hdr_name, Num&: stroff, Base: 10)) |
757 | return "" ; |
758 | lldb::offset_t string_file_offset = |
759 | m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff; |
760 | if (const char *name = m_data.GetCStr(offset_ptr: &string_file_offset)) |
761 | return name; |
762 | return "" ; |
763 | } |
764 | return hdr_name; |
765 | } |
766 | |
767 | void ObjectFilePECOFF::ParseSymtab(Symtab &symtab) { |
768 | SectionList *sect_list = GetSectionList(); |
769 | rva_symbol_list_t sorted_exports = AppendFromExportTable(sect_list, symtab); |
770 | AppendFromCOFFSymbolTable(sect_list, symtab, sorted_exports); |
771 | } |
772 | |
773 | static bool RVASymbolListCompareRVA(const std::pair<uint32_t, uint32_t> &a, |
774 | const std::pair<uint32_t, uint32_t> &b) { |
775 | return a.first < b.first; |
776 | } |
777 | |
778 | void ObjectFilePECOFF::AppendFromCOFFSymbolTable( |
779 | SectionList *sect_list, Symtab &symtab, |
780 | const ObjectFilePECOFF::rva_symbol_list_t &sorted_exports) { |
781 | const uint32_t num_syms = m_binary->getNumberOfSymbols(); |
782 | if (num_syms == 0) |
783 | return; |
784 | // Check that this is not a bigobj; we do not support bigobj. |
785 | if (m_binary->getSymbolTableEntrySize() != |
786 | sizeof(llvm::object::coff_symbol16)) |
787 | return; |
788 | |
789 | Log *log = GetLog(mask: LLDBLog::Object); |
790 | symtab.Reserve(count: symtab.GetNumSymbols() + num_syms); |
791 | for (const auto &sym_ref : m_binary->symbols()) { |
792 | const auto coff_sym_ref = m_binary->getCOFFSymbol(Symbol: sym_ref); |
793 | auto name_or_error = sym_ref.getName(); |
794 | if (!name_or_error) { |
795 | LLDB_LOG_ERROR(log, name_or_error.takeError(), |
796 | "ObjectFilePECOFF::AppendFromCOFFSymbolTable - failed to " |
797 | "get symbol table entry name: {0}" ); |
798 | continue; |
799 | } |
800 | const llvm::StringRef sym_name = *name_or_error; |
801 | Symbol symbol; |
802 | symbol.GetMangled().SetValue(ConstString(sym_name)); |
803 | int16_t section_number = |
804 | static_cast<int16_t>(coff_sym_ref.getSectionNumber()); |
805 | if (section_number >= 1) { |
806 | symbol.GetAddressRef() = Address( |
807 | sect_list->FindSectionByID(sect_id: section_number), coff_sym_ref.getValue()); |
808 | const auto symbol_type = MapSymbolType(coff_symbol_type: coff_sym_ref.getType()); |
809 | symbol.SetType(symbol_type); |
810 | |
811 | // Check for duplicate of exported symbols: |
812 | const uint32_t symbol_rva = symbol.GetAddressRef().GetFileAddress() - |
813 | m_coff_header_opt.image_base; |
814 | const auto &first_match = std::lower_bound( |
815 | first: sorted_exports.begin(), last: sorted_exports.end(), |
816 | val: std::make_pair(x: symbol_rva, y: 0), comp: RVASymbolListCompareRVA); |
817 | for (auto it = first_match; |
818 | it != sorted_exports.end() && it->first == symbol_rva; ++it) { |
819 | Symbol *exported = symtab.SymbolAtIndex(idx: it->second); |
820 | if (symbol_type != lldb::eSymbolTypeInvalid) |
821 | exported->SetType(symbol_type); |
822 | if (exported->GetMangled() == symbol.GetMangled()) { |
823 | symbol.SetExternal(true); |
824 | // We don't want the symbol to be duplicated (e.g. when running |
825 | // `disas -n func`), but we also don't want to erase this entry (to |
826 | // preserve the original symbol order), so we mark it as additional. |
827 | symbol.SetType(lldb::eSymbolTypeAdditional); |
828 | } else { |
829 | // It is possible for a symbol to be exported in a different name |
830 | // from its original. In this case keep both entries so lookup using |
831 | // either names will work. If this symbol has an invalid type, replace |
832 | // it with the type from the export symbol. |
833 | if (symbol.GetType() == lldb::eSymbolTypeInvalid) |
834 | symbol.SetType(exported->GetType()); |
835 | } |
836 | } |
837 | } else if (section_number == llvm::COFF::IMAGE_SYM_ABSOLUTE) { |
838 | symbol.GetAddressRef() = Address(coff_sym_ref.getValue()); |
839 | symbol.SetType(lldb::eSymbolTypeAbsolute); |
840 | } |
841 | symtab.AddSymbol(symbol); |
842 | } |
843 | } |
844 | |
845 | ObjectFilePECOFF::rva_symbol_list_t |
846 | ObjectFilePECOFF::AppendFromExportTable(SectionList *sect_list, |
847 | Symtab &symtab) { |
848 | const auto *export_table = m_binary->getExportTable(); |
849 | if (!export_table) |
850 | return {}; |
851 | const uint32_t num_syms = export_table->AddressTableEntries; |
852 | if (num_syms == 0) |
853 | return {}; |
854 | |
855 | Log *log = GetLog(mask: LLDBLog::Object); |
856 | rva_symbol_list_t export_list; |
857 | symtab.Reserve(count: symtab.GetNumSymbols() + num_syms); |
858 | // Read each export table entry, ordered by ordinal instead of by name. |
859 | for (const auto &entry : m_binary->export_directories()) { |
860 | llvm::StringRef sym_name; |
861 | if (auto err = entry.getSymbolName(Result&: sym_name)) { |
862 | if (log) |
863 | log->Format( |
864 | __FILE__, function: __func__, |
865 | format: "ObjectFilePECOFF::AppendFromExportTable - failed to get export " |
866 | "table entry name: {0}" , |
867 | args: llvm::fmt_consume(Item: std::move(err))); |
868 | else |
869 | llvm::consumeError(Err: std::move(err)); |
870 | continue; |
871 | } |
872 | Symbol symbol; |
873 | // Note: symbol name may be empty if it is only exported by ordinal. |
874 | symbol.GetMangled().SetValue(ConstString(sym_name)); |
875 | |
876 | uint32_t ordinal; |
877 | llvm::cantFail(Err: entry.getOrdinal(Result&: ordinal)); |
878 | symbol.SetID(ordinal); |
879 | |
880 | bool is_forwarder; |
881 | llvm::cantFail(Err: entry.isForwarder(Result&: is_forwarder)); |
882 | if (is_forwarder) { |
883 | // Forwarder exports are redirected by the loader transparently, but keep |
884 | // it in symtab and make a note using the symbol name. |
885 | llvm::StringRef forwarder_name; |
886 | if (auto err = entry.getForwardTo(Result&: forwarder_name)) { |
887 | if (log) |
888 | log->Format(__FILE__, function: __func__, |
889 | format: "ObjectFilePECOFF::AppendFromExportTable - failed to get " |
890 | "forwarder name of forwarder export '{0}': {1}" , |
891 | args&: sym_name, args: llvm::fmt_consume(Item: std::move(err))); |
892 | else |
893 | llvm::consumeError(Err: std::move(err)); |
894 | continue; |
895 | } |
896 | llvm::SmallString<256> new_name = {symbol.GetDisplayName().GetStringRef(), |
897 | " (forwarded to " , forwarder_name, |
898 | ")" }; |
899 | symbol.GetMangled().SetDemangledName(ConstString(new_name.str())); |
900 | symbol.SetDemangledNameIsSynthesized(true); |
901 | } |
902 | |
903 | uint32_t function_rva; |
904 | if (auto err = entry.getExportRVA(Result&: function_rva)) { |
905 | if (log) |
906 | log->Format(__FILE__, function: __func__, |
907 | format: "ObjectFilePECOFF::AppendFromExportTable - failed to get " |
908 | "address of export entry '{0}': {1}" , |
909 | args&: sym_name, args: llvm::fmt_consume(Item: std::move(err))); |
910 | else |
911 | llvm::consumeError(Err: std::move(err)); |
912 | continue; |
913 | } |
914 | // Skip the symbol if it doesn't look valid. |
915 | if (function_rva == 0 && sym_name.empty()) |
916 | continue; |
917 | symbol.GetAddressRef() = |
918 | Address(m_coff_header_opt.image_base + function_rva, sect_list); |
919 | |
920 | // An exported symbol may be either code or data. Guess by checking whether |
921 | // the section containing the symbol is executable. |
922 | symbol.SetType(lldb::eSymbolTypeData); |
923 | if (!is_forwarder) |
924 | if (auto section_sp = symbol.GetAddressRef().GetSection()) |
925 | if (section_sp->GetPermissions() & ePermissionsExecutable) |
926 | symbol.SetType(lldb::eSymbolTypeCode); |
927 | symbol.SetExternal(true); |
928 | uint32_t idx = symtab.AddSymbol(symbol); |
929 | export_list.push_back(x: std::make_pair(x&: function_rva, y&: idx)); |
930 | } |
931 | std::stable_sort(first: export_list.begin(), last: export_list.end(), |
932 | comp: RVASymbolListCompareRVA); |
933 | return export_list; |
934 | } |
935 | |
936 | std::unique_ptr<CallFrameInfo> ObjectFilePECOFF::CreateCallFrameInfo() { |
937 | if (llvm::COFF::EXCEPTION_TABLE >= m_coff_header_opt.data_dirs.size()) |
938 | return {}; |
939 | |
940 | data_directory data_dir_exception = |
941 | m_coff_header_opt.data_dirs[llvm::COFF::EXCEPTION_TABLE]; |
942 | if (!data_dir_exception.vmaddr) |
943 | return {}; |
944 | |
945 | if (m_coff_header.machine != llvm::COFF::IMAGE_FILE_MACHINE_AMD64) |
946 | return {}; |
947 | |
948 | return std::make_unique<PECallFrameInfo>(args&: *this, args&: data_dir_exception.vmaddr, |
949 | args&: data_dir_exception.vmsize); |
950 | } |
951 | |
952 | bool ObjectFilePECOFF::IsStripped() { |
953 | // TODO: determine this for COFF |
954 | return false; |
955 | } |
956 | |
957 | SectionType ObjectFilePECOFF::(llvm::StringRef sect_name, |
958 | const section_header_t §) { |
959 | ConstString const_sect_name(sect_name); |
960 | static ConstString g_code_sect_name(".code" ); |
961 | static ConstString g_CODE_sect_name("CODE" ); |
962 | static ConstString g_data_sect_name(".data" ); |
963 | static ConstString g_DATA_sect_name("DATA" ); |
964 | static ConstString g_bss_sect_name(".bss" ); |
965 | static ConstString g_BSS_sect_name("BSS" ); |
966 | |
967 | if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_CODE && |
968 | ((const_sect_name == g_code_sect_name) || |
969 | (const_sect_name == g_CODE_sect_name))) { |
970 | return eSectionTypeCode; |
971 | } |
972 | if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA && |
973 | ((const_sect_name == g_data_sect_name) || |
974 | (const_sect_name == g_DATA_sect_name))) { |
975 | if (sect.size == 0 && sect.offset == 0) |
976 | return eSectionTypeZeroFill; |
977 | else |
978 | return eSectionTypeData; |
979 | } |
980 | if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA && |
981 | ((const_sect_name == g_bss_sect_name) || |
982 | (const_sect_name == g_BSS_sect_name))) { |
983 | if (sect.size == 0) |
984 | return eSectionTypeZeroFill; |
985 | else |
986 | return eSectionTypeData; |
987 | } |
988 | |
989 | SectionType section_type = |
990 | llvm::StringSwitch<SectionType>(sect_name) |
991 | .Case(S: ".debug" , Value: eSectionTypeDebug) |
992 | .Case(S: ".stabstr" , Value: eSectionTypeDataCString) |
993 | .Case(S: ".reloc" , Value: eSectionTypeOther) |
994 | .Case(S: ".debug_abbrev" , Value: eSectionTypeDWARFDebugAbbrev) |
995 | .Case(S: ".debug_aranges" , Value: eSectionTypeDWARFDebugAranges) |
996 | .Case(S: ".debug_frame" , Value: eSectionTypeDWARFDebugFrame) |
997 | .Case(S: ".debug_info" , Value: eSectionTypeDWARFDebugInfo) |
998 | .Case(S: ".debug_line" , Value: eSectionTypeDWARFDebugLine) |
999 | .Case(S: ".debug_loc" , Value: eSectionTypeDWARFDebugLoc) |
1000 | .Case(S: ".debug_loclists" , Value: eSectionTypeDWARFDebugLocLists) |
1001 | .Case(S: ".debug_macinfo" , Value: eSectionTypeDWARFDebugMacInfo) |
1002 | .Case(S: ".debug_names" , Value: eSectionTypeDWARFDebugNames) |
1003 | .Case(S: ".debug_pubnames" , Value: eSectionTypeDWARFDebugPubNames) |
1004 | .Case(S: ".debug_pubtypes" , Value: eSectionTypeDWARFDebugPubTypes) |
1005 | .Case(S: ".debug_ranges" , Value: eSectionTypeDWARFDebugRanges) |
1006 | .Case(S: ".debug_str" , Value: eSectionTypeDWARFDebugStr) |
1007 | .Case(S: ".debug_types" , Value: eSectionTypeDWARFDebugTypes) |
1008 | // .eh_frame can be truncated to 8 chars. |
1009 | .Cases(S0: ".eh_frame" , S1: ".eh_fram" , Value: eSectionTypeEHFrame) |
1010 | .Case(S: ".gosymtab" , Value: eSectionTypeGoSymtab) |
1011 | .Case(S: "swiftast" , Value: eSectionTypeSwiftModules) |
1012 | .Default(Value: eSectionTypeInvalid); |
1013 | if (section_type != eSectionTypeInvalid) |
1014 | return section_type; |
1015 | |
1016 | if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_CODE) |
1017 | return eSectionTypeCode; |
1018 | if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) |
1019 | return eSectionTypeData; |
1020 | if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) { |
1021 | if (sect.size == 0) |
1022 | return eSectionTypeZeroFill; |
1023 | else |
1024 | return eSectionTypeData; |
1025 | } |
1026 | return eSectionTypeOther; |
1027 | } |
1028 | |
1029 | size_t ObjectFilePECOFF::GetSectionDataSize(Section *section) { |
1030 | // For executables, SizeOfRawData (getFileSize()) is aligned by |
1031 | // FileAlignment and the actual section size is in VirtualSize |
1032 | // (getByteSize()). See the comment on |
1033 | // llvm::object::COFFObjectFile::getSectionSize(). |
1034 | if (m_binary->getPE32Header() || m_binary->getPE32PlusHeader()) |
1035 | return std::min(a: section->GetByteSize(), b: section->GetFileSize()); |
1036 | return section->GetFileSize(); |
1037 | } |
1038 | |
1039 | void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) { |
1040 | if (m_sections_up) |
1041 | return; |
1042 | m_sections_up = std::make_unique<SectionList>(); |
1043 | ModuleSP module_sp(GetModule()); |
1044 | if (module_sp) { |
1045 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); |
1046 | |
1047 | SectionSP = std::make_shared<Section>( |
1048 | args&: module_sp, args: this, args: ~user_id_t(0), args: ConstString("PECOFF header" ), |
1049 | args: eSectionTypeOther, args&: m_coff_header_opt.image_base, |
1050 | args&: m_coff_header_opt.header_size, |
1051 | /*file_offset*/ args: 0, args&: m_coff_header_opt.header_size, |
1052 | args&: m_coff_header_opt.sect_alignment, |
1053 | /*flags*/ args: 0); |
1054 | header_sp->SetPermissions(ePermissionsReadable); |
1055 | m_sections_up->AddSection(section_sp: header_sp); |
1056 | unified_section_list.AddSection(section_sp: header_sp); |
1057 | |
1058 | const uint32_t nsects = m_sect_headers.size(); |
1059 | for (uint32_t idx = 0; idx < nsects; ++idx) { |
1060 | llvm::StringRef sect_name = GetSectionName(sect: m_sect_headers[idx]); |
1061 | ConstString const_sect_name(sect_name); |
1062 | SectionType section_type = GetSectionType(sect_name, sect: m_sect_headers[idx]); |
1063 | |
1064 | SectionSP section_sp(new Section( |
1065 | module_sp, // Module to which this section belongs |
1066 | this, // Object file to which this section belongs |
1067 | idx + 1, // Section ID is the 1 based section index. |
1068 | const_sect_name, // Name of this section |
1069 | section_type, |
1070 | m_coff_header_opt.image_base + |
1071 | m_sect_headers[idx].vmaddr, // File VM address == addresses as |
1072 | // they are found in the object file |
1073 | m_sect_headers[idx].vmsize, // VM size in bytes of this section |
1074 | m_sect_headers[idx] |
1075 | .offset, // Offset to the data for this section in the file |
1076 | m_sect_headers[idx] |
1077 | .size, // Size in bytes of this section as found in the file |
1078 | m_coff_header_opt.sect_alignment, // Section alignment |
1079 | m_sect_headers[idx].flags)); // Flags for this section |
1080 | |
1081 | uint32_t permissions = 0; |
1082 | if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) |
1083 | permissions |= ePermissionsExecutable; |
1084 | if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_MEM_READ) |
1085 | permissions |= ePermissionsReadable; |
1086 | if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_MEM_WRITE) |
1087 | permissions |= ePermissionsWritable; |
1088 | section_sp->SetPermissions(permissions); |
1089 | |
1090 | m_sections_up->AddSection(section_sp); |
1091 | unified_section_list.AddSection(section_sp); |
1092 | } |
1093 | } |
1094 | } |
1095 | |
1096 | UUID ObjectFilePECOFF::GetUUID() { |
1097 | if (m_uuid.IsValid()) |
1098 | return m_uuid; |
1099 | |
1100 | if (!CreateBinary()) |
1101 | return UUID(); |
1102 | |
1103 | m_uuid = GetCoffUUID(coff_obj&: *m_binary); |
1104 | return m_uuid; |
1105 | } |
1106 | |
1107 | std::optional<FileSpec> ObjectFilePECOFF::GetDebugLink() { |
1108 | std::string gnu_debuglink_file; |
1109 | uint32_t gnu_debuglink_crc; |
1110 | if (GetDebugLinkContents(coff_obj: *m_binary, gnu_debuglink_file, gnu_debuglink_crc)) |
1111 | return FileSpec(gnu_debuglink_file); |
1112 | return std::nullopt; |
1113 | } |
1114 | |
1115 | uint32_t ObjectFilePECOFF::ParseDependentModules() { |
1116 | ModuleSP module_sp(GetModule()); |
1117 | if (!module_sp) |
1118 | return 0; |
1119 | |
1120 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); |
1121 | if (m_deps_filespec) |
1122 | return m_deps_filespec->GetSize(); |
1123 | |
1124 | // Cache coff binary if it is not done yet. |
1125 | if (!CreateBinary()) |
1126 | return 0; |
1127 | |
1128 | Log *log = GetLog(mask: LLDBLog::Object); |
1129 | LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}" , |
1130 | this, GetModule().get(), GetModule()->GetSpecificationDescription(), |
1131 | m_file.GetPath(), m_binary.get()); |
1132 | |
1133 | m_deps_filespec = FileSpecList(); |
1134 | |
1135 | for (const auto &entry : m_binary->import_directories()) { |
1136 | llvm::StringRef dll_name; |
1137 | // Report a bogus entry. |
1138 | if (llvm::Error e = entry.getName(Result&: dll_name)) { |
1139 | LLDB_LOGF(log, |
1140 | "ObjectFilePECOFF::ParseDependentModules() - failed to get " |
1141 | "import directory entry name: %s" , |
1142 | llvm::toString(std::move(e)).c_str()); |
1143 | continue; |
1144 | } |
1145 | |
1146 | // At this moment we only have the base name of the DLL. The full path can |
1147 | // only be seen after the dynamic loading. Our best guess is Try to get it |
1148 | // with the help of the object file's directory. |
1149 | llvm::SmallString<128> dll_fullpath; |
1150 | FileSpec dll_specs(dll_name); |
1151 | dll_specs.SetDirectory(m_file.GetDirectory()); |
1152 | |
1153 | if (!llvm::sys::fs::real_path(path: dll_specs.GetPath(), output&: dll_fullpath)) |
1154 | m_deps_filespec->EmplaceBack(args&: dll_fullpath); |
1155 | else { |
1156 | // Known DLLs or DLL not found in the object file directory. |
1157 | m_deps_filespec->EmplaceBack(args&: dll_name); |
1158 | } |
1159 | } |
1160 | return m_deps_filespec->GetSize(); |
1161 | } |
1162 | |
1163 | uint32_t ObjectFilePECOFF::GetDependentModules(FileSpecList &files) { |
1164 | auto num_modules = ParseDependentModules(); |
1165 | auto original_size = files.GetSize(); |
1166 | |
1167 | for (unsigned i = 0; i < num_modules; ++i) |
1168 | files.AppendIfUnique(file: m_deps_filespec->GetFileSpecAtIndex(idx: i)); |
1169 | |
1170 | return files.GetSize() - original_size; |
1171 | } |
1172 | |
1173 | lldb_private::Address ObjectFilePECOFF::GetEntryPointAddress() { |
1174 | if (m_entry_point_address.IsValid()) |
1175 | return m_entry_point_address; |
1176 | |
1177 | if (!ParseHeader() || !IsExecutable()) |
1178 | return m_entry_point_address; |
1179 | |
1180 | SectionList *section_list = GetSectionList(); |
1181 | addr_t file_addr = m_coff_header_opt.entry + m_coff_header_opt.image_base; |
1182 | |
1183 | if (!section_list) |
1184 | m_entry_point_address.SetOffset(file_addr); |
1185 | else |
1186 | m_entry_point_address.ResolveAddressUsingFileSections(addr: file_addr, |
1187 | sections: section_list); |
1188 | return m_entry_point_address; |
1189 | } |
1190 | |
1191 | Address ObjectFilePECOFF::GetBaseAddress() { |
1192 | return Address(GetSectionList()->GetSectionAtIndex(idx: 0), 0); |
1193 | } |
1194 | |
1195 | // Dump |
1196 | // |
1197 | // Dump the specifics of the runtime file container (such as any headers |
1198 | // segments, sections, etc). |
1199 | void ObjectFilePECOFF::Dump(Stream *s) { |
1200 | ModuleSP module_sp(GetModule()); |
1201 | if (module_sp) { |
1202 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); |
1203 | s->Printf(format: "%p: " , static_cast<void *>(this)); |
1204 | s->Indent(); |
1205 | s->PutCString(cstr: "ObjectFilePECOFF" ); |
1206 | |
1207 | ArchSpec = GetArchitecture(); |
1208 | |
1209 | *s << ", file = '" << m_file |
1210 | << "', arch = " << header_arch.GetArchitectureName() << "\n" ; |
1211 | |
1212 | SectionList *sections = GetSectionList(); |
1213 | if (sections) |
1214 | sections->Dump(s&: s->AsRawOstream(), indent: s->GetIndentLevel(), target: nullptr, show_header: true, |
1215 | UINT32_MAX); |
1216 | |
1217 | if (m_symtab_up) |
1218 | m_symtab_up->Dump(s, target: nullptr, sort_type: eSortOrderNone); |
1219 | |
1220 | if (m_dos_header.e_magic) |
1221 | DumpDOSHeader(s, header: m_dos_header); |
1222 | if (m_coff_header.machine) { |
1223 | DumpCOFFHeader(s, header: m_coff_header); |
1224 | if (m_coff_header.hdrsize) |
1225 | DumpOptCOFFHeader(s, header: m_coff_header_opt); |
1226 | } |
1227 | s->EOL(); |
1228 | DumpSectionHeaders(s); |
1229 | s->EOL(); |
1230 | |
1231 | DumpDependentModules(s); |
1232 | s->EOL(); |
1233 | } |
1234 | } |
1235 | |
1236 | // DumpDOSHeader |
1237 | // |
1238 | // Dump the MS-DOS header to the specified output stream |
1239 | void ObjectFilePECOFF::(Stream *s, const dos_header_t &) { |
1240 | s->PutCString(cstr: "MSDOS Header\n" ); |
1241 | s->Printf(format: " e_magic = 0x%4.4x\n" , header.e_magic); |
1242 | s->Printf(format: " e_cblp = 0x%4.4x\n" , header.e_cblp); |
1243 | s->Printf(format: " e_cp = 0x%4.4x\n" , header.e_cp); |
1244 | s->Printf(format: " e_crlc = 0x%4.4x\n" , header.e_crlc); |
1245 | s->Printf(format: " e_cparhdr = 0x%4.4x\n" , header.e_cparhdr); |
1246 | s->Printf(format: " e_minalloc = 0x%4.4x\n" , header.e_minalloc); |
1247 | s->Printf(format: " e_maxalloc = 0x%4.4x\n" , header.e_maxalloc); |
1248 | s->Printf(format: " e_ss = 0x%4.4x\n" , header.e_ss); |
1249 | s->Printf(format: " e_sp = 0x%4.4x\n" , header.e_sp); |
1250 | s->Printf(format: " e_csum = 0x%4.4x\n" , header.e_csum); |
1251 | s->Printf(format: " e_ip = 0x%4.4x\n" , header.e_ip); |
1252 | s->Printf(format: " e_cs = 0x%4.4x\n" , header.e_cs); |
1253 | s->Printf(format: " e_lfarlc = 0x%4.4x\n" , header.e_lfarlc); |
1254 | s->Printf(format: " e_ovno = 0x%4.4x\n" , header.e_ovno); |
1255 | s->Printf(format: " e_res[4] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n" , |
1256 | header.e_res[0], header.e_res[1], header.e_res[2], header.e_res[3]); |
1257 | s->Printf(format: " e_oemid = 0x%4.4x\n" , header.e_oemid); |
1258 | s->Printf(format: " e_oeminfo = 0x%4.4x\n" , header.e_oeminfo); |
1259 | s->Printf(format: " e_res2[10] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, " |
1260 | "0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n" , |
1261 | header.e_res2[0], header.e_res2[1], header.e_res2[2], |
1262 | header.e_res2[3], header.e_res2[4], header.e_res2[5], |
1263 | header.e_res2[6], header.e_res2[7], header.e_res2[8], |
1264 | header.e_res2[9]); |
1265 | s->Printf(format: " e_lfanew = 0x%8.8x\n" , header.e_lfanew); |
1266 | } |
1267 | |
1268 | // DumpCOFFHeader |
1269 | // |
1270 | // Dump the COFF header to the specified output stream |
1271 | void ObjectFilePECOFF::(Stream *s, const coff_header_t &) { |
1272 | s->PutCString(cstr: "COFF Header\n" ); |
1273 | s->Printf(format: " machine = 0x%4.4x\n" , header.machine); |
1274 | s->Printf(format: " nsects = 0x%4.4x\n" , header.nsects); |
1275 | s->Printf(format: " modtime = 0x%8.8x\n" , header.modtime); |
1276 | s->Printf(format: " symoff = 0x%8.8x\n" , header.symoff); |
1277 | s->Printf(format: " nsyms = 0x%8.8x\n" , header.nsyms); |
1278 | s->Printf(format: " hdrsize = 0x%4.4x\n" , header.hdrsize); |
1279 | } |
1280 | |
1281 | // DumpOptCOFFHeader |
1282 | // |
1283 | // Dump the optional COFF header to the specified output stream |
1284 | void ObjectFilePECOFF::(Stream *s, |
1285 | const coff_opt_header_t &) { |
1286 | s->PutCString(cstr: "Optional COFF Header\n" ); |
1287 | s->Printf(format: " magic = 0x%4.4x\n" , header.magic); |
1288 | s->Printf(format: " major_linker_version = 0x%2.2x\n" , |
1289 | header.major_linker_version); |
1290 | s->Printf(format: " minor_linker_version = 0x%2.2x\n" , |
1291 | header.minor_linker_version); |
1292 | s->Printf(format: " code_size = 0x%8.8x\n" , header.code_size); |
1293 | s->Printf(format: " data_size = 0x%8.8x\n" , header.data_size); |
1294 | s->Printf(format: " bss_size = 0x%8.8x\n" , header.bss_size); |
1295 | s->Printf(format: " entry = 0x%8.8x\n" , header.entry); |
1296 | s->Printf(format: " code_offset = 0x%8.8x\n" , header.code_offset); |
1297 | s->Printf(format: " data_offset = 0x%8.8x\n" , header.data_offset); |
1298 | s->Printf(format: " image_base = 0x%16.16" PRIx64 "\n" , |
1299 | header.image_base); |
1300 | s->Printf(format: " sect_alignment = 0x%8.8x\n" , header.sect_alignment); |
1301 | s->Printf(format: " file_alignment = 0x%8.8x\n" , header.file_alignment); |
1302 | s->Printf(format: " major_os_system_version = 0x%4.4x\n" , |
1303 | header.major_os_system_version); |
1304 | s->Printf(format: " minor_os_system_version = 0x%4.4x\n" , |
1305 | header.minor_os_system_version); |
1306 | s->Printf(format: " major_image_version = 0x%4.4x\n" , |
1307 | header.major_image_version); |
1308 | s->Printf(format: " minor_image_version = 0x%4.4x\n" , |
1309 | header.minor_image_version); |
1310 | s->Printf(format: " major_subsystem_version = 0x%4.4x\n" , |
1311 | header.major_subsystem_version); |
1312 | s->Printf(format: " minor_subsystem_version = 0x%4.4x\n" , |
1313 | header.minor_subsystem_version); |
1314 | s->Printf(format: " reserved1 = 0x%8.8x\n" , header.reserved1); |
1315 | s->Printf(format: " image_size = 0x%8.8x\n" , header.image_size); |
1316 | s->Printf(format: " header_size = 0x%8.8x\n" , header.header_size); |
1317 | s->Printf(format: " checksum = 0x%8.8x\n" , header.checksum); |
1318 | s->Printf(format: " subsystem = 0x%4.4x\n" , header.subsystem); |
1319 | s->Printf(format: " dll_flags = 0x%4.4x\n" , header.dll_flags); |
1320 | s->Printf(format: " stack_reserve_size = 0x%16.16" PRIx64 "\n" , |
1321 | header.stack_reserve_size); |
1322 | s->Printf(format: " stack_commit_size = 0x%16.16" PRIx64 "\n" , |
1323 | header.stack_commit_size); |
1324 | s->Printf(format: " heap_reserve_size = 0x%16.16" PRIx64 "\n" , |
1325 | header.heap_reserve_size); |
1326 | s->Printf(format: " heap_commit_size = 0x%16.16" PRIx64 "\n" , |
1327 | header.heap_commit_size); |
1328 | s->Printf(format: " loader_flags = 0x%8.8x\n" , header.loader_flags); |
1329 | s->Printf(format: " num_data_dir_entries = 0x%8.8x\n" , |
1330 | (uint32_t)header.data_dirs.size()); |
1331 | uint32_t i; |
1332 | for (i = 0; i < header.data_dirs.size(); i++) { |
1333 | s->Printf(format: " data_dirs[%2u] vmaddr = 0x%8.8x, vmsize = 0x%8.8x\n" , i, |
1334 | header.data_dirs[i].vmaddr, header.data_dirs[i].vmsize); |
1335 | } |
1336 | } |
1337 | // DumpSectionHeader |
1338 | // |
1339 | // Dump a single ELF section header to the specified output stream |
1340 | void ObjectFilePECOFF::(Stream *s, |
1341 | const section_header_t &sh) { |
1342 | std::string name = std::string(GetSectionName(sect: sh)); |
1343 | s->Printf(format: "%-16s 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%4.4x " |
1344 | "0x%4.4x 0x%8.8x\n" , |
1345 | name.c_str(), sh.vmaddr, sh.vmsize, sh.offset, sh.size, sh.reloff, |
1346 | sh.lineoff, sh.nreloc, sh.nline, sh.flags); |
1347 | } |
1348 | |
1349 | // DumpSectionHeaders |
1350 | // |
1351 | // Dump all of the ELF section header to the specified output stream |
1352 | void ObjectFilePECOFF::(Stream *s) { |
1353 | |
1354 | s->PutCString(cstr: "Section Headers\n" ); |
1355 | s->PutCString(cstr: "IDX name vm addr vm size file off file " |
1356 | "size reloc off line off nreloc nline flags\n" ); |
1357 | s->PutCString(cstr: "==== ---------------- ---------- ---------- ---------- " |
1358 | "---------- ---------- ---------- ------ ------ ----------\n" ); |
1359 | |
1360 | uint32_t idx = 0; |
1361 | SectionHeaderCollIter pos, end = m_sect_headers.end(); |
1362 | |
1363 | for (pos = m_sect_headers.begin(); pos != end; ++pos, ++idx) { |
1364 | s->Printf(format: "[%2u] " , idx); |
1365 | ObjectFilePECOFF::DumpSectionHeader(s, sh: *pos); |
1366 | } |
1367 | } |
1368 | |
1369 | // DumpDependentModules |
1370 | // |
1371 | // Dump all of the dependent modules to the specified output stream |
1372 | void ObjectFilePECOFF::DumpDependentModules(lldb_private::Stream *s) { |
1373 | auto num_modules = ParseDependentModules(); |
1374 | if (num_modules > 0) { |
1375 | s->PutCString(cstr: "Dependent Modules\n" ); |
1376 | for (unsigned i = 0; i < num_modules; ++i) { |
1377 | auto spec = m_deps_filespec->GetFileSpecAtIndex(idx: i); |
1378 | s->Printf(format: " %s\n" , spec.GetFilename().GetCString()); |
1379 | } |
1380 | } |
1381 | } |
1382 | |
1383 | bool ObjectFilePECOFF::IsWindowsSubsystem() { |
1384 | switch (m_coff_header_opt.subsystem) { |
1385 | case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE: |
1386 | case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI: |
1387 | case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI: |
1388 | case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE_WINDOWS: |
1389 | case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: |
1390 | case llvm::COFF::IMAGE_SUBSYSTEM_XBOX: |
1391 | case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: |
1392 | return true; |
1393 | default: |
1394 | return false; |
1395 | } |
1396 | } |
1397 | |
1398 | ArchSpec ObjectFilePECOFF::GetArchitecture() { |
1399 | uint16_t machine = m_coff_header.machine; |
1400 | switch (machine) { |
1401 | default: |
1402 | break; |
1403 | case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: |
1404 | case llvm::COFF::IMAGE_FILE_MACHINE_I386: |
1405 | case llvm::COFF::IMAGE_FILE_MACHINE_POWERPC: |
1406 | case llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP: |
1407 | case llvm::COFF::IMAGE_FILE_MACHINE_ARM: |
1408 | case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT: |
1409 | case llvm::COFF::IMAGE_FILE_MACHINE_THUMB: |
1410 | case llvm::COFF::IMAGE_FILE_MACHINE_ARM64: |
1411 | ArchSpec arch; |
1412 | arch.SetArchitecture(arch_type: eArchTypeCOFF, cpu: machine, LLDB_INVALID_CPUTYPE, |
1413 | os: IsWindowsSubsystem() ? llvm::Triple::Win32 |
1414 | : llvm::Triple::UnknownOS); |
1415 | return arch; |
1416 | } |
1417 | return ArchSpec(); |
1418 | } |
1419 | |
1420 | ObjectFile::Type ObjectFilePECOFF::CalculateType() { |
1421 | if (m_coff_header.machine != 0) { |
1422 | if ((m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0) |
1423 | return eTypeExecutable; |
1424 | else |
1425 | return eTypeSharedLibrary; |
1426 | } |
1427 | return eTypeExecutable; |
1428 | } |
1429 | |
1430 | ObjectFile::Strata ObjectFilePECOFF::CalculateStrata() { return eStrataUser; } |
1431 | |