Coverage Report

Created: 2023-11-11 10:31

/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.95k
void ObjectContainerUniversalMachO::Initialize() {
27
3.95k
  PluginManager::RegisterPlugin(GetPluginNameStatic(),
28
3.95k
                                GetPluginDescriptionStatic(), CreateInstance,
29
3.95k
                                GetModuleSpecifications);
30
3.95k
}
31
32
3.94k
void ObjectContainerUniversalMachO::Terminate() {
33
3.94k
  PluginManager::UnregisterPlugin(CreateInstance);
34
3.94k
}
35
36
ObjectContainer *ObjectContainerUniversalMachO::CreateInstance(
37
    const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
38
    lldb::offset_t data_offset, const FileSpec *file,
39
111
    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
111
  if (data_sp) {
43
51
    DataExtractor data;
44
51
    data.SetData(data_sp, data_offset, length);
45
51
    if (ObjectContainerUniversalMachO::MagicBytesMatch(data)) {
46
51
      std::unique_ptr<ObjectContainerUniversalMachO> container_up(
47
51
          new ObjectContainerUniversalMachO(module_sp, data_sp, data_offset,
48
51
                                            file, file_offset, length));
49
51
      if (container_up->ParseHeader()) {
50
51
        return container_up.release();
51
51
      }
52
51
    }
53
51
  }
54
60
  return nullptr;
55
111
}
56
57
2.34k
bool ObjectContainerUniversalMachO::MagicBytesMatch(const DataExtractor &data) {
58
2.34k
  lldb::offset_t offset = 0;
59
2.34k
  uint32_t magic = data.GetU32(&offset);
60
2.34k
  return magic == FAT_MAGIC || magic == FAT_CIGAM || 
magic == FAT_MAGIC_6422
||
61
2.34k
         
magic == FAT_CIGAM_6422
;
62
2.34k
}
63
64
ObjectContainerUniversalMachO::ObjectContainerUniversalMachO(
65
    const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
66
    lldb::offset_t data_offset, const FileSpec *file,
67
    lldb::offset_t file_offset, lldb::offset_t length)
68
51
    : ObjectContainer(module_sp, file, file_offset, length, data_sp,
69
51
                      data_offset),
70
51
      m_header(), m_fat_archs() {
71
51
  memset(&m_header, 0, sizeof(m_header));
72
51
}
73
74
51
ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO() = default;
75
76
51
bool ObjectContainerUniversalMachO::ParseHeader() {
77
51
  bool success = ParseHeader(m_data, m_header, m_fat_archs);
78
  // We no longer need any data, we parsed all we needed to parse and cached it
79
  // in m_header and m_fat_archs
80
51
  m_data.Clear();
81
51
  return success;
82
51
}
83
84
bool ObjectContainerUniversalMachO::ParseHeader(
85
    lldb_private::DataExtractor &data, llvm::MachO::fat_header &header,
86
2.32k
    std::vector<FatArch> &fat_archs) {
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
2.32k
  lldb::offset_t offset = 0;
90
2.32k
  data.SetByteOrder(eByteOrderBig);
91
2.32k
  header.magic = data.GetU32(&offset);
92
2.32k
  fat_archs.clear();
93
94
  // Universal mach-o files always have their headers in big endian.
95
2.32k
  if (header.magic == FAT_MAGIC || 
header.magic == FAT_MAGIC_646
) {
96
2.32k
    const bool is_fat64 = header.magic == FAT_MAGIC_64;
97
2.32k
    data.SetAddressByteSize(is_fat64 ? 
86
:
42.32k
);
98
99
2.32k
    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
7.03k
    for (uint32_t arch_idx = 0; arch_idx < header.nfat_arch; 
++arch_idx4.70k
) {
105
4.70k
      if (data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch))) {
106
4.70k
        if (is_fat64) {
107
12
          fat_arch_64 arch;
108
12
          arch.cputype = data.GetU32(&offset);
109
12
          arch.cpusubtype = data.GetU32(&offset);
110
12
          arch.offset = data.GetU64(&offset);
111
12
          arch.size = data.GetU64(&offset);
112
12
          arch.align = data.GetU32(&offset);
113
12
          arch.reserved = data.GetU32(&offset);
114
12
          fat_archs.emplace_back(arch);
115
4.69k
        } else {
116
4.69k
          fat_arch arch;
117
4.69k
          arch.cputype = data.GetU32(&offset);
118
4.69k
          arch.cpusubtype = data.GetU32(&offset);
119
4.69k
          arch.offset = data.GetU32(&offset);
120
4.69k
          arch.size = data.GetU32(&offset);
121
4.69k
          arch.align = data.GetU32(&offset);
122
4.69k
          fat_archs.emplace_back(arch);
123
4.69k
        }
124
4.70k
      }
125
4.70k
    }
