1dda28197Spatrick //===-- ObjectFilePECOFF.cpp ----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "ObjectFilePECOFF.h"
10061da546Spatrick #include "PECallFrameInfo.h"
11061da546Spatrick #include "WindowsMiniDump.h"
12061da546Spatrick
13061da546Spatrick #include "lldb/Core/FileSpecList.h"
14061da546Spatrick #include "lldb/Core/Module.h"
15061da546Spatrick #include "lldb/Core/ModuleSpec.h"
16061da546Spatrick #include "lldb/Core/PluginManager.h"
17061da546Spatrick #include "lldb/Core/Section.h"
18061da546Spatrick #include "lldb/Core/StreamFile.h"
19*f6aab3d8Srobert #include "lldb/Interpreter/OptionValueDictionary.h"
20*f6aab3d8Srobert #include "lldb/Interpreter/OptionValueProperties.h"
21061da546Spatrick #include "lldb/Symbol/ObjectFile.h"
22061da546Spatrick #include "lldb/Target/Process.h"
23061da546Spatrick #include "lldb/Target/SectionLoadList.h"
24061da546Spatrick #include "lldb/Target/Target.h"
25061da546Spatrick #include "lldb/Utility/ArchSpec.h"
26061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
27061da546Spatrick #include "lldb/Utility/FileSpec.h"
28*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
29061da546Spatrick #include "lldb/Utility/Log.h"
30061da546Spatrick #include "lldb/Utility/StreamString.h"
31061da546Spatrick #include "lldb/Utility/Timer.h"
32061da546Spatrick #include "lldb/Utility/UUID.h"
33061da546Spatrick
34*f6aab3d8Srobert #include "llvm/BinaryFormat/COFF.h"
35061da546Spatrick #include "llvm/Object/COFFImportFile.h"
36*f6aab3d8Srobert #include "llvm/Support/CRC.h"
37061da546Spatrick #include "llvm/Support/Error.h"
38*f6aab3d8Srobert #include "llvm/Support/FormatAdapters.h"
39*f6aab3d8Srobert #include "llvm/Support/Host.h"
40061da546Spatrick #include "llvm/Support/MemoryBuffer.h"
41*f6aab3d8Srobert #include <optional>
42061da546Spatrick
43061da546Spatrick #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
44061da546Spatrick #define IMAGE_NT_SIGNATURE 0x00004550 // PE00
45061da546Spatrick #define OPT_HEADER_MAGIC_PE32 0x010b
46061da546Spatrick #define OPT_HEADER_MAGIC_PE32_PLUS 0x020b
47061da546Spatrick
48061da546Spatrick using namespace lldb;
49061da546Spatrick using namespace lldb_private;
50061da546Spatrick
51dda28197Spatrick LLDB_PLUGIN_DEFINE(ObjectFilePECOFF)
52dda28197Spatrick
53*f6aab3d8Srobert namespace {
54*f6aab3d8Srobert
55*f6aab3d8Srobert static constexpr OptionEnumValueElement g_abi_enums[] = {
56*f6aab3d8Srobert {
57*f6aab3d8Srobert llvm::Triple::UnknownEnvironment,
58*f6aab3d8Srobert "default",
59*f6aab3d8Srobert "Use default target (if it is Windows) or MSVC",
60*f6aab3d8Srobert },
61*f6aab3d8Srobert {
62*f6aab3d8Srobert llvm::Triple::MSVC,
63*f6aab3d8Srobert "msvc",
64*f6aab3d8Srobert "MSVC ABI",
65*f6aab3d8Srobert },
66*f6aab3d8Srobert {
67*f6aab3d8Srobert llvm::Triple::GNU,
68*f6aab3d8Srobert "gnu",
69*f6aab3d8Srobert "MinGW / Itanium ABI",
70*f6aab3d8Srobert },
71*f6aab3d8Srobert };
72*f6aab3d8Srobert
73*f6aab3d8Srobert #define LLDB_PROPERTIES_objectfilepecoff
74*f6aab3d8Srobert #include "ObjectFilePECOFFProperties.inc"
75*f6aab3d8Srobert
76*f6aab3d8Srobert enum {
77*f6aab3d8Srobert #define LLDB_PROPERTIES_objectfilepecoff
78*f6aab3d8Srobert #include "ObjectFilePECOFFPropertiesEnum.inc"
79*f6aab3d8Srobert };
80*f6aab3d8Srobert
81*f6aab3d8Srobert class PluginProperties : public Properties {
82*f6aab3d8Srobert public:
GetSettingName()83*f6aab3d8Srobert static ConstString GetSettingName() {
84*f6aab3d8Srobert return ConstString(ObjectFilePECOFF::GetPluginNameStatic());
85*f6aab3d8Srobert }
86*f6aab3d8Srobert
PluginProperties()87*f6aab3d8Srobert PluginProperties() {
88*f6aab3d8Srobert m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
89*f6aab3d8Srobert m_collection_sp->Initialize(g_objectfilepecoff_properties);
90*f6aab3d8Srobert }
91*f6aab3d8Srobert
ABI() const92*f6aab3d8Srobert llvm::Triple::EnvironmentType ABI() const {
93*f6aab3d8Srobert return (llvm::Triple::EnvironmentType)
94*f6aab3d8Srobert m_collection_sp->GetPropertyAtIndexAsEnumeration(
95*f6aab3d8Srobert nullptr, ePropertyABI, llvm::Triple::UnknownEnvironment);
96*f6aab3d8Srobert }
97*f6aab3d8Srobert
ModuleABIMap() const98*f6aab3d8Srobert OptionValueDictionary *ModuleABIMap() const {
99*f6aab3d8Srobert return m_collection_sp->GetPropertyAtIndexAsOptionValueDictionary(
100*f6aab3d8Srobert nullptr, ePropertyModuleABIMap);
101*f6aab3d8Srobert }
102*f6aab3d8Srobert };
103*f6aab3d8Srobert
104*f6aab3d8Srobert } // namespace
105*f6aab3d8Srobert
GetGlobalPluginProperties()106*f6aab3d8Srobert static PluginProperties &GetGlobalPluginProperties() {
107*f6aab3d8Srobert static PluginProperties g_settings;
108*f6aab3d8Srobert return g_settings;
109*f6aab3d8Srobert }
110*f6aab3d8Srobert
GetDebugLinkContents(const llvm::object::COFFObjectFile & coff_obj,std::string & gnu_debuglink_file,uint32_t & gnu_debuglink_crc)111*f6aab3d8Srobert static bool GetDebugLinkContents(const llvm::object::COFFObjectFile &coff_obj,
112*f6aab3d8Srobert std::string &gnu_debuglink_file,
113*f6aab3d8Srobert uint32_t &gnu_debuglink_crc) {
114*f6aab3d8Srobert static ConstString g_sect_name_gnu_debuglink(".gnu_debuglink");
115*f6aab3d8Srobert for (const auto §ion : coff_obj.sections()) {
116*f6aab3d8Srobert auto name = section.getName();
117*f6aab3d8Srobert if (!name) {
118*f6aab3d8Srobert llvm::consumeError(name.takeError());
119*f6aab3d8Srobert continue;
120*f6aab3d8Srobert }
121*f6aab3d8Srobert if (*name == g_sect_name_gnu_debuglink.GetStringRef()) {
122*f6aab3d8Srobert auto content = section.getContents();
123*f6aab3d8Srobert if (!content) {
124*f6aab3d8Srobert llvm::consumeError(content.takeError());
125*f6aab3d8Srobert return false;
126*f6aab3d8Srobert }
127*f6aab3d8Srobert DataExtractor data(
128*f6aab3d8Srobert content->data(), content->size(),
129*f6aab3d8Srobert coff_obj.isLittleEndian() ? eByteOrderLittle : eByteOrderBig, 4);
130*f6aab3d8Srobert lldb::offset_t gnu_debuglink_offset = 0;
131*f6aab3d8Srobert gnu_debuglink_file = data.GetCStr(&gnu_debuglink_offset);
132*f6aab3d8Srobert // Align to the next 4-byte offset
133*f6aab3d8Srobert gnu_debuglink_offset = llvm::alignTo(gnu_debuglink_offset, 4);
134*f6aab3d8Srobert data.GetU32(&gnu_debuglink_offset, &gnu_debuglink_crc, 1);
135*f6aab3d8Srobert return true;
136*f6aab3d8Srobert }
137*f6aab3d8Srobert }
138*f6aab3d8Srobert return false;
139*f6aab3d8Srobert }
140*f6aab3d8Srobert
GetCoffUUID(llvm::object::COFFObjectFile & coff_obj)141dda28197Spatrick static UUID GetCoffUUID(llvm::object::COFFObjectFile &coff_obj) {
142061da546Spatrick const llvm::codeview::DebugInfo *pdb_info = nullptr;
143061da546Spatrick llvm::StringRef pdb_file;
144061da546Spatrick
145*f6aab3d8Srobert // First, prefer to use the PDB build id. LLD generates this even for mingw
146*f6aab3d8Srobert // targets without PDB output, and it does not get stripped either.
147dda28197Spatrick if (!coff_obj.getDebugPDBInfo(pdb_info, pdb_file) && pdb_info) {
148061da546Spatrick if (pdb_info->PDB70.CVSignature == llvm::OMF::Signature::PDB70) {
149be691f3bSpatrick UUID::CvRecordPdb70 info;
150be691f3bSpatrick memcpy(&info.Uuid, pdb_info->PDB70.Signature, sizeof(info.Uuid));
151be691f3bSpatrick info.Age = pdb_info->PDB70.Age;
152*f6aab3d8Srobert return UUID(info);
153061da546Spatrick }
154061da546Spatrick }
155061da546Spatrick
156*f6aab3d8Srobert std::string gnu_debuglink_file;
157*f6aab3d8Srobert uint32_t gnu_debuglink_crc;
158*f6aab3d8Srobert
159*f6aab3d8Srobert // The GNU linker normally does not write a PDB build id (unless requested
160*f6aab3d8Srobert // with the --build-id option), so we should fall back to using the crc
161*f6aab3d8Srobert // from .gnu_debuglink if it exists, just like how ObjectFileELF does it.
162*f6aab3d8Srobert if (!GetDebugLinkContents(coff_obj, gnu_debuglink_file, gnu_debuglink_crc)) {
163*f6aab3d8Srobert // If there is no .gnu_debuglink section, then this may be an object
164*f6aab3d8Srobert // containing DWARF debug info for .gnu_debuglink, so calculate the crc of
165*f6aab3d8Srobert // the object itself.
166*f6aab3d8Srobert auto raw_data = coff_obj.getData();
167*f6aab3d8Srobert LLDB_SCOPED_TIMERF(
168*f6aab3d8Srobert "Calculating module crc32 %s with size %" PRIu64 " KiB",
169*f6aab3d8Srobert FileSpec(coff_obj.getFileName()).GetLastPathComponent().AsCString(),
170*f6aab3d8Srobert static_cast<lldb::offset_t>(raw_data.size()) / 1024);
171*f6aab3d8Srobert gnu_debuglink_crc = llvm::crc32(0, llvm::arrayRefFromStringRef(raw_data));
172*f6aab3d8Srobert }
173*f6aab3d8Srobert // Use 4 bytes of crc from the .gnu_debuglink section.
174*f6aab3d8Srobert llvm::support::ulittle32_t data(gnu_debuglink_crc);
175*f6aab3d8Srobert return UUID(&data, sizeof(data));
176061da546Spatrick }
177061da546Spatrick
178061da546Spatrick char ObjectFilePECOFF::ID;
179061da546Spatrick
Initialize()180061da546Spatrick void ObjectFilePECOFF::Initialize() {
181*f6aab3d8Srobert PluginManager::RegisterPlugin(GetPluginNameStatic(),
182*f6aab3d8Srobert GetPluginDescriptionStatic(), CreateInstance,
183*f6aab3d8Srobert CreateMemoryInstance, GetModuleSpecifications,
184*f6aab3d8Srobert SaveCore, DebuggerInitialize);
185*f6aab3d8Srobert }
186*f6aab3d8Srobert
DebuggerInitialize(Debugger & debugger)187*f6aab3d8Srobert void ObjectFilePECOFF::DebuggerInitialize(Debugger &debugger) {
188*f6aab3d8Srobert if (!PluginManager::GetSettingForObjectFilePlugin(
189*f6aab3d8Srobert debugger, PluginProperties::GetSettingName())) {
190*f6aab3d8Srobert const bool is_global_setting = true;
191*f6aab3d8Srobert PluginManager::CreateSettingForObjectFilePlugin(
192*f6aab3d8Srobert debugger, GetGlobalPluginProperties().GetValueProperties(),
193*f6aab3d8Srobert ConstString("Properties for the PE/COFF object-file plug-in."),
194*f6aab3d8Srobert is_global_setting);
195*f6aab3d8Srobert }
196061da546Spatrick }
197061da546Spatrick
Terminate()198061da546Spatrick void ObjectFilePECOFF::Terminate() {
199061da546Spatrick PluginManager::UnregisterPlugin(CreateInstance);
200061da546Spatrick }
201061da546Spatrick
GetPluginDescriptionStatic()202*f6aab3d8Srobert llvm::StringRef ObjectFilePECOFF::GetPluginDescriptionStatic() {
203061da546Spatrick return "Portable Executable and Common Object File Format object file reader "
204061da546Spatrick "(32 and 64 bit)";
205061da546Spatrick }
206061da546Spatrick
CreateInstance(const lldb::ModuleSP & module_sp,DataBufferSP data_sp,lldb::offset_t data_offset,const lldb_private::FileSpec * file_p,lldb::offset_t file_offset,lldb::offset_t length)207*f6aab3d8Srobert ObjectFile *ObjectFilePECOFF::CreateInstance(
208*f6aab3d8Srobert const lldb::ModuleSP &module_sp, DataBufferSP data_sp,
209*f6aab3d8Srobert lldb::offset_t data_offset, const lldb_private::FileSpec *file_p,
210*f6aab3d8Srobert lldb::offset_t file_offset, lldb::offset_t length) {
211061da546Spatrick FileSpec file = file_p ? *file_p : FileSpec();
212061da546Spatrick if (!data_sp) {
213061da546Spatrick data_sp = MapFileData(file, length, file_offset);
214061da546Spatrick if (!data_sp)
215061da546Spatrick return nullptr;
216061da546Spatrick data_offset = 0;
217061da546Spatrick }
218061da546Spatrick
219061da546Spatrick if (!ObjectFilePECOFF::MagicBytesMatch(data_sp))
220061da546Spatrick return nullptr;
221061da546Spatrick
222061da546Spatrick // Update the data to contain the entire file if it doesn't already
223061da546Spatrick if (data_sp->GetByteSize() < length) {
224061da546Spatrick data_sp = MapFileData(file, length, file_offset);
225061da546Spatrick if (!data_sp)
226061da546Spatrick return nullptr;
227061da546Spatrick }
228061da546Spatrick
229061da546Spatrick auto objfile_up = std::make_unique<ObjectFilePECOFF>(
230061da546Spatrick module_sp, data_sp, data_offset, file_p, file_offset, length);
231061da546Spatrick if (!objfile_up || !objfile_up->ParseHeader())
232061da546Spatrick return nullptr;
233061da546Spatrick
234061da546Spatrick // Cache coff binary.
235061da546Spatrick if (!objfile_up->CreateBinary())
236061da546Spatrick return nullptr;
237061da546Spatrick return objfile_up.release();
238061da546Spatrick }
239061da546Spatrick
CreateMemoryInstance(const lldb::ModuleSP & module_sp,lldb::WritableDataBufferSP data_sp,const lldb::ProcessSP & process_sp,lldb::addr_t header_addr)240061da546Spatrick ObjectFile *ObjectFilePECOFF::CreateMemoryInstance(
241*f6aab3d8Srobert const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp,
242061da546Spatrick const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
243061da546Spatrick if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp))
244061da546Spatrick return nullptr;
245061da546Spatrick auto objfile_up = std::make_unique<ObjectFilePECOFF>(
246061da546Spatrick module_sp, data_sp, process_sp, header_addr);
247061da546Spatrick if (objfile_up.get() && objfile_up->ParseHeader()) {
248061da546Spatrick return objfile_up.release();
249061da546Spatrick }
250061da546Spatrick return nullptr;
251061da546Spatrick }
252061da546Spatrick
GetModuleSpecifications(const lldb_private::FileSpec & file,lldb::DataBufferSP & data_sp,lldb::offset_t data_offset,lldb::offset_t file_offset,lldb::offset_t length,lldb_private::ModuleSpecList & specs)253061da546Spatrick size_t ObjectFilePECOFF::GetModuleSpecifications(
254061da546Spatrick const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
255061da546Spatrick lldb::offset_t data_offset, lldb::offset_t file_offset,
256061da546Spatrick lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
257061da546Spatrick const size_t initial_count = specs.GetSize();
258061da546Spatrick if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp))
259061da546Spatrick return initial_count;
260061da546Spatrick
261*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Object);
262061da546Spatrick
263dda28197Spatrick if (data_sp->GetByteSize() < length)
264dda28197Spatrick if (DataBufferSP full_sp = MapFileData(file, -1, file_offset))
265dda28197Spatrick data_sp = std::move(full_sp);
266dda28197Spatrick auto binary = llvm::object::createBinary(llvm::MemoryBufferRef(
267dda28197Spatrick toStringRef(data_sp->GetData()), file.GetFilename().GetStringRef()));
268061da546Spatrick
269061da546Spatrick if (!binary) {
270061da546Spatrick LLDB_LOG_ERROR(log, binary.takeError(),
271061da546Spatrick "Failed to create binary for file ({1}): {0}", file);
272061da546Spatrick return initial_count;
273061da546Spatrick }
274061da546Spatrick
275dda28197Spatrick auto *COFFObj = llvm::dyn_cast<llvm::object::COFFObjectFile>(binary->get());
276dda28197Spatrick if (!COFFObj)
277061da546Spatrick return initial_count;
278061da546Spatrick
279061da546Spatrick ModuleSpec module_spec(file);
280061da546Spatrick ArchSpec &spec = module_spec.GetArchitecture();
281061da546Spatrick lldb_private::UUID &uuid = module_spec.GetUUID();
282061da546Spatrick if (!uuid.IsValid())
283dda28197Spatrick uuid = GetCoffUUID(*COFFObj);
284061da546Spatrick
285*f6aab3d8Srobert static llvm::Triple::EnvironmentType default_env = [] {
286*f6aab3d8Srobert auto def_target = llvm::Triple(
287*f6aab3d8Srobert llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()));
288*f6aab3d8Srobert if (def_target.getOS() == llvm::Triple::Win32 &&
289*f6aab3d8Srobert def_target.getEnvironment() != llvm::Triple::UnknownEnvironment)
290*f6aab3d8Srobert return def_target.getEnvironment();
291*f6aab3d8Srobert return llvm::Triple::MSVC;
292*f6aab3d8Srobert }();
293*f6aab3d8Srobert
294*f6aab3d8Srobert // Check for a module-specific override.
295*f6aab3d8Srobert OptionValueSP module_env_option;
296*f6aab3d8Srobert const auto *map = GetGlobalPluginProperties().ModuleABIMap();
297*f6aab3d8Srobert if (map->GetNumValues() > 0) {
298*f6aab3d8Srobert // Step 1: Try with the exact file name.
299*f6aab3d8Srobert auto name = file.GetLastPathComponent();
300*f6aab3d8Srobert module_env_option = map->GetValueForKey(name);
301*f6aab3d8Srobert if (!module_env_option) {
302*f6aab3d8Srobert // Step 2: Try with the file name in lowercase.
303*f6aab3d8Srobert auto name_lower = name.GetStringRef().lower();
304*f6aab3d8Srobert module_env_option =
305*f6aab3d8Srobert map->GetValueForKey(ConstString(llvm::StringRef(name_lower)));
306*f6aab3d8Srobert }
307*f6aab3d8Srobert if (!module_env_option) {
308*f6aab3d8Srobert // Step 3: Try with the file name with ".debug" suffix stripped.
309*f6aab3d8Srobert auto name_stripped = name.GetStringRef();
310*f6aab3d8Srobert if (name_stripped.consume_back_insensitive(".debug")) {
311*f6aab3d8Srobert module_env_option = map->GetValueForKey(ConstString(name_stripped));
312*f6aab3d8Srobert if (!module_env_option) {
313*f6aab3d8Srobert // Step 4: Try with the file name in lowercase with ".debug" suffix
314*f6aab3d8Srobert // stripped.
315*f6aab3d8Srobert auto name_lower = name_stripped.lower();
316*f6aab3d8Srobert module_env_option =
317*f6aab3d8Srobert map->GetValueForKey(ConstString(llvm::StringRef(name_lower)));
318*f6aab3d8Srobert }
319*f6aab3d8Srobert }
320*f6aab3d8Srobert }
321*f6aab3d8Srobert }
322*f6aab3d8Srobert llvm::Triple::EnvironmentType env;
323*f6aab3d8Srobert if (module_env_option)
324*f6aab3d8Srobert env =
325*f6aab3d8Srobert (llvm::Triple::EnvironmentType)module_env_option->GetEnumerationValue();
326*f6aab3d8Srobert else
327*f6aab3d8Srobert env = GetGlobalPluginProperties().ABI();
328*f6aab3d8Srobert
329*f6aab3d8Srobert if (env == llvm::Triple::UnknownEnvironment)
330*f6aab3d8Srobert env = default_env;
331*f6aab3d8Srobert
332061da546Spatrick switch (COFFObj->getMachine()) {
333061da546Spatrick case MachineAmd64:
334061da546Spatrick spec.SetTriple("x86_64-pc-windows");
335*f6aab3d8Srobert spec.GetTriple().setEnvironment(env);
336061da546Spatrick specs.Append(module_spec);
337061da546Spatrick break;
338061da546Spatrick case MachineX86:
339061da546Spatrick spec.SetTriple("i386-pc-windows");
340*f6aab3d8Srobert spec.GetTriple().setEnvironment(env);
341061da546Spatrick specs.Append(module_spec);
342061da546Spatrick break;
343061da546Spatrick case MachineArmNt:
344061da546Spatrick spec.SetTriple("armv7-pc-windows");
345*f6aab3d8Srobert spec.GetTriple().setEnvironment(env);
346061da546Spatrick specs.Append(module_spec);
347061da546Spatrick break;
348061da546Spatrick case MachineArm64:
349061da546Spatrick spec.SetTriple("aarch64-pc-windows");
350*f6aab3d8Srobert spec.GetTriple().setEnvironment(env);
351061da546Spatrick specs.Append(module_spec);
352061da546Spatrick break;
353061da546Spatrick default:
354061da546Spatrick break;
355061da546Spatrick }
356061da546Spatrick
357061da546Spatrick return specs.GetSize() - initial_count;
358061da546Spatrick }
359061da546Spatrick
SaveCore(const lldb::ProcessSP & process_sp,const lldb_private::FileSpec & outfile,lldb::SaveCoreStyle & core_style,lldb_private::Status & error)360061da546Spatrick bool ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp,
361061da546Spatrick const lldb_private::FileSpec &outfile,
362be691f3bSpatrick lldb::SaveCoreStyle &core_style,
363061da546Spatrick lldb_private::Status &error) {
364be691f3bSpatrick core_style = eSaveCoreFull;
365061da546Spatrick return SaveMiniDump(process_sp, outfile, error);
366061da546Spatrick }
367061da546Spatrick
MagicBytesMatch(DataBufferSP data_sp)368*f6aab3d8Srobert bool ObjectFilePECOFF::MagicBytesMatch(DataBufferSP data_sp) {
369061da546Spatrick DataExtractor data(data_sp, eByteOrderLittle, 4);
370061da546Spatrick lldb::offset_t offset = 0;
371061da546Spatrick uint16_t magic = data.GetU16(&offset);
372061da546Spatrick return magic == IMAGE_DOS_SIGNATURE;
373061da546Spatrick }
374061da546Spatrick
MapSymbolType(uint16_t coff_symbol_type)375061da546Spatrick lldb::SymbolType ObjectFilePECOFF::MapSymbolType(uint16_t coff_symbol_type) {
376061da546Spatrick // TODO: We need to complete this mapping of COFF symbol types to LLDB ones.
377061da546Spatrick // For now, here's a hack to make sure our function have types.
378061da546Spatrick const auto complex_type =
379061da546Spatrick coff_symbol_type >> llvm::COFF::SCT_COMPLEX_TYPE_SHIFT;
380061da546Spatrick if (complex_type == llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION) {
381061da546Spatrick return lldb::eSymbolTypeCode;
382061da546Spatrick }
383*f6aab3d8Srobert const auto base_type = coff_symbol_type & 0xff;
384*f6aab3d8Srobert if (base_type == llvm::COFF::IMAGE_SYM_TYPE_NULL &&
385*f6aab3d8Srobert complex_type == llvm::COFF::IMAGE_SYM_DTYPE_NULL) {
386*f6aab3d8Srobert // Unknown type. LLD and GNU ld uses this for variables on MinGW, so
387*f6aab3d8Srobert // consider these symbols to be data to enable printing.
388*f6aab3d8Srobert return lldb::eSymbolTypeData;
389*f6aab3d8Srobert }
390061da546Spatrick return lldb::eSymbolTypeInvalid;
391061da546Spatrick }
392061da546Spatrick
CreateBinary()393061da546Spatrick bool ObjectFilePECOFF::CreateBinary() {
394dda28197Spatrick if (m_binary)
395061da546Spatrick return true;
396061da546Spatrick
397*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Object);
398061da546Spatrick
399dda28197Spatrick auto binary = llvm::object::createBinary(llvm::MemoryBufferRef(
400dda28197Spatrick toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()));
401061da546Spatrick if (!binary) {
402061da546Spatrick LLDB_LOG_ERROR(log, binary.takeError(),
403061da546Spatrick "Failed to create binary for file ({1}): {0}", m_file);
404061da546Spatrick return false;
405061da546Spatrick }
406061da546Spatrick
407061da546Spatrick // Make sure we only handle COFF format.
408dda28197Spatrick m_binary =
409dda28197Spatrick llvm::unique_dyn_cast<llvm::object::COFFObjectFile>(std::move(*binary));
410dda28197Spatrick if (!m_binary)
411061da546Spatrick return false;
412061da546Spatrick
413dda28197Spatrick LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",
414dda28197Spatrick this, GetModule().get(), GetModule()->GetSpecificationDescription(),
415dda28197Spatrick m_file.GetPath(), m_binary.get());
416061da546Spatrick return true;
417061da546Spatrick }
418061da546Spatrick
ObjectFilePECOFF(const lldb::ModuleSP & module_sp,DataBufferSP data_sp,lldb::offset_t data_offset,const FileSpec * file,lldb::offset_t file_offset,lldb::offset_t length)419061da546Spatrick ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp,
420*f6aab3d8Srobert DataBufferSP data_sp,
421061da546Spatrick lldb::offset_t data_offset,
422061da546Spatrick const FileSpec *file,
423061da546Spatrick lldb::offset_t file_offset,
424061da546Spatrick lldb::offset_t length)
425061da546Spatrick : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
426*f6aab3d8Srobert m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(),
427*f6aab3d8Srobert m_image_base(LLDB_INVALID_ADDRESS), m_entry_point_address(),
428*f6aab3d8Srobert m_deps_filespec() {}
429061da546Spatrick
ObjectFilePECOFF(const lldb::ModuleSP & module_sp,WritableDataBufferSP header_data_sp,const lldb::ProcessSP & process_sp,addr_t header_addr)430061da546Spatrick ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp,
431*f6aab3d8Srobert WritableDataBufferSP header_data_sp,
432061da546Spatrick const lldb::ProcessSP &process_sp,
433061da546Spatrick addr_t header_addr)
434061da546Spatrick : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
435*f6aab3d8Srobert m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(),
436*f6aab3d8Srobert m_image_base(LLDB_INVALID_ADDRESS), m_entry_point_address(),
437*f6aab3d8Srobert m_deps_filespec() {}
438061da546Spatrick
439be691f3bSpatrick ObjectFilePECOFF::~ObjectFilePECOFF() = default;
440061da546Spatrick
ParseHeader()441061da546Spatrick bool ObjectFilePECOFF::ParseHeader() {
442061da546Spatrick ModuleSP module_sp(GetModule());
443061da546Spatrick if (module_sp) {
444061da546Spatrick std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
445061da546Spatrick m_sect_headers.clear();
446061da546Spatrick m_data.SetByteOrder(eByteOrderLittle);
447061da546Spatrick lldb::offset_t offset = 0;
448061da546Spatrick
449061da546Spatrick if (ParseDOSHeader(m_data, m_dos_header)) {
450061da546Spatrick offset = m_dos_header.e_lfanew;
451061da546Spatrick uint32_t pe_signature = m_data.GetU32(&offset);
452061da546Spatrick if (pe_signature != IMAGE_NT_SIGNATURE)
453061da546Spatrick return false;
454061da546Spatrick if (ParseCOFFHeader(m_data, &offset, m_coff_header)) {
455061da546Spatrick if (m_coff_header.hdrsize > 0)
456061da546Spatrick ParseCOFFOptionalHeader(&offset);
457061da546Spatrick ParseSectionHeaders(offset);
458061da546Spatrick }
459061da546Spatrick m_data.SetAddressByteSize(GetAddressByteSize());
460061da546Spatrick return true;
461061da546Spatrick }
462061da546Spatrick }
463061da546Spatrick return false;
464061da546Spatrick }
465061da546Spatrick
SetLoadAddress(Target & target,addr_t value,bool value_is_offset)466061da546Spatrick bool ObjectFilePECOFF::SetLoadAddress(Target &target, addr_t value,
467061da546Spatrick bool value_is_offset) {
468061da546Spatrick bool changed = false;
469061da546Spatrick ModuleSP module_sp = GetModule();
470061da546Spatrick if (module_sp) {
471061da546Spatrick size_t num_loaded_sections = 0;
472061da546Spatrick SectionList *section_list = GetSectionList();
473061da546Spatrick if (section_list) {
474061da546Spatrick if (!value_is_offset) {
475061da546Spatrick value -= m_image_base;
476061da546Spatrick }
477061da546Spatrick
478061da546Spatrick const size_t num_sections = section_list->GetSize();
479061da546Spatrick size_t sect_idx = 0;
480061da546Spatrick
481061da546Spatrick for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
482061da546Spatrick // Iterate through the object file sections to find all of the sections
483061da546Spatrick // that have SHF_ALLOC in their flag bits.
484061da546Spatrick SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
485061da546Spatrick if (section_sp && !section_sp->IsThreadSpecific()) {
486061da546Spatrick if (target.GetSectionLoadList().SetSectionLoadAddress(
487061da546Spatrick section_sp, section_sp->GetFileAddress() + value))
488061da546Spatrick ++num_loaded_sections;
489061da546Spatrick }
490061da546Spatrick }
491061da546Spatrick changed = num_loaded_sections > 0;
492061da546Spatrick }
493061da546Spatrick }
494061da546Spatrick return changed;
495061da546Spatrick }
496061da546Spatrick
GetByteOrder() const497061da546Spatrick ByteOrder ObjectFilePECOFF::GetByteOrder() const { return eByteOrderLittle; }
498061da546Spatrick
IsExecutable() const499061da546Spatrick bool ObjectFilePECOFF::IsExecutable() const {
500061da546Spatrick return (m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0;
501061da546Spatrick }
502061da546Spatrick
GetAddressByteSize() const503061da546Spatrick uint32_t ObjectFilePECOFF::GetAddressByteSize() const {
504061da546Spatrick if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32_PLUS)
505061da546Spatrick return 8;
506061da546Spatrick else if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32)
507061da546Spatrick return 4;
508061da546Spatrick return 4;
509061da546Spatrick }
510061da546Spatrick
511061da546Spatrick // NeedsEndianSwap
512061da546Spatrick //
513061da546Spatrick // Return true if an endian swap needs to occur when extracting data from this
514061da546Spatrick // file.
NeedsEndianSwap() const515061da546Spatrick bool ObjectFilePECOFF::NeedsEndianSwap() const {
516061da546Spatrick #if defined(__LITTLE_ENDIAN__)
517061da546Spatrick return false;
518061da546Spatrick #else
519061da546Spatrick return true;
520061da546Spatrick #endif
521061da546Spatrick }
522061da546Spatrick // ParseDOSHeader
ParseDOSHeader(DataExtractor & data,dos_header_t & dos_header)523061da546Spatrick bool ObjectFilePECOFF::ParseDOSHeader(DataExtractor &data,
524061da546Spatrick dos_header_t &dos_header) {
525061da546Spatrick bool success = false;
526061da546Spatrick lldb::offset_t offset = 0;
527061da546Spatrick success = data.ValidOffsetForDataOfSize(0, sizeof(dos_header));
528061da546Spatrick
529061da546Spatrick if (success) {
530061da546Spatrick dos_header.e_magic = data.GetU16(&offset); // Magic number
531061da546Spatrick success = dos_header.e_magic == IMAGE_DOS_SIGNATURE;
532061da546Spatrick
533061da546Spatrick if (success) {
534061da546Spatrick dos_header.e_cblp = data.GetU16(&offset); // Bytes on last page of file
535061da546Spatrick dos_header.e_cp = data.GetU16(&offset); // Pages in file
536061da546Spatrick dos_header.e_crlc = data.GetU16(&offset); // Relocations
537061da546Spatrick dos_header.e_cparhdr =
538061da546Spatrick data.GetU16(&offset); // Size of header in paragraphs
539061da546Spatrick dos_header.e_minalloc =
540061da546Spatrick data.GetU16(&offset); // Minimum extra paragraphs needed
541061da546Spatrick dos_header.e_maxalloc =
542061da546Spatrick data.GetU16(&offset); // Maximum extra paragraphs needed
543061da546Spatrick dos_header.e_ss = data.GetU16(&offset); // Initial (relative) SS value
544061da546Spatrick dos_header.e_sp = data.GetU16(&offset); // Initial SP value
545061da546Spatrick dos_header.e_csum = data.GetU16(&offset); // Checksum
546061da546Spatrick dos_header.e_ip = data.GetU16(&offset); // Initial IP value
547061da546Spatrick dos_header.e_cs = data.GetU16(&offset); // Initial (relative) CS value
548061da546Spatrick dos_header.e_lfarlc =
549061da546Spatrick data.GetU16(&offset); // File address of relocation table
550061da546Spatrick dos_header.e_ovno = data.GetU16(&offset); // Overlay number
551061da546Spatrick
552061da546Spatrick dos_header.e_res[0] = data.GetU16(&offset); // Reserved words
553061da546Spatrick dos_header.e_res[1] = data.GetU16(&offset); // Reserved words
554061da546Spatrick dos_header.e_res[2] = data.GetU16(&offset); // Reserved words
555061da546Spatrick dos_header.e_res[3] = data.GetU16(&offset); // Reserved words
556061da546Spatrick
557061da546Spatrick dos_header.e_oemid =
558061da546Spatrick data.GetU16(&offset); // OEM identifier (for e_oeminfo)
559061da546Spatrick dos_header.e_oeminfo =
560061da546Spatrick data.GetU16(&offset); // OEM information; e_oemid specific
561061da546Spatrick dos_header.e_res2[0] = data.GetU16(&offset); // Reserved words
562061da546Spatrick dos_header.e_res2[1] = data.GetU16(&offset); // Reserved words
563061da546Spatrick dos_header.e_res2[2] = data.GetU16(&offset); // Reserved words
564061da546Spatrick dos_header.e_res2[3] = data.GetU16(&offset); // Reserved words
565061da546Spatrick dos_header.e_res2[4] = data.GetU16(&offset); // Reserved words
566061da546Spatrick dos_header.e_res2[5] = data.GetU16(&offset); // Reserved words
567061da546Spatrick dos_header.e_res2[6] = data.GetU16(&offset); // Reserved words
568061da546Spatrick dos_header.e_res2[7] = data.GetU16(&offset); // Reserved words
569061da546Spatrick dos_header.e_res2[8] = data.GetU16(&offset); // Reserved words
570061da546Spatrick dos_header.e_res2[9] = data.GetU16(&offset); // Reserved words
571061da546Spatrick
572061da546Spatrick dos_header.e_lfanew =
573061da546Spatrick data.GetU32(&offset); // File address of new exe header
574061da546Spatrick }
575061da546Spatrick }
576061da546Spatrick if (!success)
577061da546Spatrick memset(&dos_header, 0, sizeof(dos_header));
578061da546Spatrick return success;
579061da546Spatrick }
580061da546Spatrick
581061da546Spatrick // ParserCOFFHeader
ParseCOFFHeader(DataExtractor & data,lldb::offset_t * offset_ptr,coff_header_t & coff_header)582061da546Spatrick bool ObjectFilePECOFF::ParseCOFFHeader(DataExtractor &data,
583061da546Spatrick lldb::offset_t *offset_ptr,
584061da546Spatrick coff_header_t &coff_header) {
585061da546Spatrick bool success =
586061da546Spatrick data.ValidOffsetForDataOfSize(*offset_ptr, sizeof(coff_header));
587061da546Spatrick if (success) {
588061da546Spatrick coff_header.machine = data.GetU16(offset_ptr);
589061da546Spatrick coff_header.nsects = data.GetU16(offset_ptr);
590061da546Spatrick coff_header.modtime = data.GetU32(offset_ptr);
591061da546Spatrick coff_header.symoff = data.GetU32(offset_ptr);
592061da546Spatrick coff_header.nsyms = data.GetU32(offset_ptr);
593061da546Spatrick coff_header.hdrsize = data.GetU16(offset_ptr);
594061da546Spatrick coff_header.flags = data.GetU16(offset_ptr);
595061da546Spatrick }
596061da546Spatrick if (!success)
597061da546Spatrick memset(&coff_header, 0, sizeof(coff_header));
598061da546Spatrick return success;
599061da546Spatrick }
600061da546Spatrick
ParseCOFFOptionalHeader(lldb::offset_t * offset_ptr)601061da546Spatrick bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) {
602061da546Spatrick bool success = false;
603061da546Spatrick const lldb::offset_t end_offset = *offset_ptr + m_coff_header.hdrsize;
604061da546Spatrick if (*offset_ptr < end_offset) {
605061da546Spatrick success = true;
606061da546Spatrick m_coff_header_opt.magic = m_data.GetU16(offset_ptr);
607061da546Spatrick m_coff_header_opt.major_linker_version = m_data.GetU8(offset_ptr);
608061da546Spatrick m_coff_header_opt.minor_linker_version = m_data.GetU8(offset_ptr);
609061da546Spatrick m_coff_header_opt.code_size = m_data.GetU32(offset_ptr);
610061da546Spatrick m_coff_header_opt.data_size = m_data.GetU32(offset_ptr);
611061da546Spatrick m_coff_header_opt.bss_size = m_data.GetU32(offset_ptr);
612061da546Spatrick m_coff_header_opt.entry = m_data.GetU32(offset_ptr);
613061da546Spatrick m_coff_header_opt.code_offset = m_data.GetU32(offset_ptr);
614061da546Spatrick
615061da546Spatrick const uint32_t addr_byte_size = GetAddressByteSize();
616061da546Spatrick
617061da546Spatrick if (*offset_ptr < end_offset) {
618061da546Spatrick if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) {
619061da546Spatrick // PE32 only
620061da546Spatrick m_coff_header_opt.data_offset = m_data.GetU32(offset_ptr);
621061da546Spatrick } else
622061da546Spatrick m_coff_header_opt.data_offset = 0;
623061da546Spatrick
624061da546Spatrick if (*offset_ptr < end_offset) {
625061da546Spatrick m_coff_header_opt.image_base =
626061da546Spatrick m_data.GetMaxU64(offset_ptr, addr_byte_size);
627061da546Spatrick m_coff_header_opt.sect_alignment = m_data.GetU32(offset_ptr);
628061da546Spatrick m_coff_header_opt.file_alignment = m_data.GetU32(offset_ptr);
629061da546Spatrick m_coff_header_opt.major_os_system_version = m_data.GetU16(offset_ptr);
630061da546Spatrick m_coff_header_opt.minor_os_system_version = m_data.GetU16(offset_ptr);
631061da546Spatrick m_coff_header_opt.major_image_version = m_data.GetU16(offset_ptr);
632061da546Spatrick m_coff_header_opt.minor_image_version = m_data.GetU16(offset_ptr);
633061da546Spatrick m_coff_header_opt.major_subsystem_version = m_data.GetU16(offset_ptr);
634061da546Spatrick m_coff_header_opt.minor_subsystem_version = m_data.GetU16(offset_ptr);
635061da546Spatrick m_coff_header_opt.reserved1 = m_data.GetU32(offset_ptr);
636061da546Spatrick m_coff_header_opt.image_size = m_data.GetU32(offset_ptr);
637061da546Spatrick m_coff_header_opt.header_size = m_data.GetU32(offset_ptr);
638061da546Spatrick m_coff_header_opt.checksum = m_data.GetU32(offset_ptr);
639061da546Spatrick m_coff_header_opt.subsystem = m_data.GetU16(offset_ptr);
640061da546Spatrick m_coff_header_opt.dll_flags = m_data.GetU16(offset_ptr);
641061da546Spatrick m_coff_header_opt.stack_reserve_size =
642061da546Spatrick m_data.GetMaxU64(offset_ptr, addr_byte_size);
643061da546Spatrick m_coff_header_opt.stack_commit_size =
644061da546Spatrick m_data.GetMaxU64(offset_ptr, addr_byte_size);
645061da546Spatrick m_coff_header_opt.heap_reserve_size =
646061da546Spatrick m_data.GetMaxU64(offset_ptr, addr_byte_size);
647061da546Spatrick m_coff_header_opt.heap_commit_size =
648061da546Spatrick m_data.GetMaxU64(offset_ptr, addr_byte_size);
649061da546Spatrick m_coff_header_opt.loader_flags = m_data.GetU32(offset_ptr);
650061da546Spatrick uint32_t num_data_dir_entries = m_data.GetU32(offset_ptr);
651061da546Spatrick m_coff_header_opt.data_dirs.clear();
652061da546Spatrick m_coff_header_opt.data_dirs.resize(num_data_dir_entries);
653061da546Spatrick uint32_t i;
654061da546Spatrick for (i = 0; i < num_data_dir_entries; i++) {
655061da546Spatrick m_coff_header_opt.data_dirs[i].vmaddr = m_data.GetU32(offset_ptr);
656061da546Spatrick m_coff_header_opt.data_dirs[i].vmsize = m_data.GetU32(offset_ptr);
657061da546Spatrick }
658061da546Spatrick
659061da546Spatrick m_image_base = m_coff_header_opt.image_base;
660061da546Spatrick }
661061da546Spatrick }
662061da546Spatrick }
663061da546Spatrick // Make sure we are on track for section data which follows
664061da546Spatrick *offset_ptr = end_offset;
665061da546Spatrick return success;
666061da546Spatrick }
667061da546Spatrick
GetRVA(const Address & addr) const668061da546Spatrick uint32_t ObjectFilePECOFF::GetRVA(const Address &addr) const {
669061da546Spatrick return addr.GetFileAddress() - m_image_base;
670061da546Spatrick }
671061da546Spatrick
GetAddress(uint32_t rva)672061da546Spatrick Address ObjectFilePECOFF::GetAddress(uint32_t rva) {
673061da546Spatrick SectionList *sect_list = GetSectionList();
674061da546Spatrick if (!sect_list)
675061da546Spatrick return Address(GetFileAddress(rva));
676061da546Spatrick
677061da546Spatrick return Address(GetFileAddress(rva), sect_list);
678061da546Spatrick }
679061da546Spatrick
GetFileAddress(uint32_t rva) const680061da546Spatrick lldb::addr_t ObjectFilePECOFF::GetFileAddress(uint32_t rva) const {
681061da546Spatrick return m_image_base + rva;
682061da546Spatrick }
683061da546Spatrick
ReadImageData(uint32_t offset,size_t size)684061da546Spatrick DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) {
685061da546Spatrick if (!size)
686061da546Spatrick return {};
687061da546Spatrick
688dda28197Spatrick if (m_data.ValidOffsetForDataOfSize(offset, size))
689dda28197Spatrick return DataExtractor(m_data, offset, size);
690dda28197Spatrick
691061da546Spatrick ProcessSP process_sp(m_process_wp.lock());
692061da546Spatrick DataExtractor data;
693061da546Spatrick if (process_sp) {
694061da546Spatrick auto data_up = std::make_unique<DataBufferHeap>(size, 0);
695061da546Spatrick Status readmem_error;
696061da546Spatrick size_t bytes_read =
697061da546Spatrick process_sp->ReadMemory(m_image_base + offset, data_up->GetBytes(),
698061da546Spatrick data_up->GetByteSize(), readmem_error);
699061da546Spatrick if (bytes_read == size) {
700061da546Spatrick DataBufferSP buffer_sp(data_up.release());
701061da546Spatrick data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
702061da546Spatrick }
703061da546Spatrick }
704061da546Spatrick return data;
705061da546Spatrick }
706061da546Spatrick
ReadImageDataByRVA(uint32_t rva,size_t size)707061da546Spatrick DataExtractor ObjectFilePECOFF::ReadImageDataByRVA(uint32_t rva, size_t size) {
708061da546Spatrick Address addr = GetAddress(rva);
709061da546Spatrick SectionSP sect = addr.GetSection();
710061da546Spatrick if (!sect)
711061da546Spatrick return {};
712061da546Spatrick rva = sect->GetFileOffset() + addr.GetOffset();
713061da546Spatrick
714061da546Spatrick return ReadImageData(rva, size);
715061da546Spatrick }
716061da546Spatrick
717061da546Spatrick // ParseSectionHeaders
ParseSectionHeaders(uint32_t section_header_data_offset)718061da546Spatrick bool ObjectFilePECOFF::ParseSectionHeaders(
719061da546Spatrick uint32_t section_header_data_offset) {
720061da546Spatrick const uint32_t nsects = m_coff_header.nsects;
721061da546Spatrick m_sect_headers.clear();
722061da546Spatrick
723061da546Spatrick if (nsects > 0) {
724061da546Spatrick const size_t section_header_byte_size = nsects * sizeof(section_header_t);
725061da546Spatrick DataExtractor section_header_data =
726061da546Spatrick ReadImageData(section_header_data_offset, section_header_byte_size);
727061da546Spatrick
728061da546Spatrick lldb::offset_t offset = 0;
729061da546Spatrick if (section_header_data.ValidOffsetForDataOfSize(
730061da546Spatrick offset, section_header_byte_size)) {
731061da546Spatrick m_sect_headers.resize(nsects);
732061da546Spatrick
733061da546Spatrick for (uint32_t idx = 0; idx < nsects; ++idx) {
734061da546Spatrick const void *name_data = section_header_data.GetData(&offset, 8);
735061da546Spatrick if (name_data) {
736061da546Spatrick memcpy(m_sect_headers[idx].name, name_data, 8);
737061da546Spatrick m_sect_headers[idx].vmsize = section_header_data.GetU32(&offset);
738061da546Spatrick m_sect_headers[idx].vmaddr = section_header_data.GetU32(&offset);
739061da546Spatrick m_sect_headers[idx].size = section_header_data.GetU32(&offset);
740061da546Spatrick m_sect_headers[idx].offset = section_header_data.GetU32(&offset);
741061da546Spatrick m_sect_headers[idx].reloff = section_header_data.GetU32(&offset);
742061da546Spatrick m_sect_headers[idx].lineoff = section_header_data.GetU32(&offset);
743061da546Spatrick m_sect_headers[idx].nreloc = section_header_data.GetU16(&offset);
744061da546Spatrick m_sect_headers[idx].nline = section_header_data.GetU16(&offset);
745061da546Spatrick m_sect_headers[idx].flags = section_header_data.GetU32(&offset);
746061da546Spatrick }
747061da546Spatrick }
748061da546Spatrick }
749061da546Spatrick }
750061da546Spatrick
751061da546Spatrick return !m_sect_headers.empty();
752061da546Spatrick }
753061da546Spatrick
GetSectionName(const section_header_t & sect)754061da546Spatrick llvm::StringRef ObjectFilePECOFF::GetSectionName(const section_header_t §) {
755*f6aab3d8Srobert llvm::StringRef hdr_name(sect.name, std::size(sect.name));
756061da546Spatrick hdr_name = hdr_name.split('\0').first;
757061da546Spatrick if (hdr_name.consume_front("/")) {
758061da546Spatrick lldb::offset_t stroff;
759061da546Spatrick if (!to_integer(hdr_name, stroff, 10))
760061da546Spatrick return "";
761061da546Spatrick lldb::offset_t string_file_offset =
762061da546Spatrick m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff;
763061da546Spatrick if (const char *name = m_data.GetCStr(&string_file_offset))
764061da546Spatrick return name;
765061da546Spatrick return "";
766061da546Spatrick }
767061da546Spatrick return hdr_name;
768061da546Spatrick }
769061da546Spatrick
ParseSymtab(Symtab & symtab)770*f6aab3d8Srobert void ObjectFilePECOFF::ParseSymtab(Symtab &symtab) {
771061da546Spatrick SectionList *sect_list = GetSectionList();
772*f6aab3d8Srobert rva_symbol_list_t sorted_exports = AppendFromExportTable(sect_list, symtab);
773*f6aab3d8Srobert AppendFromCOFFSymbolTable(sect_list, symtab, sorted_exports);
774*f6aab3d8Srobert }
775061da546Spatrick
RVASymbolListCompareRVA(const std::pair<uint32_t,uint32_t> & a,const std::pair<uint32_t,uint32_t> & b)776*f6aab3d8Srobert static bool RVASymbolListCompareRVA(const std::pair<uint32_t, uint32_t> &a,
777*f6aab3d8Srobert const std::pair<uint32_t, uint32_t> &b) {
778*f6aab3d8Srobert return a.first < b.first;
779*f6aab3d8Srobert }
780061da546Spatrick
AppendFromCOFFSymbolTable(SectionList * sect_list,Symtab & symtab,const ObjectFilePECOFF::rva_symbol_list_t & sorted_exports)781*f6aab3d8Srobert void ObjectFilePECOFF::AppendFromCOFFSymbolTable(
782*f6aab3d8Srobert SectionList *sect_list, Symtab &symtab,
783*f6aab3d8Srobert const ObjectFilePECOFF::rva_symbol_list_t &sorted_exports) {
784*f6aab3d8Srobert const uint32_t num_syms = m_binary->getNumberOfSymbols();
785*f6aab3d8Srobert if (num_syms == 0)
786*f6aab3d8Srobert return;
787*f6aab3d8Srobert // Check that this is not a bigobj; we do not support bigobj.
788*f6aab3d8Srobert if (m_binary->getSymbolTableEntrySize() !=
789*f6aab3d8Srobert sizeof(llvm::object::coff_symbol16))
790*f6aab3d8Srobert return;
791061da546Spatrick
792*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Object);
793*f6aab3d8Srobert symtab.Reserve(symtab.GetNumSymbols() + num_syms);
794*f6aab3d8Srobert for (const auto &sym_ref : m_binary->symbols()) {
795*f6aab3d8Srobert const auto coff_sym_ref = m_binary->getCOFFSymbol(sym_ref);
796*f6aab3d8Srobert auto name_or_error = sym_ref.getName();
797*f6aab3d8Srobert if (auto err = name_or_error.takeError()) {
798*f6aab3d8Srobert LLDB_LOG(log,
799*f6aab3d8Srobert "ObjectFilePECOFF::AppendFromCOFFSymbolTable - failed to get "
800*f6aab3d8Srobert "symbol table entry name: {0}",
801*f6aab3d8Srobert llvm::fmt_consume(std::move(err)));
802*f6aab3d8Srobert continue;
803*f6aab3d8Srobert }
804*f6aab3d8Srobert const llvm::StringRef sym_name = *name_or_error;
805*f6aab3d8Srobert Symbol symbol;
806*f6aab3d8Srobert symbol.GetMangled().SetValue(ConstString(sym_name));
807*f6aab3d8Srobert int16_t section_number =
808*f6aab3d8Srobert static_cast<int16_t>(coff_sym_ref.getSectionNumber());
809*f6aab3d8Srobert if (section_number >= 1) {
810*f6aab3d8Srobert symbol.GetAddressRef() = Address(
811*f6aab3d8Srobert sect_list->FindSectionByID(section_number), coff_sym_ref.getValue());
812*f6aab3d8Srobert const auto symbol_type = MapSymbolType(coff_sym_ref.getType());
813*f6aab3d8Srobert symbol.SetType(symbol_type);
814*f6aab3d8Srobert
815*f6aab3d8Srobert // Check for duplicate of exported symbols:
816*f6aab3d8Srobert const uint32_t symbol_rva = symbol.GetAddressRef().GetFileAddress() -
817*f6aab3d8Srobert m_coff_header_opt.image_base;
818*f6aab3d8Srobert const auto &first_match = std::lower_bound(
819*f6aab3d8Srobert sorted_exports.begin(), sorted_exports.end(),
820*f6aab3d8Srobert std::make_pair(symbol_rva, 0), RVASymbolListCompareRVA);
821*f6aab3d8Srobert for (auto it = first_match;
822*f6aab3d8Srobert it != sorted_exports.end() && it->first == symbol_rva; ++it) {
823*f6aab3d8Srobert Symbol *exported = symtab.SymbolAtIndex(it->second);
824*f6aab3d8Srobert if (symbol_type != lldb::eSymbolTypeInvalid)
825*f6aab3d8Srobert exported->SetType(symbol_type);
826*f6aab3d8Srobert if (exported->GetMangled() == symbol.GetMangled()) {
827*f6aab3d8Srobert symbol.SetExternal(true);
828*f6aab3d8Srobert // We don't want the symbol to be duplicated (e.g. when running
829*f6aab3d8Srobert // `disas -n func`), but we also don't want to erase this entry (to
830*f6aab3d8Srobert // preserve the original symbol order), so we mark it as additional.
831*f6aab3d8Srobert symbol.SetType(lldb::eSymbolTypeAdditional);
832061da546Spatrick } else {
833*f6aab3d8Srobert // It is possible for a symbol to be exported in a different name
834*f6aab3d8Srobert // from its original. In this case keep both entries so lookup using
835*f6aab3d8Srobert // either names will work. If this symbol has an invalid type, replace
836*f6aab3d8Srobert // it with the type from the export symbol.
837*f6aab3d8Srobert if (symbol.GetType() == lldb::eSymbolTypeInvalid)
838*f6aab3d8Srobert symbol.SetType(exported->GetType());
839061da546Spatrick }
840061da546Spatrick }
841*f6aab3d8Srobert } else if (section_number == llvm::COFF::IMAGE_SYM_ABSOLUTE) {
842*f6aab3d8Srobert symbol.GetAddressRef() = Address(coff_sym_ref.getValue());
843*f6aab3d8Srobert symbol.SetType(lldb::eSymbolTypeAbsolute);
844*f6aab3d8Srobert }
845*f6aab3d8Srobert symtab.AddSymbol(symbol);
846061da546Spatrick }
847061da546Spatrick }
848061da546Spatrick
849*f6aab3d8Srobert ObjectFilePECOFF::rva_symbol_list_t
AppendFromExportTable(SectionList * sect_list,Symtab & symtab)850*f6aab3d8Srobert ObjectFilePECOFF::AppendFromExportTable(SectionList *sect_list,
851*f6aab3d8Srobert Symtab &symtab) {
852*f6aab3d8Srobert const auto *export_table = m_binary->getExportTable();
853*f6aab3d8Srobert if (!export_table)
854*f6aab3d8Srobert return {};
855*f6aab3d8Srobert const uint32_t num_syms = export_table->AddressTableEntries;
856*f6aab3d8Srobert if (num_syms == 0)
857*f6aab3d8Srobert return {};
858061da546Spatrick
859*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Object);
860*f6aab3d8Srobert rva_symbol_list_t export_list;
861*f6aab3d8Srobert symtab.Reserve(symtab.GetNumSymbols() + num_syms);
862*f6aab3d8Srobert // Read each export table entry, ordered by ordinal instead of by name.
863*f6aab3d8Srobert for (const auto &entry : m_binary->export_directories()) {
864*f6aab3d8Srobert llvm::StringRef sym_name;
865*f6aab3d8Srobert if (auto err = entry.getSymbolName(sym_name)) {
866*f6aab3d8Srobert LLDB_LOG(log,
867*f6aab3d8Srobert "ObjectFilePECOFF::AppendFromExportTable - failed to get export "
868*f6aab3d8Srobert "table entry name: {0}",
869*f6aab3d8Srobert llvm::fmt_consume(std::move(err)));
870*f6aab3d8Srobert continue;
871061da546Spatrick }
872*f6aab3d8Srobert Symbol symbol;
873*f6aab3d8Srobert // Note: symbol name may be empty if it is only exported by ordinal.
874*f6aab3d8Srobert symbol.GetMangled().SetValue(ConstString(sym_name));
875*f6aab3d8Srobert
876*f6aab3d8Srobert uint32_t ordinal;
877*f6aab3d8Srobert llvm::cantFail(entry.getOrdinal(ordinal));
878*f6aab3d8Srobert symbol.SetID(ordinal);
879*f6aab3d8Srobert
880*f6aab3d8Srobert bool is_forwarder;
881*f6aab3d8Srobert llvm::cantFail(entry.isForwarder(is_forwarder));
882*f6aab3d8Srobert if (is_forwarder) {
883*f6aab3d8Srobert // Forwarder exports are redirected by the loader transparently, but keep
884*f6aab3d8Srobert // it in symtab and make a note using the symbol name.
885*f6aab3d8Srobert llvm::StringRef forwarder_name;
886*f6aab3d8Srobert if (auto err = entry.getForwardTo(forwarder_name)) {
887*f6aab3d8Srobert LLDB_LOG(log,
888*f6aab3d8Srobert "ObjectFilePECOFF::AppendFromExportTable - failed to get "
889*f6aab3d8Srobert "forwarder name of forwarder export '{0}': {1}",
890*f6aab3d8Srobert sym_name, llvm::fmt_consume(std::move(err)));
891*f6aab3d8Srobert continue;
892061da546Spatrick }
893*f6aab3d8Srobert llvm::SmallString<256> new_name = {symbol.GetDisplayName().GetStringRef(),
894*f6aab3d8Srobert " (forwarded to ", forwarder_name,
895*f6aab3d8Srobert ")"};
896*f6aab3d8Srobert symbol.GetMangled().SetDemangledName(ConstString(new_name.str()));
897*f6aab3d8Srobert symbol.SetDemangledNameIsSynthesized(true);
898061da546Spatrick }
899*f6aab3d8Srobert
900*f6aab3d8Srobert uint32_t function_rva;
901*f6aab3d8Srobert if (auto err = entry.getExportRVA(function_rva)) {
902*f6aab3d8Srobert LLDB_LOG(log,
903*f6aab3d8Srobert "ObjectFilePECOFF::AppendFromExportTable - failed to get "
904*f6aab3d8Srobert "address of export entry '{0}': {1}",
905*f6aab3d8Srobert sym_name, llvm::fmt_consume(std::move(err)));
906*f6aab3d8Srobert continue;
907061da546Spatrick }
908*f6aab3d8Srobert // Skip the symbol if it doesn't look valid.
909*f6aab3d8Srobert if (function_rva == 0 && sym_name.empty())
910*f6aab3d8Srobert continue;
911*f6aab3d8Srobert symbol.GetAddressRef() =
912*f6aab3d8Srobert Address(m_coff_header_opt.image_base + function_rva, sect_list);
913*f6aab3d8Srobert
914*f6aab3d8Srobert // An exported symbol may be either code or data. Guess by checking whether
915*f6aab3d8Srobert // the section containing the symbol is executable.
916*f6aab3d8Srobert symbol.SetType(lldb::eSymbolTypeData);
917*f6aab3d8Srobert if (!is_forwarder)
918*f6aab3d8Srobert if (auto section_sp = symbol.GetAddressRef().GetSection())
919*f6aab3d8Srobert if (section_sp->GetPermissions() & ePermissionsExecutable)
920*f6aab3d8Srobert symbol.SetType(lldb::eSymbolTypeCode);
921*f6aab3d8Srobert symbol.SetExternal(true);
922*f6aab3d8Srobert uint32_t idx = symtab.AddSymbol(symbol);
923*f6aab3d8Srobert export_list.push_back(std::make_pair(function_rva, idx));
924*f6aab3d8Srobert }
925*f6aab3d8Srobert std::stable_sort(export_list.begin(), export_list.end(),
926*f6aab3d8Srobert RVASymbolListCompareRVA);
927*f6aab3d8Srobert return export_list;
928061da546Spatrick }
929061da546Spatrick
CreateCallFrameInfo()930061da546Spatrick std::unique_ptr<CallFrameInfo> ObjectFilePECOFF::CreateCallFrameInfo() {
931*f6aab3d8Srobert if (llvm::COFF::EXCEPTION_TABLE >= m_coff_header_opt.data_dirs.size())
932061da546Spatrick return {};
933061da546Spatrick
934061da546Spatrick data_directory data_dir_exception =
935*f6aab3d8Srobert m_coff_header_opt.data_dirs[llvm::COFF::EXCEPTION_TABLE];
936061da546Spatrick if (!data_dir_exception.vmaddr)
937061da546Spatrick return {};
938061da546Spatrick
939053af629Spatrick if (m_coff_header.machine != llvm::COFF::IMAGE_FILE_MACHINE_AMD64)
940053af629Spatrick return {};
941053af629Spatrick
942061da546Spatrick return std::make_unique<PECallFrameInfo>(*this, data_dir_exception.vmaddr,
943061da546Spatrick data_dir_exception.vmsize);
944061da546Spatrick }
945061da546Spatrick
IsStripped()946061da546Spatrick bool ObjectFilePECOFF::IsStripped() {
947061da546Spatrick // TODO: determine this for COFF
948061da546Spatrick return false;
949061da546Spatrick }
950061da546Spatrick
GetSectionType(llvm::StringRef sect_name,const section_header_t & sect)951061da546Spatrick SectionType ObjectFilePECOFF::GetSectionType(llvm::StringRef sect_name,
952061da546Spatrick const section_header_t §) {
953061da546Spatrick ConstString const_sect_name(sect_name);
954061da546Spatrick static ConstString g_code_sect_name(".code");
955061da546Spatrick static ConstString g_CODE_sect_name("CODE");
956061da546Spatrick static ConstString g_data_sect_name(".data");
957061da546Spatrick static ConstString g_DATA_sect_name("DATA");
958061da546Spatrick static ConstString g_bss_sect_name(".bss");
959061da546Spatrick static ConstString g_BSS_sect_name("BSS");
960061da546Spatrick
961061da546Spatrick if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_CODE &&
962061da546Spatrick ((const_sect_name == g_code_sect_name) ||
963061da546Spatrick (const_sect_name == g_CODE_sect_name))) {
964061da546Spatrick return eSectionTypeCode;
965061da546Spatrick }
966061da546Spatrick if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA &&
967061da546Spatrick ((const_sect_name == g_data_sect_name) ||
968061da546Spatrick (const_sect_name == g_DATA_sect_name))) {
969061da546Spatrick if (sect.size == 0 && sect.offset == 0)
970061da546Spatrick return eSectionTypeZeroFill;
971061da546Spatrick else
972061da546Spatrick return eSectionTypeData;
973061da546Spatrick }
974061da546Spatrick if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA &&
975061da546Spatrick ((const_sect_name == g_bss_sect_name) ||
976061da546Spatrick (const_sect_name == g_BSS_sect_name))) {
977061da546Spatrick if (sect.size == 0)
978061da546Spatrick return eSectionTypeZeroFill;
979061da546Spatrick else
980061da546Spatrick return eSectionTypeData;
981061da546Spatrick }
982061da546Spatrick
983061da546Spatrick SectionType section_type =
984061da546Spatrick llvm::StringSwitch<SectionType>(sect_name)
985061da546Spatrick .Case(".debug", eSectionTypeDebug)
986061da546Spatrick .Case(".stabstr", eSectionTypeDataCString)
987061da546Spatrick .Case(".reloc", eSectionTypeOther)
988061da546Spatrick .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev)
989061da546Spatrick .Case(".debug_aranges", eSectionTypeDWARFDebugAranges)
990061da546Spatrick .Case(".debug_frame", eSectionTypeDWARFDebugFrame)
991061da546Spatrick .Case(".debug_info", eSectionTypeDWARFDebugInfo)
992061da546Spatrick .Case(".debug_line", eSectionTypeDWARFDebugLine)
993061da546Spatrick .Case(".debug_loc", eSectionTypeDWARFDebugLoc)
994061da546Spatrick .Case(".debug_loclists", eSectionTypeDWARFDebugLocLists)
995061da546Spatrick .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo)
996061da546Spatrick .Case(".debug_names", eSectionTypeDWARFDebugNames)
997061da546Spatrick .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames)
998061da546Spatrick .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes)
999061da546Spatrick .Case(".debug_ranges", eSectionTypeDWARFDebugRanges)
1000061da546Spatrick .Case(".debug_str", eSectionTypeDWARFDebugStr)
1001061da546Spatrick .Case(".debug_types", eSectionTypeDWARFDebugTypes)
1002061da546Spatrick // .eh_frame can be truncated to 8 chars.
1003061da546Spatrick .Cases(".eh_frame", ".eh_fram", eSectionTypeEHFrame)
1004061da546Spatrick .Case(".gosymtab", eSectionTypeGoSymtab)
1005061da546Spatrick .Default(eSectionTypeInvalid);
1006061da546Spatrick if (section_type != eSectionTypeInvalid)
1007061da546Spatrick return section_type;
1008061da546Spatrick
1009061da546Spatrick if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_CODE)
1010061da546Spatrick return eSectionTypeCode;
1011061da546Spatrick if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
1012061da546Spatrick return eSectionTypeData;
1013061da546Spatrick if (sect.flags & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
1014061da546Spatrick if (sect.size == 0)
1015061da546Spatrick return eSectionTypeZeroFill;
1016061da546Spatrick else
1017061da546Spatrick return eSectionTypeData;
1018061da546Spatrick }
1019061da546Spatrick return eSectionTypeOther;
1020061da546Spatrick }
1021061da546Spatrick
CreateSections(SectionList & unified_section_list)1022061da546Spatrick void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) {
1023061da546Spatrick if (m_sections_up)
1024061da546Spatrick return;
1025dda28197Spatrick m_sections_up = std::make_unique<SectionList>();
1026061da546Spatrick ModuleSP module_sp(GetModule());
1027061da546Spatrick if (module_sp) {
1028061da546Spatrick std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
1029061da546Spatrick
1030061da546Spatrick SectionSP header_sp = std::make_shared<Section>(
1031061da546Spatrick module_sp, this, ~user_id_t(0), ConstString("PECOFF header"),
1032061da546Spatrick eSectionTypeOther, m_coff_header_opt.image_base,
1033061da546Spatrick m_coff_header_opt.header_size,
1034061da546Spatrick /*file_offset*/ 0, m_coff_header_opt.header_size,
1035061da546Spatrick m_coff_header_opt.sect_alignment,
1036061da546Spatrick /*flags*/ 0);
1037061da546Spatrick header_sp->SetPermissions(ePermissionsReadable);
1038061da546Spatrick m_sections_up->AddSection(header_sp);
1039061da546Spatrick unified_section_list.AddSection(header_sp);
1040061da546Spatrick
1041061da546Spatrick const uint32_t nsects = m_sect_headers.size();
1042061da546Spatrick ModuleSP module_sp(GetModule());
1043061da546Spatrick for (uint32_t idx = 0; idx < nsects; ++idx) {
1044061da546Spatrick llvm::StringRef sect_name = GetSectionName(m_sect_headers[idx]);
1045061da546Spatrick ConstString const_sect_name(sect_name);
1046061da546Spatrick SectionType section_type = GetSectionType(sect_name, m_sect_headers[idx]);
1047061da546Spatrick
1048061da546Spatrick SectionSP section_sp(new Section(
1049061da546Spatrick module_sp, // Module to which this section belongs
1050061da546Spatrick this, // Object file to which this section belongs
1051061da546Spatrick idx + 1, // Section ID is the 1 based section index.
1052061da546Spatrick const_sect_name, // Name of this section
1053061da546Spatrick section_type,
1054061da546Spatrick m_coff_header_opt.image_base +
1055061da546Spatrick m_sect_headers[idx].vmaddr, // File VM address == addresses as
1056061da546Spatrick // they are found in the object file
1057061da546Spatrick m_sect_headers[idx].vmsize, // VM size in bytes of this section
1058061da546Spatrick m_sect_headers[idx]
1059061da546Spatrick .offset, // Offset to the data for this section in the file
1060061da546Spatrick m_sect_headers[idx]
1061061da546Spatrick .size, // Size in bytes of this section as found in the file
1062061da546Spatrick m_coff_header_opt.sect_alignment, // Section alignment
1063061da546Spatrick m_sect_headers[idx].flags)); // Flags for this section
1064061da546Spatrick
1065061da546Spatrick uint32_t permissions = 0;
1066061da546Spatrick if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
1067061da546Spatrick permissions |= ePermissionsExecutable;
1068061da546Spatrick if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_MEM_READ)
1069061da546Spatrick permissions |= ePermissionsReadable;
1070061da546Spatrick if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_MEM_WRITE)
1071061da546Spatrick permissions |= ePermissionsWritable;
1072061da546Spatrick section_sp->SetPermissions(permissions);
1073061da546Spatrick
1074061da546Spatrick m_sections_up->AddSection(section_sp);
1075061da546Spatrick unified_section_list.AddSection(section_sp);
1076061da546Spatrick }
1077061da546Spatrick }
1078061da546Spatrick }
1079061da546Spatrick
GetUUID()1080061da546Spatrick UUID ObjectFilePECOFF::GetUUID() {
1081061da546Spatrick if (m_uuid.IsValid())
1082061da546Spatrick return m_uuid;
1083061da546Spatrick
1084061da546Spatrick if (!CreateBinary())
1085061da546Spatrick return UUID();
1086061da546Spatrick
1087dda28197Spatrick m_uuid = GetCoffUUID(*m_binary);
1088061da546Spatrick return m_uuid;
1089061da546Spatrick }
1090061da546Spatrick
GetDebugLink()1091*f6aab3d8Srobert std::optional<FileSpec> ObjectFilePECOFF::GetDebugLink() {
1092*f6aab3d8Srobert std::string gnu_debuglink_file;
1093*f6aab3d8Srobert uint32_t gnu_debuglink_crc;
1094*f6aab3d8Srobert if (GetDebugLinkContents(*m_binary, gnu_debuglink_file, gnu_debuglink_crc))
1095*f6aab3d8Srobert return FileSpec(gnu_debuglink_file);
1096*f6aab3d8Srobert return std::nullopt;
1097*f6aab3d8Srobert }
1098*f6aab3d8Srobert
ParseDependentModules()1099061da546Spatrick uint32_t ObjectFilePECOFF::ParseDependentModules() {
1100061da546Spatrick ModuleSP module_sp(GetModule());
1101061da546Spatrick if (!module_sp)
1102061da546Spatrick return 0;
1103061da546Spatrick
1104061da546Spatrick std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
1105061da546Spatrick if (m_deps_filespec)
1106061da546Spatrick return m_deps_filespec->GetSize();
1107061da546Spatrick
1108061da546Spatrick // Cache coff binary if it is not done yet.
1109061da546Spatrick if (!CreateBinary())
1110061da546Spatrick return 0;
1111061da546Spatrick
1112*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Object);
1113dda28197Spatrick LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",
1114dda28197Spatrick this, GetModule().get(), GetModule()->GetSpecificationDescription(),
1115dda28197Spatrick m_file.GetPath(), m_binary.get());
1116061da546Spatrick
1117061da546Spatrick m_deps_filespec = FileSpecList();
1118061da546Spatrick
1119dda28197Spatrick for (const auto &entry : m_binary->import_directories()) {
1120061da546Spatrick llvm::StringRef dll_name;
1121061da546Spatrick // Report a bogus entry.
1122dda28197Spatrick if (llvm::Error e = entry.getName(dll_name)) {
1123061da546Spatrick LLDB_LOGF(log,
1124061da546Spatrick "ObjectFilePECOFF::ParseDependentModules() - failed to get "
1125061da546Spatrick "import directory entry name: %s",
1126dda28197Spatrick llvm::toString(std::move(e)).c_str());
1127061da546Spatrick continue;
1128061da546Spatrick }
1129061da546Spatrick
1130061da546Spatrick // At this moment we only have the base name of the DLL. The full path can
1131061da546Spatrick // only be seen after the dynamic loading. Our best guess is Try to get it
1132061da546Spatrick // with the help of the object file's directory.
1133061da546Spatrick llvm::SmallString<128> dll_fullpath;
1134061da546Spatrick FileSpec dll_specs(dll_name);
1135*f6aab3d8Srobert dll_specs.SetDirectory(m_file.GetDirectory());
1136061da546Spatrick
1137061da546Spatrick if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath))
1138061da546Spatrick m_deps_filespec->EmplaceBack(dll_fullpath);
1139061da546Spatrick else {
1140061da546Spatrick // Known DLLs or DLL not found in the object file directory.
1141061da546Spatrick m_deps_filespec->EmplaceBack(dll_name);
1142061da546Spatrick }
1143061da546Spatrick }
1144061da546Spatrick return m_deps_filespec->GetSize();
1145061da546Spatrick }
1146061da546Spatrick
GetDependentModules(FileSpecList & files)1147061da546Spatrick uint32_t ObjectFilePECOFF::GetDependentModules(FileSpecList &files) {
1148061da546Spatrick auto num_modules = ParseDependentModules();
1149061da546Spatrick auto original_size = files.GetSize();
1150061da546Spatrick
1151061da546Spatrick for (unsigned i = 0; i < num_modules; ++i)
1152061da546Spatrick files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i));
1153061da546Spatrick
1154061da546Spatrick return files.GetSize() - original_size;
1155061da546Spatrick }
1156061da546Spatrick
GetEntryPointAddress()1157061da546Spatrick lldb_private::Address ObjectFilePECOFF::GetEntryPointAddress() {
1158061da546Spatrick if (m_entry_point_address.IsValid())
1159061da546Spatrick return m_entry_point_address;
1160061da546Spatrick
1161061da546Spatrick if (!ParseHeader() || !IsExecutable())
1162061da546Spatrick return m_entry_point_address;
1163061da546Spatrick
1164061da546Spatrick SectionList *section_list = GetSectionList();
1165061da546Spatrick addr_t file_addr = m_coff_header_opt.entry + m_coff_header_opt.image_base;
1166061da546Spatrick
1167061da546Spatrick if (!section_list)
1168061da546Spatrick m_entry_point_address.SetOffset(file_addr);
1169061da546Spatrick else
1170061da546Spatrick m_entry_point_address.ResolveAddressUsingFileSections(file_addr,
1171061da546Spatrick section_list);
1172061da546Spatrick return m_entry_point_address;
1173061da546Spatrick }
1174061da546Spatrick
GetBaseAddress()1175061da546Spatrick Address ObjectFilePECOFF::GetBaseAddress() {
1176061da546Spatrick return Address(GetSectionList()->GetSectionAtIndex(0), 0);
1177061da546Spatrick }
1178061da546Spatrick
1179061da546Spatrick // Dump
1180061da546Spatrick //
1181061da546Spatrick // Dump the specifics of the runtime file container (such as any headers
1182061da546Spatrick // segments, sections, etc).
Dump(Stream * s)1183061da546Spatrick void ObjectFilePECOFF::Dump(Stream *s) {
1184061da546Spatrick ModuleSP module_sp(GetModule());
1185061da546Spatrick if (module_sp) {
1186061da546Spatrick std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
1187061da546Spatrick s->Printf("%p: ", static_cast<void *>(this));
1188061da546Spatrick s->Indent();
1189061da546Spatrick s->PutCString("ObjectFilePECOFF");
1190061da546Spatrick
1191061da546Spatrick ArchSpec header_arch = GetArchitecture();
1192061da546Spatrick
1193061da546Spatrick *s << ", file = '" << m_file
1194061da546Spatrick << "', arch = " << header_arch.GetArchitectureName() << "\n";
1195061da546Spatrick
1196061da546Spatrick SectionList *sections = GetSectionList();
1197061da546Spatrick if (sections)
1198dda28197Spatrick sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true,
1199dda28197Spatrick UINT32_MAX);
1200061da546Spatrick
1201061da546Spatrick if (m_symtab_up)
1202061da546Spatrick m_symtab_up->Dump(s, nullptr, eSortOrderNone);
1203061da546Spatrick
1204061da546Spatrick if (m_dos_header.e_magic)
1205061da546Spatrick DumpDOSHeader(s, m_dos_header);
1206061da546Spatrick if (m_coff_header.machine) {
1207061da546Spatrick DumpCOFFHeader(s, m_coff_header);
1208061da546Spatrick if (m_coff_header.hdrsize)
1209061da546Spatrick DumpOptCOFFHeader(s, m_coff_header_opt);
1210061da546Spatrick }
1211061da546Spatrick s->EOL();
1212061da546Spatrick DumpSectionHeaders(s);
1213061da546Spatrick s->EOL();
1214061da546Spatrick
1215061da546Spatrick DumpDependentModules(s);
1216061da546Spatrick s->EOL();
1217061da546Spatrick }
1218061da546Spatrick }
1219061da546Spatrick
1220061da546Spatrick // DumpDOSHeader
1221061da546Spatrick //
1222061da546Spatrick // Dump the MS-DOS header to the specified output stream
DumpDOSHeader(Stream * s,const dos_header_t & header)1223061da546Spatrick void ObjectFilePECOFF::DumpDOSHeader(Stream *s, const dos_header_t &header) {
1224061da546Spatrick s->PutCString("MSDOS Header\n");
1225061da546Spatrick s->Printf(" e_magic = 0x%4.4x\n", header.e_magic);
1226061da546Spatrick s->Printf(" e_cblp = 0x%4.4x\n", header.e_cblp);
1227061da546Spatrick s->Printf(" e_cp = 0x%4.4x\n", header.e_cp);
1228061da546Spatrick s->Printf(" e_crlc = 0x%4.4x\n", header.e_crlc);
1229061da546Spatrick s->Printf(" e_cparhdr = 0x%4.4x\n", header.e_cparhdr);
1230061da546Spatrick s->Printf(" e_minalloc = 0x%4.4x\n", header.e_minalloc);
1231061da546Spatrick s->Printf(" e_maxalloc = 0x%4.4x\n", header.e_maxalloc);
1232061da546Spatrick s->Printf(" e_ss = 0x%4.4x\n", header.e_ss);
1233061da546Spatrick s->Printf(" e_sp = 0x%4.4x\n", header.e_sp);
1234061da546Spatrick s->Printf(" e_csum = 0x%4.4x\n", header.e_csum);
1235061da546Spatrick s->Printf(" e_ip = 0x%4.4x\n", header.e_ip);
1236061da546Spatrick s->Printf(" e_cs = 0x%4.4x\n", header.e_cs);
1237061da546Spatrick s->Printf(" e_lfarlc = 0x%4.4x\n", header.e_lfarlc);
1238061da546Spatrick s->Printf(" e_ovno = 0x%4.4x\n", header.e_ovno);
1239061da546Spatrick s->Printf(" e_res[4] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n",
1240061da546Spatrick header.e_res[0], header.e_res[1], header.e_res[2], header.e_res[3]);
1241061da546Spatrick s->Printf(" e_oemid = 0x%4.4x\n", header.e_oemid);
1242061da546Spatrick s->Printf(" e_oeminfo = 0x%4.4x\n", header.e_oeminfo);
1243061da546Spatrick s->Printf(" e_res2[10] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, "
1244061da546Spatrick "0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n",
1245061da546Spatrick header.e_res2[0], header.e_res2[1], header.e_res2[2],
1246061da546Spatrick header.e_res2[3], header.e_res2[4], header.e_res2[5],
1247061da546Spatrick header.e_res2[6], header.e_res2[7], header.e_res2[8],
1248061da546Spatrick header.e_res2[9]);
1249061da546Spatrick s->Printf(" e_lfanew = 0x%8.8x\n", header.e_lfanew);
1250061da546Spatrick }
1251061da546Spatrick
1252061da546Spatrick // DumpCOFFHeader
1253061da546Spatrick //
1254061da546Spatrick // Dump the COFF header to the specified output stream
DumpCOFFHeader(Stream * s,const coff_header_t & header)1255061da546Spatrick void ObjectFilePECOFF::DumpCOFFHeader(Stream *s, const coff_header_t &header) {
1256061da546Spatrick s->PutCString("COFF Header\n");
1257061da546Spatrick s->Printf(" machine = 0x%4.4x\n", header.machine);
1258061da546Spatrick s->Printf(" nsects = 0x%4.4x\n", header.nsects);
1259061da546Spatrick s->Printf(" modtime = 0x%8.8x\n", header.modtime);
1260061da546Spatrick s->Printf(" symoff = 0x%8.8x\n", header.symoff);
1261061da546Spatrick s->Printf(" nsyms = 0x%8.8x\n", header.nsyms);
1262061da546Spatrick s->Printf(" hdrsize = 0x%4.4x\n", header.hdrsize);
1263061da546Spatrick }
1264061da546Spatrick
1265061da546Spatrick // DumpOptCOFFHeader
1266061da546Spatrick //
1267061da546Spatrick // Dump the optional COFF header to the specified output stream
DumpOptCOFFHeader(Stream * s,const coff_opt_header_t & header)1268061da546Spatrick void ObjectFilePECOFF::DumpOptCOFFHeader(Stream *s,
1269061da546Spatrick const coff_opt_header_t &header) {
1270061da546Spatrick s->PutCString("Optional COFF Header\n");
1271061da546Spatrick s->Printf(" magic = 0x%4.4x\n", header.magic);
1272061da546Spatrick s->Printf(" major_linker_version = 0x%2.2x\n",
1273061da546Spatrick header.major_linker_version);
1274061da546Spatrick s->Printf(" minor_linker_version = 0x%2.2x\n",
1275061da546Spatrick header.minor_linker_version);
1276061da546Spatrick s->Printf(" code_size = 0x%8.8x\n", header.code_size);
1277061da546Spatrick s->Printf(" data_size = 0x%8.8x\n", header.data_size);
1278061da546Spatrick s->Printf(" bss_size = 0x%8.8x\n", header.bss_size);
1279061da546Spatrick s->Printf(" entry = 0x%8.8x\n", header.entry);
1280061da546Spatrick s->Printf(" code_offset = 0x%8.8x\n", header.code_offset);
1281061da546Spatrick s->Printf(" data_offset = 0x%8.8x\n", header.data_offset);
1282061da546Spatrick s->Printf(" image_base = 0x%16.16" PRIx64 "\n",
1283061da546Spatrick header.image_base);
1284061da546Spatrick s->Printf(" sect_alignment = 0x%8.8x\n", header.sect_alignment);
1285061da546Spatrick s->Printf(" file_alignment = 0x%8.8x\n", header.file_alignment);
1286061da546Spatrick s->Printf(" major_os_system_version = 0x%4.4x\n",
1287061da546Spatrick header.major_os_system_version);
1288061da546Spatrick s->Printf(" minor_os_system_version = 0x%4.4x\n",
1289061da546Spatrick header.minor_os_system_version);
1290061da546Spatrick s->Printf(" major_image_version = 0x%4.4x\n",
1291061da546Spatrick header.major_image_version);
1292061da546Spatrick s->Printf(" minor_image_version = 0x%4.4x\n",
1293061da546Spatrick header.minor_image_version);
1294061da546Spatrick s->Printf(" major_subsystem_version = 0x%4.4x\n",
1295061da546Spatrick header.major_subsystem_version);
1296061da546Spatrick s->Printf(" minor_subsystem_version = 0x%4.4x\n",
1297061da546Spatrick header.minor_subsystem_version);
1298061da546Spatrick s->Printf(" reserved1 = 0x%8.8x\n", header.reserved1);
1299061da546Spatrick s->Printf(" image_size = 0x%8.8x\n", header.image_size);
1300061da546Spatrick s->Printf(" header_size = 0x%8.8x\n", header.header_size);
1301061da546Spatrick s->Printf(" checksum = 0x%8.8x\n", header.checksum);
1302061da546Spatrick s->Printf(" subsystem = 0x%4.4x\n", header.subsystem);
1303061da546Spatrick s->Printf(" dll_flags = 0x%4.4x\n", header.dll_flags);
1304061da546Spatrick s->Printf(" stack_reserve_size = 0x%16.16" PRIx64 "\n",
1305061da546Spatrick header.stack_reserve_size);
1306061da546Spatrick s->Printf(" stack_commit_size = 0x%16.16" PRIx64 "\n",
1307061da546Spatrick header.stack_commit_size);
1308061da546Spatrick s->Printf(" heap_reserve_size = 0x%16.16" PRIx64 "\n",
1309061da546Spatrick header.heap_reserve_size);
1310061da546Spatrick s->Printf(" heap_commit_size = 0x%16.16" PRIx64 "\n",
1311061da546Spatrick header.heap_commit_size);
1312061da546Spatrick s->Printf(" loader_flags = 0x%8.8x\n", header.loader_flags);
1313061da546Spatrick s->Printf(" num_data_dir_entries = 0x%8.8x\n",
1314061da546Spatrick (uint32_t)header.data_dirs.size());
1315061da546Spatrick uint32_t i;
1316061da546Spatrick for (i = 0; i < header.data_dirs.size(); i++) {
1317061da546Spatrick s->Printf(" data_dirs[%2u] vmaddr = 0x%8.8x, vmsize = 0x%8.8x\n", i,
1318061da546Spatrick header.data_dirs[i].vmaddr, header.data_dirs[i].vmsize);
1319061da546Spatrick }
1320061da546Spatrick }
1321061da546Spatrick // DumpSectionHeader
1322061da546Spatrick //
1323061da546Spatrick // Dump a single ELF section header to the specified output stream
DumpSectionHeader(Stream * s,const section_header_t & sh)1324061da546Spatrick void ObjectFilePECOFF::DumpSectionHeader(Stream *s,
1325061da546Spatrick const section_header_t &sh) {
1326dda28197Spatrick std::string name = std::string(GetSectionName(sh));
1327061da546Spatrick s->Printf("%-16s 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%4.4x "
1328061da546Spatrick "0x%4.4x 0x%8.8x\n",
1329061da546Spatrick name.c_str(), sh.vmaddr, sh.vmsize, sh.offset, sh.size, sh.reloff,
1330061da546Spatrick sh.lineoff, sh.nreloc, sh.nline, sh.flags);
1331061da546Spatrick }
1332061da546Spatrick
1333061da546Spatrick // DumpSectionHeaders
1334061da546Spatrick //
1335061da546Spatrick // Dump all of the ELF section header to the specified output stream
DumpSectionHeaders(Stream * s)1336061da546Spatrick void ObjectFilePECOFF::DumpSectionHeaders(Stream *s) {
1337061da546Spatrick
1338061da546Spatrick s->PutCString("Section Headers\n");
1339061da546Spatrick s->PutCString("IDX name vm addr vm size file off file "
1340061da546Spatrick "size reloc off line off nreloc nline flags\n");
1341061da546Spatrick s->PutCString("==== ---------------- ---------- ---------- ---------- "
1342061da546Spatrick "---------- ---------- ---------- ------ ------ ----------\n");
1343061da546Spatrick
1344061da546Spatrick uint32_t idx = 0;
1345061da546Spatrick SectionHeaderCollIter pos, end = m_sect_headers.end();
1346061da546Spatrick
1347061da546Spatrick for (pos = m_sect_headers.begin(); pos != end; ++pos, ++idx) {
1348061da546Spatrick s->Printf("[%2u] ", idx);
1349061da546Spatrick ObjectFilePECOFF::DumpSectionHeader(s, *pos);
1350061da546Spatrick }
1351061da546Spatrick }
1352061da546Spatrick
1353061da546Spatrick // DumpDependentModules
1354061da546Spatrick //
1355061da546Spatrick // Dump all of the dependent modules to the specified output stream
DumpDependentModules(lldb_private::Stream * s)1356061da546Spatrick void ObjectFilePECOFF::DumpDependentModules(lldb_private::Stream *s) {
1357061da546Spatrick auto num_modules = ParseDependentModules();
1358061da546Spatrick if (num_modules > 0) {
1359061da546Spatrick s->PutCString("Dependent Modules\n");
1360061da546Spatrick for (unsigned i = 0; i < num_modules; ++i) {
1361061da546Spatrick auto spec = m_deps_filespec->GetFileSpecAtIndex(i);
1362061da546Spatrick s->Printf(" %s\n", spec.GetFilename().GetCString());
1363061da546Spatrick }
1364061da546Spatrick }
1365061da546Spatrick }
1366061da546Spatrick
IsWindowsSubsystem()1367061da546Spatrick bool ObjectFilePECOFF::IsWindowsSubsystem() {
1368061da546Spatrick switch (m_coff_header_opt.subsystem) {
1369061da546Spatrick case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE:
1370061da546Spatrick case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI:
1371061da546Spatrick case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI:
1372061da546Spatrick case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE_WINDOWS:
1373061da546Spatrick case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
1374061da546Spatrick case llvm::COFF::IMAGE_SUBSYSTEM_XBOX:
1375061da546Spatrick case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION:
1376061da546Spatrick return true;
1377061da546Spatrick default:
1378061da546Spatrick return false;
1379061da546Spatrick }
1380061da546Spatrick }
1381061da546Spatrick
GetArchitecture()1382061da546Spatrick ArchSpec ObjectFilePECOFF::GetArchitecture() {
1383061da546Spatrick uint16_t machine = m_coff_header.machine;
1384061da546Spatrick switch (machine) {
1385061da546Spatrick default:
1386061da546Spatrick break;
1387061da546Spatrick case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
1388061da546Spatrick case llvm::COFF::IMAGE_FILE_MACHINE_I386:
1389061da546Spatrick case llvm::COFF::IMAGE_FILE_MACHINE_POWERPC:
1390061da546Spatrick case llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP:
1391061da546Spatrick case llvm::COFF::IMAGE_FILE_MACHINE_ARM:
1392061da546Spatrick case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
1393061da546Spatrick case llvm::COFF::IMAGE_FILE_MACHINE_THUMB:
1394061da546Spatrick case llvm::COFF::IMAGE_FILE_MACHINE_ARM64:
1395061da546Spatrick ArchSpec arch;
1396061da546Spatrick arch.SetArchitecture(eArchTypeCOFF, machine, LLDB_INVALID_CPUTYPE,
1397061da546Spatrick IsWindowsSubsystem() ? llvm::Triple::Win32
1398061da546Spatrick : llvm::Triple::UnknownOS);
1399061da546Spatrick return arch;
1400061da546Spatrick }
1401061da546Spatrick return ArchSpec();
1402061da546Spatrick }
1403061da546Spatrick
CalculateType()1404061da546Spatrick ObjectFile::Type ObjectFilePECOFF::CalculateType() {
1405061da546Spatrick if (m_coff_header.machine != 0) {
1406061da546Spatrick if ((m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0)
1407061da546Spatrick return eTypeExecutable;
1408061da546Spatrick else
1409061da546Spatrick return eTypeSharedLibrary;
1410061da546Spatrick }
1411061da546Spatrick return eTypeExecutable;
1412061da546Spatrick }
1413061da546Spatrick
CalculateStrata()1414061da546Spatrick ObjectFile::Strata ObjectFilePECOFF::CalculateStrata() { return eStrataUser; }
1415