201 lines · cpp
1//===-- ThreadWriter.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "ThreadWriter.h"10#include "CoreSpec.h"11#include "Utility.h"12#include "llvm/BinaryFormat/MachO.h"13#include <algorithm>14#include <stdio.h>15 16#define ARM_THREAD_STATE 117#define ARM_THREAD_STATE_COUNT 1718#define ARM_EXCEPTION_STATE 319#define ARM_EXCEPTION_STATE_COUNT 320 21std::vector<RegisterNameAndValue>::const_iterator22find_by_name(std::vector<RegisterNameAndValue>::const_iterator first,23 std::vector<RegisterNameAndValue>::const_iterator last,24 const char *name) {25 for (; first != last; ++first)26 if (first->name == name)27 return first;28 return last;29}30 31void add_reg_value(CoreSpec &spec, std::vector<uint8_t> &buf,32 const std::vector<RegisterNameAndValue> ®isters,33 const char *regname, int regsize) {34 const auto it = find_by_name(registers.begin(), registers.end(), regname);35 if (it != registers.end()) {36 if (regsize == 8)37 add_uint64(buf, it->value);38 else39 add_uint32(buf, it->value);40 } else {41 if (regsize == 8)42 add_uint64(buf, 0);43 else44 add_uint32(buf, 0);45 }46}47 48void add_reg_value_32(CoreSpec &spec, std::vector<uint8_t> &buf,49 const std::vector<RegisterNameAndValue> ®isters,50 const char *regname) {51 add_reg_value(spec, buf, registers, regname, 4);52}53 54void add_reg_value_64(CoreSpec &spec, std::vector<uint8_t> &buf,55 const std::vector<RegisterNameAndValue> ®isters,56 const char *regname) {57 add_reg_value(spec, buf, registers, regname, 8);58}59 60void add_lc_threads_armv7(CoreSpec &spec,61 std::vector<std::vector<uint8_t>> &load_commands) {62 for (const Thread &th : spec.threads) {63 std::vector<uint8_t> lc;64 int size_of_all_flavors = 0;65 for (const RegisterSet &rs : th.regsets) {66 if (rs.flavor == RegisterFlavor::GPR)67 size_of_all_flavors += (ARM_THREAD_STATE_COUNT * 4);68 if (rs.flavor == RegisterFlavor::EXC)69 size_of_all_flavors += (ARM_EXCEPTION_STATE_COUNT * 4);70 }71 int cmdsize = 4 * 2; // cmd, cmdsize72 cmdsize += 4 * 2 * th.regsets.size(); // flavor, count (per register flavor)73 cmdsize += size_of_all_flavors; // size of all the register set data74 75 add_uint32(lc, llvm::MachO::LC_THREAD); // thread_command.cmd76 add_uint32(lc, cmdsize); // thread_command.cmdsize77 for (const RegisterSet &rs : th.regsets) {78 if (rs.flavor == RegisterFlavor::GPR) {79 add_uint32(lc, ARM_THREAD_STATE); // thread_command.flavor80 add_uint32(lc, ARM_THREAD_STATE_COUNT); // thread_command.count81 const char *names[] = {"r0", "r1", "r2", "r3", "r4", "r5",82 "r6", "r7", "r8", "r9", "r10", "r11",83 "r12", "sp", "lr", "pc", "cpsr", nullptr};84 for (int i = 0; names[i]; i++)85 add_reg_value_32(spec, lc, rs.registers, names[i]);86 }87 if (rs.flavor == RegisterFlavor::EXC) {88 add_uint32(lc, ARM_EXCEPTION_STATE); // thread_command.flavor89 add_uint32(lc, ARM_EXCEPTION_STATE_COUNT); // thread_command.count90 const char *names[] = {"far", "esr", "exception", nullptr};91 for (int i = 0; names[i]; i++)92 add_reg_value_32(spec, lc, rs.registers, names[i]);93 }94 }95 load_commands.push_back(lc);96 }97}98 99#define ARM_THREAD_STATE64 6100#define ARM_THREAD_STATE64_COUNT 68101#define ARM_EXCEPTION_STATE64 7102#define ARM_EXCEPTION_STATE64_COUNT 4103 104void add_lc_threads_arm64(CoreSpec &spec,105 std::vector<std::vector<uint8_t>> &load_commands) {106 for (const Thread &th : spec.threads) {107 std::vector<uint8_t> lc;108 int size_of_all_flavors = 0;109 for (const RegisterSet &rs : th.regsets) {110 if (rs.flavor == RegisterFlavor::GPR)111 size_of_all_flavors += (ARM_THREAD_STATE64_COUNT * 4);112 if (rs.flavor == RegisterFlavor::EXC)113 size_of_all_flavors += (ARM_EXCEPTION_STATE64_COUNT * 4);114 }115 int cmdsize = 4 * 2; // cmd, cmdsize116 cmdsize += 4 * 2 * th.regsets.size(); // flavor, count (per register flavor)117 cmdsize += size_of_all_flavors; // size of all the register set data118 119 add_uint32(lc, llvm::MachO::LC_THREAD); // thread_command.cmd120 add_uint32(lc, cmdsize); // thread_command.cmdsize121 122 for (const RegisterSet &rs : th.regsets) {123 if (rs.flavor == RegisterFlavor::GPR) {124 add_uint32(lc, ARM_THREAD_STATE64); // thread_command.flavor125 add_uint32(lc, ARM_THREAD_STATE64_COUNT); // thread_command.count126 const char *names[] = {"x0", "x1", "x2", "x3", "x4", "x5", "x6",127 "x7", "x8", "x9", "x10", "x11", "x12", "x13",128 "x14", "x15", "x16", "x17", "x18", "x19", "x20",129 "x21", "x22", "x23", "x24", "x25", "x26", "x27",130 "x28", "fp", "lr", "sp", "pc", nullptr};131 for (int i = 0; names[i]; i++)132 add_reg_value_64(spec, lc, rs.registers, names[i]);133 134 // cpsr is a 4-byte reg135 add_reg_value_32(spec, lc, rs.registers, "cpsr");136 // the 4 bytes of zeroes137 add_uint32(lc, 0);138 }139 if (rs.flavor == RegisterFlavor::EXC) {140 add_uint32(lc, ARM_EXCEPTION_STATE64); // thread_command.flavor141 add_uint32(lc,142 ARM_EXCEPTION_STATE64_COUNT); // thread_command.count143 add_reg_value_64(spec, lc, rs.registers, "far");144 add_reg_value_32(spec, lc, rs.registers, "esr");145 add_reg_value_32(spec, lc, rs.registers, "exception");146 }147 }148 load_commands.push_back(lc);149 }150}151 152#define RV32_THREAD_STATE 2153#define RV32_THREAD_STATE_COUNT 33154 155void add_lc_threads_riscv(CoreSpec &spec,156 std::vector<std::vector<uint8_t>> &load_commands) {157 for (const Thread &th : spec.threads) {158 std::vector<uint8_t> lc;159 int size_of_all_flavors = 0;160 for (const RegisterSet &rs : th.regsets) {161 if (rs.flavor == RegisterFlavor::GPR)162 size_of_all_flavors += (RV32_THREAD_STATE_COUNT * 4);163 }164 int cmdsize = 4 * 2; // cmd, cmdsize165 cmdsize += 4 * 2 * th.regsets.size(); // flavor, count (per register flavor)166 cmdsize += size_of_all_flavors; // size of all the register set data167 168 add_uint32(lc, llvm::MachO::LC_THREAD); // thread_command.cmd169 add_uint32(lc, cmdsize); // thread_command.cmdsize170 for (const RegisterSet &rs : th.regsets) {171 if (rs.flavor == RegisterFlavor::GPR) {172 add_uint32(lc, RV32_THREAD_STATE); // thread_command.flavor173 add_uint32(lc, RV32_THREAD_STATE_COUNT); // thread_command.count174 const char *names[] = {"zero", "ra", "sp", "gp", "tp", "t0", "t1",175 "t2", "fp", "s1", "a0", "a1", "a2", "a3",176 "a4", "a5", "a6", "a7", "s2", "s3", "s4",177 "s5", "s6", "s7", "s8", "s9", "s10", "s11",178 "t3", "t4", "t5", "t6", "pc", nullptr};179 for (int i = 0; names[i]; i++)180 add_reg_value_32(spec, lc, rs.registers, names[i]);181 }182 }183 load_commands.push_back(lc);184 }185}186 187void add_lc_threads(CoreSpec &spec,188 std::vector<std::vector<uint8_t>> &load_commands) {189 if (spec.cputype == llvm::MachO::CPU_TYPE_ARM)190 add_lc_threads_armv7(spec, load_commands);191 else if (spec.cputype == llvm::MachO::CPU_TYPE_ARM64)192 add_lc_threads_arm64(spec, load_commands);193 else if (spec.cputype == llvm::MachO::CPU_TYPE_RISCV)194 add_lc_threads_riscv(spec, load_commands);195 else {196 fprintf(stderr,197 "Unrecognized cputype, could not write LC_THREAD. Exiting.\n");198 exit(1);199 }200}201