126
2.32k
    return true;
127
2.32k
  }
128
129
0
  memset(&header, 0, sizeof(header));
130
0
  return true;
131
2.32k
}
132
133
0
size_t ObjectContainerUniversalMachO::GetNumArchitectures() const {
134
0
  return m_header.nfat_arch;
135
0
}
136
137
bool ObjectContainerUniversalMachO::GetArchitectureAtIndex(
138
51
    uint32_t idx, ArchSpec &arch) const {
139
51
  if (idx < m_header.nfat_arch) {
140
51
    arch.SetArchitecture(eArchTypeMachO, m_fat_archs[idx].GetCPUType(),
141
51
                         m_fat_archs[idx].GetCPUSubType());
142
51
    return true;
143
51
  }
144
0
  return false;
145
51
}
146
147
ObjectFileSP
148
51
ObjectContainerUniversalMachO::GetObjectFile(const FileSpec *file) {
149
51
  uint32_t arch_idx = 0;
150
51
  ArchSpec arch;
151
  // If the module hasn't specified an architecture yet, set it to the default
152
  // architecture:
153
51
  ModuleSP module_sp(GetModule());
154
51
  if (module_sp) {
155
51
    if (!module_sp->GetArchitecture().IsValid()) {
156
0
      arch = Target::GetDefaultArchitecture();
157
0
      if (!arch.IsValid())
158
0
        arch.SetTriple(LLDB_ARCH_DEFAULT);
159
0
    } else
160
51
      arch = module_sp->GetArchitecture();
161
162
51
    ArchSpec curr_arch;
163
    // First, try to find an exact match for the Arch of the Target.
164
51
    for (arch_idx = 0; arch_idx < m_header.nfat_arch; 
++arch_idx0
) {
165
51
      if (GetArchitectureAtIndex(arch_idx, curr_arch) &&
166
51
          arch.IsExactMatch(curr_arch))
167
51
        break;
168
51
    }
169
170
    // Failing an exact match, try to find a compatible Arch of the Target.
171
51
    if (arch_idx >= m_header.nfat_arch) {
172
0
      for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx) {
173
0
        if (GetArchitectureAtIndex(arch_idx, curr_arch) &&
174
0
            arch.IsCompatibleMatch(curr_arch))
175
0
          break;
176
0
      }
177
0
    }
178
179
51
    if (arch_idx < m_header.nfat_arch) {
180
51
      DataBufferSP data_sp;
181
51
      lldb::offset_t data_offset = 0;
182
51
      return ObjectFile::FindPlugin(
183
51
          module_sp, file, m_offset + m_fat_archs[arch_idx].GetOffset(),
184
51
          m_fat_archs[arch_idx].GetSize(), data_sp, data_offset);
185
51
    }
186
51
  }
187
0
  return ObjectFileSP();
188
51
}
189
190
size_t ObjectContainerUniversalMachO::GetModuleSpecifications(
191
    const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
192
    lldb::offset_t data_offset, lldb::offset_t file_offset,
193
2.29k
    lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) {
194
2.29k
  const size_t initial_count = specs.GetSize();
195
196
2.29k
  DataExtractor data;
197
2.29k
  data.SetData(data_sp, data_offset, data_sp->GetByteSize());
198
199
2.29k
  if (ObjectContainerUniversalMachO::MagicBytesMatch(data)) {
200
2.27k
    llvm::MachO::fat_header header;
201
2.27k
    std::vector<FatArch> fat_archs;
202
2.27k
    if (ParseHeader(data, header, fat_archs)) {
203
4.55k
      for (const FatArch &fat_arch : fat_archs) {
204
4.55k
        const lldb::offset_t slice_file_offset =
205
4.55k
            fat_arch.GetOffset() + file_offset;
206
4.55k
        if (fat_arch.GetOffset() < file_size && file_size > slice_file_offset) {
207
4.55k
          ObjectFile::GetModuleSpecifications(
208
4.55k
              file, slice_file_offset, file_size - slice_file_offset, specs);
209
4.55k
        }
210
4.55k
      }
211
2.27k
    }
212
2.27k
  }
213
2.29k
  return specs.GetSize() - initial_count;
214
2.29k
}