brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · 85979a3 Raw
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