Coverage Report

Created: 2022-01-25 06:29

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- ObjectContainerUniversalMachO.cpp ---------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "ObjectContainerUniversalMachO.h"
10
#include "lldb/Core/Module.h"
11
#include "lldb/Core/ModuleSpec.h"
12
#include "lldb/Core/PluginManager.h"
13
#include "lldb/Symbol/ObjectFile.h"
14
#include "lldb/Target/Target.h"
15
#include "lldb/Utility/ArchSpec.h"
16
#include "lldb/Utility/DataBuffer.h"
17
#include "lldb/Utility/Stream.h"
18
19
using namespace lldb;
20
using namespace lldb_private;
21
using namespace llvm::MachO;
22
23
LLDB_PLUGIN_DEFINE_ADV(ObjectContainerUniversalMachO,
24
                       ObjectContainerMachOArchive)
25
26
3.44k
void ObjectContainerUniversalMachO::Initialize() {
27
3.44k
  PluginManager::RegisterPlugin(GetPluginNameStatic(),
28
3.44k
                                GetPluginDescriptionStatic(), CreateInstance,
29
3.44k
                                GetModuleSpecifications);
30
3.44k
}
31
32
3.43k
void ObjectContainerUniversalMachO::Terminate() {
33
3.43k
  PluginManager::UnregisterPlugin(CreateInstance);
34
3.43k
}
35
36
ObjectContainer *ObjectContainerUniversalMachO::CreateInstance(
37
    const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
38
    lldb::offset_t data_offset, const FileSpec *file,
39
400
    lldb::offset_t file_offset, lldb::offset_t length) {
40
  // We get data when we aren't trying to look for cached container
41
  // information, so only try and look for an architecture slice if we get data
42
400
  if (data_sp) {
43
193
    DataExtractor data;
44
193
    data.SetData(data_sp, data_offset, length);
45
193
    if (ObjectContainerUniversalMachO::MagicBytesMatch(data)) {
46
193
      std::unique_ptr<ObjectContainerUniversalMachO> container_up(
47
193
          new ObjectContainerUniversalMachO(module_sp, data_sp, data_offset,
48
193
                                            file, file_offset, length));
49
193
      if (container_up->ParseHeader()) {
50
193
        return container_up.release();
51
193
      }
52
193
    }
53
193
  }
54
207
  return nullptr;
55
400
}
56
57
2.86k
bool ObjectContainerUniversalMachO::MagicBytesMatch(const DataExtractor &data) {
58
2.86k
  lldb::offset_t offset = 0;
59
2.86k
  uint32_t magic = data.GetU32(&offset);
60
2.86k
  return magic == FAT_MAGIC || magic == FAT_CIGAM;
61
2.86k
}
62
63
ObjectContainerUniversalMachO::ObjectContainerUniversalMachO(
64
    const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
65
    lldb::offset_t data_offset, const FileSpec *file,
66
    lldb::offset_t file_offset, lldb::offset_t length)
67
    : ObjectContainer(module_sp, file, file_offset, length, data_sp,
68
                      data_offset),
69
193
      m_header(), m_fat_archs() {
70
193
  memset(&m_header, 0, sizeof(m_header));
71
193
}
72
73
193
ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO() = default;
74
75
193
bool ObjectContainerUniversalMachO::ParseHeader() {
76
193
  bool success = ParseHeader(m_data, m_header, m_fat_archs);
77
  // We no longer need any data, we parsed all we needed to parse and cached it
78
  // in m_header and m_fat_archs
79
193
  m_data.Clear();
80
193
  return success;
81
193
}
82
83
bool ObjectContainerUniversalMachO::ParseHeader(
84
    lldb_private::DataExtractor &data, llvm::MachO::fat_header &header,
85
2.85k
    std::vector<llvm::MachO::fat_arch> &fat_archs) {
86
2.85k
  bool success = false;
87
  // Store the file offset for this universal file as we could have a universal
88
  // .o file in a BSD archive, or be contained in another kind of object.
89
  // Universal mach-o files always have their headers in big endian.
90
2.85k
  lldb::offset_t offset = 0;
91
2.85k
  data.SetByteOrder(eByteOrderBig);
92
2.85k
  header.magic = data.GetU32(&offset);
93
2.85k
  fat_archs.clear();
94
95
2.85k
  if (header.magic == FAT_MAGIC) {
96
97
2.85k
    data.SetAddressByteSize(4);
98
99
2.85k
    header.nfat_arch = data.GetU32(&offset);
100
101
    // Now we should have enough data for all of the fat headers, so lets index
102
    // them so we know how many architectures that this universal binary
103
    // contains.
104
2.85k
    uint32_t arch_idx = 0;
105
8.56k
    for (arch_idx = 0; arch_idx < header.nfat_arch; 
++arch_idx5.71k
) {
106
5.71k
      if (data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch))) {
107
5.71k
        fat_arch arch;
108
5.71k
        if (data.GetU32(&offset, &arch, sizeof(fat_arch) / sizeof(uint32_t)))
109
5.71k
          fat_archs.push_back(arch);
110
5.71k
      }
111
5.71k
    }
112
2.85k
    success = true;
