1 //===-- ObjectFileCOFF.cpp ------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "ObjectFileCOFF.h"
11 #include "lldb/Core/Module.h"
12 #include "lldb/Core/ModuleSpec.h"
13 #include "lldb/Core/PluginManager.h"
14 #include "lldb/Utility/LLDBLog.h"
16 #include "llvm/Support/Error.h"
17 #include "llvm/Support/FormatAdapters.h"
20 using namespace lldb_private
;
23 using namespace llvm::object
;
25 static bool IsCOFFObjectFile(const DataBufferSP
&data
) {
26 return identify_magic(toStringRef(data
->GetData())) ==
27 file_magic::coff_object
;
30 LLDB_PLUGIN_DEFINE(ObjectFileCOFF
)
32 char ObjectFileCOFF::ID
;
34 ObjectFileCOFF::~ObjectFileCOFF() = default;
36 void ObjectFileCOFF::Initialize() {
37 PluginManager::RegisterPlugin(GetPluginNameStatic(),
38 GetPluginDescriptionStatic(), CreateInstance
,
39 CreateMemoryInstance
, GetModuleSpecifications
);
42 void ObjectFileCOFF::Terminate() {
43 PluginManager::UnregisterPlugin(CreateInstance
);
46 lldb_private::ObjectFile
*
47 ObjectFileCOFF::CreateInstance(const ModuleSP
&module_sp
, DataBufferSP data_sp
,
48 offset_t data_offset
, const FileSpec
*file
,
49 offset_t file_offset
, offset_t length
) {
50 Log
*log
= GetLog(LLDBLog::Object
);
53 data_sp
= MapFileData(*file
, length
, file_offset
);
56 "Failed to create ObjectFileCOFF instance: cannot read file {0}",
63 assert(data_sp
&& "must have mapped file at this point");
65 if (!IsCOFFObjectFile(data_sp
))
68 if (data_sp
->GetByteSize() < length
) {
69 data_sp
= MapFileData(*file
, length
, file_offset
);
72 "Failed to create ObjectFileCOFF instance: cannot read file {0}",
80 MemoryBufferRef buffer
{toStringRef(data_sp
->GetData()),
81 file
->GetFilename().GetStringRef()};
83 Expected
<std::unique_ptr
<Binary
>> binary
= createBinary(buffer
);
85 LLDB_LOG_ERROR(log
, binary
.takeError(),
86 "Failed to create binary for file ({1}): {0}",
91 LLDB_LOG(log
, "ObjectFileCOFF::ObjectFileCOFF module = {1} ({2}), file = {3}",
92 module_sp
.get(), module_sp
->GetSpecificationDescription(),
95 return new ObjectFileCOFF(unique_dyn_cast
<COFFObjectFile
>(std::move(*binary
)),
96 module_sp
, data_sp
, data_offset
, file
, file_offset
,
100 lldb_private::ObjectFile
*ObjectFileCOFF::CreateMemoryInstance(
101 const ModuleSP
&module_sp
, WritableDataBufferSP data_sp
,
102 const ProcessSP
&process_sp
, addr_t header
) {
103 // FIXME: do we need to worry about construction from a memory region?
107 size_t ObjectFileCOFF::GetModuleSpecifications(
108 const FileSpec
&file
, DataBufferSP
&data_sp
, offset_t data_offset
,
109 offset_t file_offset
, offset_t length
, ModuleSpecList
&specs
) {
110 if (!IsCOFFObjectFile(data_sp
))
113 MemoryBufferRef buffer
{toStringRef(data_sp
->GetData()),
114 file
.GetFilename().GetStringRef()};
115 Expected
<std::unique_ptr
<Binary
>> binary
= createBinary(buffer
);
117 Log
*log
= GetLog(LLDBLog::Object
);
118 LLDB_LOG_ERROR(log
, binary
.takeError(),
119 "Failed to create binary for file ({1}): {0}",
124 std::unique_ptr
<COFFObjectFile
> object
=
125 unique_dyn_cast
<COFFObjectFile
>(std::move(*binary
));
126 switch (static_cast<COFF::MachineTypes
>(object
->getMachine())) {
127 case COFF::IMAGE_FILE_MACHINE_I386
:
128 specs
.Append(ModuleSpec(file
, ArchSpec("i686-unknown-windows-msvc")));
130 case COFF::IMAGE_FILE_MACHINE_AMD64
:
131 specs
.Append(ModuleSpec(file
, ArchSpec("x86_64-unknown-windows-msvc")));
133 case COFF::IMAGE_FILE_MACHINE_ARMNT
:
134 specs
.Append(ModuleSpec(file
, ArchSpec("armv7-unknown-windows-msvc")));
136 case COFF::IMAGE_FILE_MACHINE_ARM64
:
137 specs
.Append(ModuleSpec(file
, ArchSpec("aarch64-unknown-windows-msvc")));
144 void ObjectFileCOFF::Dump(Stream
*stream
) {
145 ModuleSP
module(GetModule());
149 std::lock_guard
<std::recursive_mutex
> guard(module
->GetMutex());
151 stream
->Printf("%p: ", static_cast<void *>(this));
153 stream
->PutCString("ObjectFileCOFF");
154 *stream
<< ", file = '" << m_file
155 << "', arch = " << GetArchitecture().GetArchitectureName() << '\n';
157 if (SectionList
*sections
= GetSectionList())
158 sections
->Dump(stream
->AsRawOstream(), stream
->GetIndentLevel(), nullptr,
159 true, std::numeric_limits
<uint32_t>::max());
162 uint32_t ObjectFileCOFF::GetAddressByteSize() const {
163 return const_cast<ObjectFileCOFF
*>(this)->GetArchitecture().GetAddressByteSize();
166 ArchSpec
ObjectFileCOFF::GetArchitecture() {
167 switch (static_cast<COFF::MachineTypes
>(m_object
->getMachine())) {
168 case COFF::IMAGE_FILE_MACHINE_I386
:
169 return ArchSpec("i686-unknown-windows-msvc");
170 case COFF::IMAGE_FILE_MACHINE_AMD64
:
171 return ArchSpec("x86_64-unknown-windows-msvc");
172 case COFF::IMAGE_FILE_MACHINE_ARMNT
:
173 return ArchSpec("armv7-unknown-windows-msvc");
174 case COFF::IMAGE_FILE_MACHINE_ARM64
:
175 return ArchSpec("aarch64-unknown-windows-msvc");
181 void ObjectFileCOFF::CreateSections(lldb_private::SectionList
§ions
) {
185 m_sections_up
= std::make_unique
<SectionList
>();
186 ModuleSP
module(GetModule());
190 std::lock_guard
<std::recursive_mutex
> guard(module
->GetMutex());
192 auto SectionType
= [](StringRef Name
,
193 const coff_section
*Section
) -> lldb::SectionType
{
194 lldb::SectionType type
=
195 StringSwitch
<lldb::SectionType
>(Name
)
196 // DWARF Debug Sections
197 .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev
)
198 .Case(".debug_info", eSectionTypeDWARFDebugInfo
)
199 .Case(".debug_line", eSectionTypeDWARFDebugLine
)
200 .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames
)
201 .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes
)
202 .Case(".debug_str", eSectionTypeDWARFDebugStr
)
203 // CodeView Debug Sections: .debug$S, .debug$T
204 .StartsWith(".debug$", eSectionTypeDebug
)
205 .Case("clangast", eSectionTypeOther
)
206 .Default(eSectionTypeInvalid
);
207 if (type
!= eSectionTypeInvalid
)
210 if (Section
->Characteristics
& COFF::IMAGE_SCN_CNT_CODE
)
211 return eSectionTypeCode
;
212 if (Section
->Characteristics
& COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
)
213 return eSectionTypeData
;
214 if (Section
->Characteristics
& COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
215 return Section
->SizeOfRawData
? eSectionTypeData
: eSectionTypeZeroFill
;
216 return eSectionTypeOther
;
218 auto Permissions
= [](const object::coff_section
*Section
) -> uint32_t {
219 uint32_t permissions
= 0;
220 if (Section
->Characteristics
& COFF::IMAGE_SCN_MEM_EXECUTE
)
221 permissions
|= lldb::ePermissionsExecutable
;
222 if (Section
->Characteristics
& COFF::IMAGE_SCN_MEM_READ
)
223 permissions
|= lldb::ePermissionsReadable
;
224 if (Section
->Characteristics
& COFF::IMAGE_SCN_MEM_WRITE
)
225 permissions
|= lldb::ePermissionsWritable
;
229 for (const auto &SecRef
: m_object
->sections()) {
230 const auto COFFSection
= m_object
->getCOFFSection(SecRef
);
232 llvm::Expected
<StringRef
> Name
= SecRef
.getName();
233 StringRef SectionName
= Name
? *Name
: COFFSection
->Name
;
235 consumeError(Name
.takeError());
238 std::make_unique
<Section
>(module
, this,
239 static_cast<user_id_t
>(SecRef
.getIndex()),
240 ConstString(SectionName
),
241 SectionType(SectionName
, COFFSection
),
242 COFFSection
->VirtualAddress
,
243 COFFSection
->VirtualSize
,
244 COFFSection
->PointerToRawData
,
245 COFFSection
->SizeOfRawData
,
246 COFFSection
->getAlignment(),
248 section
->SetPermissions(Permissions(COFFSection
));
250 m_sections_up
->AddSection(section
);
251 sections
.AddSection(section
);
255 void ObjectFileCOFF::ParseSymtab(lldb_private::Symtab
&symtab
) {
256 Log
*log
= GetLog(LLDBLog::Object
);
258 SectionList
*sections
= GetSectionList();
259 symtab
.Reserve(symtab
.GetNumSymbols() + m_object
->getNumberOfSymbols());
261 auto SymbolType
= [](const COFFSymbolRef
&Symbol
) -> lldb::SymbolType
{
262 if (Symbol
.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION
)
263 return eSymbolTypeCode
;
264 if (Symbol
.getBaseType() == COFF::IMAGE_SYM_TYPE_NULL
&&
265 Symbol
.getComplexType() == COFF::IMAGE_SYM_DTYPE_NULL
)
266 return eSymbolTypeData
;
267 return eSymbolTypeInvalid
;
270 for (const auto &SymRef
: m_object
->symbols()) {
271 const auto COFFSymRef
= m_object
->getCOFFSymbol(SymRef
);
273 Expected
<StringRef
> NameOrErr
= SymRef
.getName();
275 LLDB_LOG_ERROR(log
, NameOrErr
.takeError(),
276 "ObjectFileCOFF: failed to get symbol name: {0}");
281 symbol
.GetMangled().SetValue(ConstString(*NameOrErr
));
283 int16_t SecIdx
= static_cast<int16_t>(COFFSymRef
.getSectionNumber());
284 if (SecIdx
== COFF::IMAGE_SYM_ABSOLUTE
) {
285 symbol
.GetAddressRef() = Address
{COFFSymRef
.getValue()};
286 symbol
.SetType(eSymbolTypeAbsolute
);
287 } else if (SecIdx
>= 1) {
288 symbol
.GetAddressRef() = Address(sections
->GetSectionAtIndex(SecIdx
- 1),
289 COFFSymRef
.getValue());
290 symbol
.SetType(SymbolType(COFFSymRef
));
293 symtab
.AddSymbol(symbol
);
296 LLDB_LOG(log
, "ObjectFileCOFF::ParseSymtab processed {0} symbols",
297 m_object
->getNumberOfSymbols());
300 bool ObjectFileCOFF::ParseHeader() {
301 ModuleSP
module(GetModule());
305 std::lock_guard
<std::recursive_mutex
> guard(module
->GetMutex());
307 m_data
.SetByteOrder(eByteOrderLittle
);
308 m_data
.SetAddressByteSize(GetAddressByteSize());