LLDB mainline
ObjectContainerMachOFileset.cpp
Go to the documentation of this file.
1//===-- ObjectContainerMachOFileset.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
10#include "lldb/Core/Module.h"
14#include "lldb/Target/Target.h"
17#include "lldb/Utility/Stream.h"
18#include <optional>
19
20using namespace lldb;
21using namespace lldb_private;
22using namespace llvm::MachO;
23
25
26void ObjectContainerMachOFileset::Initialize() {
27 PluginManager::RegisterPlugin(GetPluginNameStatic(),
28 GetPluginDescriptionStatic(), CreateInstance,
29 GetModuleSpecifications, CreateMemoryInstance);
30}
31
34}
35
37 const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
38 lldb::offset_t data_offset, const lldb_private::FileSpec *file,
39 lldb::offset_t offset, lldb::offset_t length)
40 : ObjectContainer(module_sp, file, offset, length, data_sp, data_offset),
41 m_memory_addr(LLDB_INVALID_ADDRESS) {}
42
44 const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp,
45 const lldb::ProcessSP &process_sp, lldb::addr_t header_addr)
46 : ObjectContainer(module_sp, nullptr, 0, data_sp->GetByteSize(), data_sp,
47 0),
48 m_process_wp(process_sp), m_memory_addr(header_addr) {}
49
51 const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
52 lldb::offset_t data_offset, const FileSpec *file,
53 lldb::offset_t file_offset, lldb::offset_t length) {
54 if (!data_sp)
55 return {};
56
57 DataExtractor data;
58 data.SetData(data_sp, data_offset, length);
59 if (!MagicBytesMatch(data))
60 return {};
61
62 auto container_up = std::make_unique<ObjectContainerMachOFileset>(
63 module_sp, data_sp, data_offset, file, file_offset, length);
64 if (!container_up->ParseHeader())
65 return {};
66
67 return container_up.release();
68}
69
71 const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp,
72 const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
73 if (!MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
74 return {};
75
76 auto container_up = std::make_unique<ObjectContainerMachOFileset>(
77 module_sp, data_sp, process_sp, header_addr);
78 if (!container_up->ParseHeader())
79 return {};
80
81 return container_up.release();
82}
83
85
86static uint32_t MachHeaderSizeFromMagic(uint32_t magic) {
87 switch (magic) {
88 case MH_MAGIC:
89 case MH_CIGAM:
90 return sizeof(struct mach_header);
91 case MH_MAGIC_64:
92 case MH_CIGAM_64:
93 return sizeof(struct mach_header_64);
94 default:
95 return 0;
96 }
97}
98
99static std::optional<mach_header> ParseMachOHeader(DataExtractor &data) {
100 lldb::offset_t offset = 0;
101 mach_header header;
102 header.magic = data.GetU32(&offset);
103 switch (header.magic) {
104 case MH_MAGIC:
106 data.SetAddressByteSize(4);
107 break;
108 case MH_MAGIC_64:
110 data.SetAddressByteSize(8);
111 break;
112 case MH_CIGAM:
115 : eByteOrderBig);
116 data.SetAddressByteSize(4);
117 break;
118 case MH_CIGAM_64:
121 : eByteOrderBig);
122 data.SetAddressByteSize(8);
123 break;
124 default:
125 return {};
126 }
127
128 header.cputype = data.GetU32(&offset);
129 header.cpusubtype = data.GetU32(&offset);
130 header.filetype = data.GetU32(&offset);
131 header.ncmds = data.GetU32(&offset);
132 header.sizeofcmds = data.GetU32(&offset);
133 return header;
134}
135
136static bool
137ParseFileset(DataExtractor &data, mach_header header,
138 std::vector<ObjectContainerMachOFileset::Entry> &entries,
139 std::optional<lldb::addr_t> load_addr = std::nullopt) {
140 lldb::offset_t offset = MachHeaderSizeFromMagic(header.magic);
141 lldb::offset_t slide = 0;
142 for (uint32_t i = 0; i < header.ncmds; ++i) {
143 const lldb::offset_t load_cmd_offset = offset;
144 load_command lc = {};
145 if (data.GetU32(&offset, &lc.cmd, 2) == nullptr)
146 break;
147
148 // If we know the load address we can compute the slide.
149 if (load_addr) {
150 if (lc.cmd == llvm::MachO::LC_SEGMENT_64) {
151 segment_command_64 segment;
152 data.CopyData(load_cmd_offset, sizeof(segment_command_64), &segment);
153 if (llvm::StringRef(segment.segname) == "__TEXT")
154 slide = *load_addr - segment.vmaddr;
155 }
156 }
157
158 if (lc.cmd == LC_FILESET_ENTRY) {
159 fileset_entry_command entry;
160 data.CopyData(load_cmd_offset, sizeof(fileset_entry_command), &entry);
161 lldb::offset_t entry_id_offset = load_cmd_offset + entry.entry_id.offset;
162 const char *id = data.GetCStr(&entry_id_offset);
163 entries.emplace_back(entry.vmaddr + slide, entry.fileoff,
164 std::string(id));
165 }
166
167 offset = load_cmd_offset + lc.cmdsize;
168 }
169
170 return true;
171}
172
174 DataExtractor &data, const lldb_private::FileSpec &file,
175 lldb::offset_t file_offset, std::vector<Entry> &entries) {
176 std::optional<mach_header> header = ParseMachOHeader(data);
177
178 if (!header)
179 return false;
180
181 const size_t header_size = MachHeaderSizeFromMagic(header->magic);
182 const size_t header_and_lc_size = header_size + header->sizeofcmds;
183
184 if (data.GetByteSize() < header_and_lc_size) {
185 DataBufferSP data_sp =
186 ObjectFile::MapFileData(file, header_and_lc_size, file_offset);
187 data.SetData(data_sp);
188 }
189
190 return ParseFileset(data, *header, entries);
191}
192
194 ModuleSP module_sp(GetModule());
195 if (!module_sp)
196 return false;
197
198 std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
199
200 std::optional<mach_header> header = ParseMachOHeader(m_data);
201 if (!header)
202 return false;
203
204 const size_t header_size = MachHeaderSizeFromMagic(header->magic);
205 const size_t header_and_lc_size = header_size + header->sizeofcmds;
206
207 if (m_data.GetByteSize() < header_and_lc_size) {
208 ProcessSP process_sp(m_process_wp.lock());
209 DataBufferSP data_sp =
210 process_sp
212 header_and_lc_size)
213 : ObjectFile::MapFileData(m_file, header_and_lc_size, m_offset);
214 m_data.SetData(data_sp);
215 }
216
217 return ParseFileset(m_data, *header, m_entries, m_memory_addr);
218}
219
221 const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
222 lldb::offset_t data_offset, lldb::offset_t file_offset,
224 const size_t initial_count = specs.GetSize();
225
226 DataExtractor data;
227 data.SetData(data_sp, data_offset, data_sp->GetByteSize());
228
229 if (MagicBytesMatch(data)) {
230 std::vector<Entry> entries;
231 if (ParseHeader(data, file, file_offset, entries)) {
232 for (const Entry &entry : entries) {
233 const lldb::offset_t entry_offset = entry.fileoff + file_offset;
235 file, entry_offset, file_size - entry_offset, specs)) {
236 ModuleSpec &spec = specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1);
237 spec.GetObjectName() = ConstString(entry.id);
238 }
239 }
240 }
241 }
242 return specs.GetSize() - initial_count;
243}
244
246 lldb::addr_t data_offset,
247 lldb::addr_t data_length) {
248 DataExtractor data;
249 data.SetData(data_sp, data_offset, data_length);
250 return MagicBytesMatch(data);
251}
252
254 lldb::offset_t offset = 0;
255 uint32_t magic = data.GetU32(&offset);
256 switch (magic) {
257 case MH_MAGIC:
258 case MH_CIGAM:
259 case MH_MAGIC_64:
260 case MH_CIGAM_64:
261 break;
262 default:
263 return false;
264 }
265 offset += 4; // cputype
266 offset += 4; // cpusubtype
267 uint32_t filetype = data.GetU32(&offset);
268 return filetype == MH_FILESET;
269}
270
273 ModuleSP module_sp(GetModule());
274 if (!module_sp)
275 return {};
276
277 ConstString object_name = module_sp->GetObjectName();
278 if (!object_name)
279 return {};
280
281 Entry *entry = FindEntry(object_name.GetCString());
282 if (!entry)
283 return {};
284
285 DataBufferSP data_sp;
286 lldb::offset_t data_offset = 0;
287 return ObjectFile::FindPlugin(module_sp, file, m_offset + entry->fileoff,
288 m_data.GetByteSize() - entry->fileoff, data_sp,
289 data_offset);
290}
291
294 for (Entry &entry : m_entries) {
295 if (entry.id == id)
296 return &entry;
297 }
298 return nullptr;
299}
static bool ParseFileset(DataExtractor &data, mach_header header, std::vector< ObjectContainerMachOFileset::Entry > &entries, std::optional< lldb::addr_t > load_addr=std::nullopt)
static std::optional< mach_header > ParseMachOHeader(DataExtractor &data)
static uint32_t MachHeaderSizeFromMagic(uint32_t magic)
#define LLDB_PLUGIN_DEFINE(PluginName)
Definition: PluginManager.h:31
A uniqued constant string class.
Definition: ConstString.h:40
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:214
An data extractor class.
Definition: DataExtractor.h:48
const char * GetCStr(lldb::offset_t *offset_ptr) const
Extract a C string from *offset_ptr.
lldb::offset_t CopyData(lldb::offset_t offset, lldb::offset_t length, void *dst) const
Copy length bytes from *offset, without swapping bytes.
void SetByteOrder(lldb::ByteOrder byte_order)
Set the byte_order value.
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
uint64_t GetByteSize() const
Get the number of bytes contained in this object.
lldb::offset_t SetData(const void *bytes, lldb::offset_t length, lldb::ByteOrder byte_order)
Set data with a buffer that is caller owned.
void SetAddressByteSize(uint32_t addr_size)
Set the address byte size.
A file utility class.
Definition: FileSpec.h:56
lldb::ModuleSP GetModule() const
Get const accessor for the module pointer.
Definition: ModuleChild.cpp:24
ModuleSpec & GetModuleSpecRefAtIndex(size_t i)
Definition: ModuleSpec.h:321
ConstString & GetObjectName()
Definition: ModuleSpec.h:103
static bool MagicBytesMatch(const lldb_private::DataExtractor &data)
static lldb_private::ObjectContainer * CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, lldb::offset_t offset, lldb::offset_t length)
ObjectContainerMachOFileset(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, lldb::offset_t offset, lldb::offset_t length)
static lldb_private::ObjectContainer * CreateMemoryInstance(const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header_addr)
static size_t 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)
bool ParseHeader() override
Attempts to parse the object header.
lldb::ObjectFileSP GetObjectFile(const lldb_private::FileSpec *file) override
Selects an architecture in an object file.
A plug-in interface definition class for object containers.
DataExtractor m_data
The data for this object file so things can be parsed lazily.
FileSpec m_file
The file that represents this container objects (which can be different from the module's file).
lldb::addr_t m_offset
The offset in bytes into the file, or the address in memory.
static lldb::ObjectFileSP FindPlugin(const lldb::ModuleSP &module_sp, const FileSpec *file_spec, lldb::offset_t file_offset, lldb::offset_t file_size, lldb::DataBufferSP &data_sp, lldb::offset_t &data_offset)
Find a ObjectFile plug-in that can parse file_spec.
Definition: ObjectFile.cpp:53
static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size, uint64_t Offset)
Definition: ObjectFile.cpp:661
static lldb::DataBufferSP ReadMemory(const lldb::ProcessSP &process_sp, lldb::addr_t addr, size_t byte_size)
Definition: ObjectFile.cpp:448
static size_t GetModuleSpecifications(const FileSpec &file, lldb::offset_t file_offset, lldb::offset_t file_size, ModuleSpecList &specs, lldb::DataBufferSP data_sp=lldb::DataBufferSP())
Definition: ObjectFile.cpp:187
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:82
lldb::ByteOrder InlHostByteOrder()
Definition: Endian.h:25
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Definition: SBAddress.h:15
uint64_t offset_t
Definition: lldb-types.h:83
std::shared_ptr< lldb_private::ObjectFile > ObjectFileSP
Definition: lldb-forward.h:367
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:381
@ eByteOrderLittle
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
Definition: lldb-forward.h:328
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
Definition: lldb-forward.h:329
uint64_t addr_t
Definition: lldb-types.h:79
std::shared_ptr< lldb_private::Module > ModuleSP
Definition: lldb-forward.h:365