113
2.85k
  } else {
114
0
    memset(&header, 0, sizeof(header));
115
0
  }
116
2.85k
  return success;
117
2.85k
}
118
119
0
void ObjectContainerUniversalMachO::Dump(Stream *s) const {
120
0
  s->Printf("%p: ", static_cast<const void *>(this));
121
0
  s->Indent();
122
0
  const size_t num_archs = GetNumArchitectures();
123
0
  const size_t num_objects = GetNumObjects();
124
0
  s->Printf("ObjectContainerUniversalMachO, num_archs = %zu, num_objects = %zu",
125
0
            num_archs, num_objects);
126
0
  uint32_t i;
127
0
  ArchSpec arch;
128
0
  s->IndentMore();
129
0
  for (i = 0; i < num_archs; i++) {
130
0
    s->Indent();
131
0
    GetArchitectureAtIndex(i, arch);
132
0
    s->Printf("arch[%u] = %s\n", i, arch.GetArchitectureName());
133
0
  }
134
0
  for (i = 0; i < num_objects; i++) {
135
0
    s->Indent();
136
0
    s->Printf("object[%u] = %s\n", i, GetObjectNameAtIndex(i));
137
0
  }
138
0
  s->IndentLess();
139
0
  s->EOL();
140
0
}
141
142
0
size_t ObjectContainerUniversalMachO::GetNumArchitectures() const {
143
0
  return m_header.nfat_arch;
144
0
}
145
146
bool ObjectContainerUniversalMachO::GetArchitectureAtIndex(
147
193
    uint32_t idx, ArchSpec &arch) const {
148
193
  if (idx < m_header.nfat_arch) {
149
193
    arch.SetArchitecture(eArchTypeMachO, m_fat_archs[idx].cputype,
150
193
                         m_fat_archs[idx].cpusubtype);
151
193
    return true;
152
193
  }
153
0
  return false;
154
193
}
155
156
ObjectFileSP
157
193
ObjectContainerUniversalMachO::GetObjectFile(const FileSpec *file) {
158
193
  uint32_t arch_idx = 0;
159
193
  ArchSpec arch;
160
  // If the module hasn't specified an architecture yet, set it to the default
161
  // architecture:
162
193
  ModuleSP module_sp(GetModule());
163
193
  if (module_sp) {
164
193
    if (!module_sp->GetArchitecture().IsValid()) {
165
0
      arch = Target::GetDefaultArchitecture();
166
0
      if (!arch.IsValid())
167
0
        arch.SetTriple(LLDB_ARCH_DEFAULT);
168
0
    } else
169
193
      arch = module_sp->GetArchitecture();
170
171
193
    ArchSpec curr_arch;
172
    // First, try to find an exact match for the Arch of the Target.
173
193
    for (arch_idx = 0; arch_idx < m_header.nfat_arch; 
++arch_idx0
) {
174
193
      if (GetArchitectureAtIndex(arch_idx, curr_arch) &&
175
193
          arch.IsExactMatch(curr_arch))
176
193
        break;
177
193
    }
178
179
    // Failing an exact match, try to find a compatible Arch of the Target.
180
193
    if (arch_idx >= m_header.nfat_arch) {
181
0
      for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx) {
182
0
        if (GetArchitectureAtIndex(arch_idx, curr_arch) &&
183
0
            arch.IsCompatibleMatch(curr_arch))
184
0
          break;
185
0
      }
186
0
    }
187
188
193
    if (arch_idx < m_header.nfat_arch) {
189
193
      DataBufferSP data_sp;
190
193
      lldb::offset_t data_offset = 0;
191
193
      return ObjectFile::FindPlugin(
192
193
          module_sp, file, m_offset + m_fat_archs[arch_idx].offset,
193
193
          m_fat_archs[arch_idx].size, data_sp, data_offset);
194
193
    }
195
193
  }
196
0
  return ObjectFileSP();
197
193
}
198
199
size_t ObjectContainerUniversalMachO::GetModuleSpecifications(
200
    const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
201
    lldb::offset_t data_offset, lldb::offset_t file_offset,
202
2.67k
    lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) {
203
2.67k
  const size_t initial_count = specs.GetSize();
204
205
2.67k
  DataExtractor data;
206
2.67k
  data.SetData(data_sp, data_offset, data_sp->GetByteSize());
207
208
2.67k
  if (ObjectContainerUniversalMachO::MagicBytesMatch(data)) {
209
2.66k
    llvm::MachO::fat_header header;
210
2.66k
    std::vector<llvm::MachO::fat_arch> fat_archs;
211
2.66k
    if (ParseHeader(data, header, fat_archs)) {
212
5.32k
      for (const llvm::MachO::fat_arch &fat_arch : fat_archs) {
213
5.32k
        const lldb::offset_t slice_file_offset = fat_arch.offset + file_offset;
214
5.32k
        if (fat_arch.offset < file_size && file_size > slice_file_offset) {
215
5.32k
          ObjectFile::GetModuleSpecifications(
216
5.32k
              file, slice_file_offset, file_size - slice_file_offset, specs);
217
5.32k
        }
218
5.32k
      }
219
2.66k
    }
220
2.66k
  }
221
2.67k
  return specs.GetSize() - initial_count;
222
2.67k
}