diff options
Diffstat (limited to 'lldb/tools/yaml2macho-core/yaml2macho.cpp')
| -rw-r--r-- | lldb/tools/yaml2macho-core/yaml2macho.cpp | 250 |
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); +} |
