summaryrefslogtreecommitdiff
path: root/lldb/tools/yaml2macho-core/yaml2macho.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/tools/yaml2macho-core/yaml2macho.cpp')
-rw-r--r--lldb/tools/yaml2macho-core/yaml2macho.cpp250
1 files changed, 250 insertions, 0 deletions
diff --git a/lldb/tools/yaml2macho-core/yaml2macho.cpp b/lldb/tools/yaml2macho-core/yaml2macho.cpp
new file mode 100644
index 000000000000..85979a37d167
--- /dev/null
+++ b/lldb/tools/yaml2macho-core/yaml2macho.cpp
@@ -0,0 +1,250 @@
+//===-- main.cppp ---------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoreSpec.h"
+#include "LCNoteWriter.h"
+#include "MemoryWriter.h"
+#include "ThreadWriter.h"
+#include "Utility.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/CommandLine.h"
+#include <stdio.h>
+#include <string>
+#include <sys/stat.h>
+
+std::vector<std::string> get_fields_from_delimited_string(std::string str,
+ const char delim) {
+ std::vector<std::string> result;
+ std::string::size_type prev = std::string::npos;
+ std::string::size_type next = str.find(delim);
+ if (str.empty()) {
+ return result;
+ }
+ if (next == std::string::npos) {
+ result.push_back(str);
+ } else {
+ result.push_back(std::string(str, 0, next));
+ prev = next;
+ while ((next = str.find(delim, prev + 1)) != std::string::npos) {
+ result.push_back(std::string(str, prev + 1, next - prev - 1));
+ prev = next;
+ }
+ result.push_back(std::string(str, prev + 1));
+ }
+ return result;
+}
+
+llvm::cl::opt<std::string> InputFilename("i", llvm::cl::Required,
+ llvm::cl::desc("input yaml filename"),
+ llvm::cl::value_desc("input"));
+llvm::cl::opt<std::string>
+ OutputFilename("o", llvm::cl::Required,
+ llvm::cl::desc("output core filenames"),
+ llvm::cl::value_desc("output"));
+llvm::cl::list<std::string>
+ UUIDs("u", llvm::cl::desc("uuid of binary loaded at slide 0"),
+ llvm::cl::value_desc("uuid"));
+llvm::cl::list<std::string>
+ UUIDAndVAs("L", llvm::cl::desc("UUID,virtual-address-loaded-at"),
+ llvm::cl::value_desc("--uuid-and-load-addr"));
+llvm::cl::opt<int>
+ AddressableBitsOverride("A",
+ llvm::cl::desc("number of bits used in addressing"),
+ llvm::cl::value_desc("--address-bits"));
+
+int main(int argc, char **argv) {
+ llvm::cl::ParseCommandLineOptions(argc, argv);
+
+ if (InputFilename.empty() || OutputFilename.empty()) {
+ fprintf(stderr, "Missing input or outpur file.\n");
+ exit(1);
+ }
+
+ struct stat sb;
+
+ if (stat(InputFilename.c_str(), &sb) == -1) {
+ fprintf(stderr, "Unable to stat %s, exiting\n", InputFilename.c_str());
+ exit(1);
+ }
+
+ FILE *input = fopen(InputFilename.c_str(), "r");
+ if (!input) {
+ fprintf(stderr, "Unable to open %s, exiting\n", InputFilename.c_str());
+ exit(1);
+ }
+ auto file_corespec = std::make_unique<char[]>(sb.st_size);
+ if (fread(file_corespec.get(), sb.st_size, 1, input) != 1) {
+ fprintf(stderr, "Unable to read all of %s, exiting\n",
+ InputFilename.c_str());
+ exit(1);
+ }
+ CoreSpec spec = from_yaml(file_corespec.get(), sb.st_size);
+ fclose(input);
+
+ for (const std::string &uuid : UUIDs) {
+ Binary binary;
+ binary.uuid = uuid;
+ binary.value = 0;
+ binary.value_is_slide = true;
+ spec.binaries.push_back(binary);
+ }
+
+ for (const std::string &uuid_and_va : UUIDAndVAs) {
+ std::vector<std::string> parts =
+ get_fields_from_delimited_string(uuid_and_va, ',');
+
+ std::string uuid = parts[0];
+ uint64_t va = std::strtoull(parts[1].c_str(), nullptr, 16);
+ Binary binary;
+ binary.uuid = uuid;
+ binary.value = va;
+ binary.value_is_slide = false;
+ spec.binaries.push_back(binary);
+ }
+
+ if (AddressableBitsOverride) {
+ AddressableBits bits;
+ bits.lowmem_bits = bits.highmem_bits = AddressableBitsOverride;
+ spec.addressable_bits = bits;
+ }
+
+ // An array of load commands
+ std::vector<std::vector<uint8_t>> load_commands;
+
+ // An array of corefile contents (memory regions)
+ std::vector<uint8_t> payload;
+
+ // First add all the load commands / payload so we can figure out how large
+ // the load commands will be.
+
+ add_lc_threads(spec, load_commands);
+ for (size_t i = 0; i < spec.memory_regions.size(); i++) {
+ std::vector<uint8_t> segment_command_bytes;
+ create_lc_segment_cmd(spec, segment_command_bytes, spec.memory_regions[i],
+ 0);
+ load_commands.push_back(segment_command_bytes);
+ }
+
+ if (spec.binaries.size() > 0)
+ for (const Binary &binary : spec.binaries) {
+ std::vector<uint8_t> segment_command_bytes;
+ std::vector<uint8_t> payload_bytes;
+ create_lc_note_binary_load_cmd(spec, segment_command_bytes, binary,
+ payload_bytes, 0);
+ load_commands.push_back(segment_command_bytes);
+ }
+ if (spec.addressable_bits) {
+ std::vector<uint8_t> segment_command_bytes;
+ std::vector<uint8_t> payload_bytes;
+ create_lc_note_addressable_bits(spec, segment_command_bytes,
+ *spec.addressable_bits, payload_bytes, 0);
+ load_commands.push_back(segment_command_bytes);
+ }
+
+ off_t size_of_load_commands = 0;
+ for (const auto &lc : load_commands)
+ size_of_load_commands += lc.size();
+
+ off_t header_and_load_cmd_room =
+ sizeof(llvm::MachO::mach_header_64) + size_of_load_commands;
+ off_t initial_payload_fileoff = header_and_load_cmd_room;
+ initial_payload_fileoff = (initial_payload_fileoff + 4096 - 1) & ~(4096 - 1);
+ off_t payload_fileoff = initial_payload_fileoff;
+
+ // Erase the load commands / payload now that we know how much space is
+ // needed, redo it with real values.
+ load_commands.clear();
+ payload.clear();
+
+ add_lc_threads(spec, load_commands);
+ for (size_t i = 0; i < spec.memory_regions.size(); i++) {
+ std::vector<uint8_t> segment_command_bytes;
+ create_lc_segment_cmd(spec, segment_command_bytes, spec.memory_regions[i],
+ payload_fileoff);
+ load_commands.push_back(segment_command_bytes);
+ payload_fileoff += spec.memory_regions[i].size;
+ payload_fileoff = (payload_fileoff + 4096 - 1) & ~(4096 - 1);
+ }
+
+ off_t payload_fileoff_before_lcnotes = payload_fileoff;
+ std::vector<uint8_t> lc_note_payload_bytes;
+ if (spec.binaries.size() > 0)
+ for (const Binary &binary : spec.binaries) {
+ std::vector<uint8_t> segment_command_bytes;
+ std::vector<uint8_t> payload_bytes;
+ create_lc_note_binary_load_cmd(spec, segment_command_bytes, binary,
+ lc_note_payload_bytes, payload_fileoff);
+ payload_fileoff =
+ payload_fileoff_before_lcnotes + lc_note_payload_bytes.size();
+ load_commands.push_back(segment_command_bytes);
+ }
+ if (spec.addressable_bits) {
+ std::vector<uint8_t> segment_command_bytes;
+ std::vector<uint8_t> payload_bytes;
+ create_lc_note_addressable_bits(spec, segment_command_bytes,
+ *spec.addressable_bits,
+ lc_note_payload_bytes, payload_fileoff);
+ payload_fileoff =
+ payload_fileoff_before_lcnotes + lc_note_payload_bytes.size();
+ load_commands.push_back(segment_command_bytes);
+ }
+
+ // Realign our payload offset if we added any LC_NOTEs.
+ if (lc_note_payload_bytes.size() > 0)
+ payload_fileoff = (payload_fileoff + 4096 - 1) & ~(4096 - 1);
+
+ FILE *f = fopen(OutputFilename.c_str(), "wb");
+ if (f == nullptr) {
+ fprintf(stderr, "Unable to open file %s for writing\n",
+ OutputFilename.c_str());
+ exit(1);
+ }
+
+ std::vector<uint8_t> mh;
+ // Write the fields of a mach_header_64 struct
+ if (spec.wordsize == 8)
+ add_uint32(mh, llvm::MachO::MH_MAGIC_64); // magic
+ else
+ add_uint32(mh, llvm::MachO::MH_MAGIC); // magic
+ add_uint32(mh, spec.cputype); // cputype
+ add_uint32(mh, spec.cpusubtype); // cpusubtype
+ add_uint32(mh, llvm::MachO::MH_CORE); // filetype
+ add_uint32(mh, load_commands.size()); // ncmds
+ add_uint32(mh, size_of_load_commands); // sizeofcmds
+ add_uint32(mh, 0); // flags
+ if (spec.wordsize == 8)
+ add_uint32(mh, 0); // reserved
+
+ fwrite(mh.data(), mh.size(), 1, f);
+
+ for (const auto &lc : load_commands)
+ fwrite(lc.data(), lc.size(), 1, f);
+
+ // Reset the payload offset back to the first one.
+ payload_fileoff = initial_payload_fileoff;
+ if (spec.memory_regions.size() > 0) {
+ for (size_t i = 0; i < spec.memory_regions.size(); i++) {
+ std::vector<uint8_t> bytes;
+ create_memory_bytes(spec, spec.memory_regions[i], bytes);
+ fseek(f, payload_fileoff, SEEK_SET);
+ fwrite(bytes.data(), bytes.size(), 1, f);
+
+ payload_fileoff += bytes.size();
+ payload_fileoff = (payload_fileoff + 4096 - 1) & ~(4096 - 1);
+ }
+ }
+
+ if (lc_note_payload_bytes.size() > 0) {
+ fseek(f, payload_fileoff, SEEK_SET);
+ fwrite(lc_note_payload_bytes.data(), lc_note_payload_bytes.size(), 1, f);
+ payload_fileoff += lc_note_payload_bytes.size();
+ payload_fileoff = (payload_fileoff + 4096 - 1) & ~(4096 - 1);
+ }
+
+ fclose(f);
+}