251 lines · cpp
1//===-- main.cppp ---------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "CoreSpec.h"10#include "LCNoteWriter.h"11#include "MemoryWriter.h"12#include "ThreadWriter.h"13#include "Utility.h"14#include "llvm/BinaryFormat/MachO.h"15#include "llvm/Support/CommandLine.h"16#include <stdio.h>17#include <string>18#include <sys/stat.h>19 20std::vector<std::string> get_fields_from_delimited_string(std::string str,21 const char delim) {22 std::vector<std::string> result;23 std::string::size_type prev = std::string::npos;24 std::string::size_type next = str.find(delim);25 if (str.empty()) {26 return result;27 }28 if (next == std::string::npos) {29 result.push_back(str);30 } else {31 result.push_back(std::string(str, 0, next));32 prev = next;33 while ((next = str.find(delim, prev + 1)) != std::string::npos) {34 result.push_back(std::string(str, prev + 1, next - prev - 1));35 prev = next;36 }37 result.push_back(std::string(str, prev + 1));38 }39 return result;40}41 42llvm::cl::opt<std::string> InputFilename("i", llvm::cl::Required,43 llvm::cl::desc("input yaml filename"),44 llvm::cl::value_desc("input"));45llvm::cl::opt<std::string>46 OutputFilename("o", llvm::cl::Required,47 llvm::cl::desc("output core filenames"),48 llvm::cl::value_desc("output"));49llvm::cl::list<std::string>50 UUIDs("u", llvm::cl::desc("uuid of binary loaded at slide 0"),51 llvm::cl::value_desc("uuid"));52llvm::cl::list<std::string>53 UUIDAndVAs("L", llvm::cl::desc("UUID,virtual-address-loaded-at"),54 llvm::cl::value_desc("--uuid-and-load-addr"));55llvm::cl::opt<int>56 AddressableBitsOverride("A",57 llvm::cl::desc("number of bits used in addressing"),58 llvm::cl::value_desc("--address-bits"));59 60int main(int argc, char **argv) {61 llvm::cl::ParseCommandLineOptions(argc, argv);62 63 if (InputFilename.empty() || OutputFilename.empty()) {64 fprintf(stderr, "Missing input or outpur file.\n");65 exit(1);66 }67 68 struct stat sb;69 70 if (stat(InputFilename.c_str(), &sb) == -1) {71 fprintf(stderr, "Unable to stat %s, exiting\n", InputFilename.c_str());72 exit(1);73 }74 75 FILE *input = fopen(InputFilename.c_str(), "r");76 if (!input) {77 fprintf(stderr, "Unable to open %s, exiting\n", InputFilename.c_str());78 exit(1);79 }80 auto file_corespec = std::make_unique<char[]>(sb.st_size);81 if (fread(file_corespec.get(), sb.st_size, 1, input) != 1) {82 fprintf(stderr, "Unable to read all of %s, exiting\n",83 InputFilename.c_str());84 exit(1);85 }86 CoreSpec spec = from_yaml(file_corespec.get(), sb.st_size);87 fclose(input);88 89 for (const std::string &uuid : UUIDs) {90 Binary binary;91 binary.uuid = uuid;92 binary.value = 0;93 binary.value_is_slide = true;94 spec.binaries.push_back(binary);95 }96 97 for (const std::string &uuid_and_va : UUIDAndVAs) {98 std::vector<std::string> parts =99 get_fields_from_delimited_string(uuid_and_va, ',');100 101 std::string uuid = parts[0];102 uint64_t va = std::strtoull(parts[1].c_str(), nullptr, 16);103 Binary binary;104 binary.uuid = uuid;105 binary.value = va;106 binary.value_is_slide = false;107 spec.binaries.push_back(binary);108 }109 110 if (AddressableBitsOverride) {111 AddressableBits bits;112 bits.lowmem_bits = bits.highmem_bits = AddressableBitsOverride;113 spec.addressable_bits = bits;114 }115 116 // An array of load commands117 std::vector<std::vector<uint8_t>> load_commands;118 119 // An array of corefile contents (memory regions)120 std::vector<uint8_t> payload;121 122 // First add all the load commands / payload so we can figure out how large123 // the load commands will be.124 125 add_lc_threads(spec, load_commands);126 for (size_t i = 0; i < spec.memory_regions.size(); i++) {127 std::vector<uint8_t> segment_command_bytes;128 create_lc_segment_cmd(spec, segment_command_bytes, spec.memory_regions[i],129 0);130 load_commands.push_back(segment_command_bytes);131 }132 133 if (spec.binaries.size() > 0)134 for (const Binary &binary : spec.binaries) {135 std::vector<uint8_t> segment_command_bytes;136 std::vector<uint8_t> payload_bytes;137 create_lc_note_binary_load_cmd(spec, segment_command_bytes, binary,138 payload_bytes, 0);139 load_commands.push_back(segment_command_bytes);140 }141 if (spec.addressable_bits) {142 std::vector<uint8_t> segment_command_bytes;143 std::vector<uint8_t> payload_bytes;144 create_lc_note_addressable_bits(spec, segment_command_bytes,145 *spec.addressable_bits, payload_bytes, 0);146 load_commands.push_back(segment_command_bytes);147 }148 149 off_t size_of_load_commands = 0;150 for (const auto &lc : load_commands)151 size_of_load_commands += lc.size();152 153 off_t header_and_load_cmd_room =154 sizeof(llvm::MachO::mach_header_64) + size_of_load_commands;155 off_t initial_payload_fileoff = header_and_load_cmd_room;156 initial_payload_fileoff = (initial_payload_fileoff + 4096 - 1) & ~(4096 - 1);157 off_t payload_fileoff = initial_payload_fileoff;158 159 // Erase the load commands / payload now that we know how much space is160 // needed, redo it with real values.161 load_commands.clear();162 payload.clear();163 164 add_lc_threads(spec, load_commands);165 for (size_t i = 0; i < spec.memory_regions.size(); i++) {166 std::vector<uint8_t> segment_command_bytes;167 create_lc_segment_cmd(spec, segment_command_bytes, spec.memory_regions[i],168 payload_fileoff);169 load_commands.push_back(segment_command_bytes);170 payload_fileoff += spec.memory_regions[i].size;171 payload_fileoff = (payload_fileoff + 4096 - 1) & ~(4096 - 1);172 }173 174 off_t payload_fileoff_before_lcnotes = payload_fileoff;175 std::vector<uint8_t> lc_note_payload_bytes;176 if (spec.binaries.size() > 0)177 for (const Binary &binary : spec.binaries) {178 std::vector<uint8_t> segment_command_bytes;179 std::vector<uint8_t> payload_bytes;180 create_lc_note_binary_load_cmd(spec, segment_command_bytes, binary,181 lc_note_payload_bytes, payload_fileoff);182 payload_fileoff =183 payload_fileoff_before_lcnotes + lc_note_payload_bytes.size();184 load_commands.push_back(segment_command_bytes);185 }186 if (spec.addressable_bits) {187 std::vector<uint8_t> segment_command_bytes;188 std::vector<uint8_t> payload_bytes;189 create_lc_note_addressable_bits(spec, segment_command_bytes,190 *spec.addressable_bits,191 lc_note_payload_bytes, payload_fileoff);192 payload_fileoff =193 payload_fileoff_before_lcnotes + lc_note_payload_bytes.size();194 load_commands.push_back(segment_command_bytes);195 }196 197 // Realign our payload offset if we added any LC_NOTEs.198 if (lc_note_payload_bytes.size() > 0)199 payload_fileoff = (payload_fileoff + 4096 - 1) & ~(4096 - 1);200 201 FILE *f = fopen(OutputFilename.c_str(), "wb");202 if (f == nullptr) {203 fprintf(stderr, "Unable to open file %s for writing\n",204 OutputFilename.c_str());205 exit(1);206 }207 208 std::vector<uint8_t> mh;209 // Write the fields of a mach_header_64 struct210 if (spec.wordsize == 8)211 add_uint32(mh, llvm::MachO::MH_MAGIC_64); // magic212 else213 add_uint32(mh, llvm::MachO::MH_MAGIC); // magic214 add_uint32(mh, spec.cputype); // cputype215 add_uint32(mh, spec.cpusubtype); // cpusubtype216 add_uint32(mh, llvm::MachO::MH_CORE); // filetype217 add_uint32(mh, load_commands.size()); // ncmds218 add_uint32(mh, size_of_load_commands); // sizeofcmds219 add_uint32(mh, 0); // flags220 if (spec.wordsize == 8)221 add_uint32(mh, 0); // reserved222 223 fwrite(mh.data(), mh.size(), 1, f);224 225 for (const auto &lc : load_commands)226 fwrite(lc.data(), lc.size(), 1, f);227 228 // Reset the payload offset back to the first one.229 payload_fileoff = initial_payload_fileoff;230 if (spec.memory_regions.size() > 0) {231 for (size_t i = 0; i < spec.memory_regions.size(); i++) {232 std::vector<uint8_t> bytes;233 create_memory_bytes(spec, spec.memory_regions[i], bytes);234 fseek(f, payload_fileoff, SEEK_SET);235 fwrite(bytes.data(), bytes.size(), 1, f);236 237 payload_fileoff += bytes.size();238 payload_fileoff = (payload_fileoff + 4096 - 1) & ~(4096 - 1);239 }240 }241 242 if (lc_note_payload_bytes.size() > 0) {243 fseek(f, payload_fileoff, SEEK_SET);244 fwrite(lc_note_payload_bytes.data(), lc_note_payload_bytes.size(), 1, f);245 payload_fileoff += lc_note_payload_bytes.size();246 payload_fileoff = (payload_fileoff + 4096 - 1) & ~(4096 - 1);247 }248 249 fclose(f);250}251