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