[lldb][MachO] MachO corefile support for riscv32 binaries (#137092)
Add support for reading a macho corefile with CPU_TYPE_RISCV and the riscv32 general purpose register file. I added code for the floating point and exception registers too, but haven't exercised this. If we start putting the full CSR register bank in a riscv corefile, it'll be in separate 4k byte chunks, but I don't have a corefile to test against that so I haven't written the code to read it. The RegisterContextDarwin_riscv32 is copied & in the style of the other RegisterContextDarwin classes; it's not the first choice I would make for representing this, but it wasn't worth changing for this cputype. rdar://145014653
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextDarwin_riscv32.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
@@ -769,6 +770,147 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
class RegisterContextDarwin_riscv32_Mach
|
||||
: public RegisterContextDarwin_riscv32 {
|
||||
public:
|
||||
RegisterContextDarwin_riscv32_Mach(lldb_private::Thread &thread,
|
||||
const DataExtractor &data)
|
||||
: RegisterContextDarwin_riscv32(thread, 0) {
|
||||
SetRegisterDataFrom_LC_THREAD(data);
|
||||
}
|
||||
|
||||
void InvalidateAllRegisters() override {
|
||||
// Do nothing... registers are always valid...
|
||||
}
|
||||
|
||||
void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
|
||||
lldb::offset_t offset = 0;
|
||||
SetError(GPRRegSet, Read, -1);
|
||||
SetError(FPURegSet, Read, -1);
|
||||
SetError(EXCRegSet, Read, -1);
|
||||
SetError(CSRRegSet, Read, -1);
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
int flavor = data.GetU32(&offset);
|
||||
uint32_t count = data.GetU32(&offset);
|
||||
lldb::offset_t next_thread_state = offset + (count * 4);
|
||||
switch (flavor) {
|
||||
case GPRRegSet:
|
||||
// x0-x31 + pc
|
||||
if (count >= 32) {
|
||||
for (uint32_t i = 0; i < 32; ++i)
|
||||
((uint32_t *)&gpr.x0)[i] = data.GetU32(&offset);
|
||||
gpr.pc = data.GetU32(&offset);
|
||||
SetError(GPRRegSet, Read, 0);
|
||||
}
|
||||
offset = next_thread_state;
|
||||
break;
|
||||
case FPURegSet: {
|
||||
// f0-f31 + fcsr
|
||||
if (count >= 32) {
|
||||
for (uint32_t i = 0; i < 32; ++i)
|
||||
((uint32_t *)&fpr.f0)[i] = data.GetU32(&offset);
|
||||
fpr.fcsr = data.GetU32(&offset);
|
||||
SetError(FPURegSet, Read, 0);
|
||||
}
|
||||
}
|
||||
offset = next_thread_state;
|
||||
break;
|
||||
case EXCRegSet:
|
||||
if (count == 3) {
|
||||
exc.exception = data.GetU32(&offset);
|
||||
exc.fsr = data.GetU32(&offset);
|
||||
exc.far = data.GetU32(&offset);
|
||||
SetError(EXCRegSet, Read, 0);
|
||||
}
|
||||
offset = next_thread_state;
|
||||
break;
|
||||
default:
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool Create_LC_THREAD(Thread *thread, Stream &data) {
|
||||
RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
|
||||
if (reg_ctx_sp) {
|
||||
RegisterContext *reg_ctx = reg_ctx_sp.get();
|
||||
|
||||
data.PutHex32(GPRRegSet); // Flavor
|
||||
data.PutHex32(GPRWordCount);
|
||||
PrintRegisterValue(reg_ctx, "x0", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x1", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x2", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x3", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x4", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x5", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x6", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x7", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x8", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x9", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x10", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x11", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x12", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x13", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x14", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x15", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x16", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x17", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x18", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x19", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x20", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x21", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x22", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x23", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x24", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x25", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x26", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x27", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x28", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x29", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x30", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "x31", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "pc", nullptr, 4, data);
|
||||
data.PutHex32(0); // uint32_t pad at the end
|
||||
|
||||
// Write out the EXC registers
|
||||
data.PutHex32(EXCRegSet);
|
||||
data.PutHex32(EXCWordCount);
|
||||
PrintRegisterValue(reg_ctx, "exception", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "fsr", nullptr, 4, data);
|
||||
PrintRegisterValue(reg_ctx, "far", nullptr, 4, data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; }
|
||||
|
||||
int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; }
|
||||
|
||||
int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; }
|
||||
|
||||
int DoReadCSR(lldb::tid_t tid, int flavor, CSR &csr) override { return -1; }
|
||||
|
||||
int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DoWriteCSR(lldb::tid_t tid, int flavor, const CSR &csr) override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
static uint32_t MachHeaderSizeFromMagic(uint32_t magic) {
|
||||
switch (magic) {
|
||||
case MH_MAGIC:
|
||||
@@ -5827,6 +5969,11 @@ ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx,
|
||||
reg_ctx_sp =
|
||||
std::make_shared<RegisterContextDarwin_x86_64_Mach>(thread, data);
|
||||
break;
|
||||
|
||||
case llvm::MachO::CPU_TYPE_RISCV:
|
||||
reg_ctx_sp =
|
||||
std::make_shared<RegisterContextDarwin_riscv32_Mach>(thread, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6695,6 +6842,11 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
|
||||
RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD(
|
||||
thread_sp.get(), LC_THREAD_datas[thread_idx]);
|
||||
break;
|
||||
|
||||
case llvm::MachO::CPU_TYPE_RISCV:
|
||||
RegisterContextDarwin_riscv32_Mach::Create_LC_THREAD(
|
||||
thread_sp.get(), LC_THREAD_datas[thread_idx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ add_lldb_library(lldbPluginProcessUtility
|
||||
RegisterContextDarwin_arm.cpp
|
||||
RegisterContextDarwin_arm64.cpp
|
||||
RegisterContextDarwin_i386.cpp
|
||||
RegisterContextDarwin_riscv32.cpp
|
||||
RegisterContextDarwin_x86_64.cpp
|
||||
RegisterContextDummy.cpp
|
||||
RegisterContextFreeBSD_i386.cpp
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,260 @@
|
||||
//===-- RegisterContextDarwin_riscv32.h -------------------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_RISCV32_H
|
||||
#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_RISCV32_H
|
||||
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
class RegisterContextDarwin_riscv32 : public lldb_private::RegisterContext {
|
||||
public:
|
||||
RegisterContextDarwin_riscv32(lldb_private::Thread &thread,
|
||||
uint32_t concrete_frame_idx);
|
||||
|
||||
~RegisterContextDarwin_riscv32() override;
|
||||
|
||||
void InvalidateAllRegisters() override;
|
||||
|
||||
size_t GetRegisterCount() override;
|
||||
|
||||
const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
|
||||
|
||||
size_t GetRegisterSetCount() override;
|
||||
|
||||
const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
|
||||
|
||||
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
|
||||
lldb_private::RegisterValue &value) override;
|
||||
|
||||
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
|
||||
const lldb_private::RegisterValue &value) override;
|
||||
|
||||
bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
|
||||
|
||||
bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
|
||||
|
||||
uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
|
||||
uint32_t num) override;
|
||||
|
||||
struct GPR {
|
||||
uint32_t x0;
|
||||
uint32_t x1;
|
||||
uint32_t x2;
|
||||
uint32_t x3;
|
||||
uint32_t x4;
|
||||
uint32_t x5;
|
||||
uint32_t x6;
|
||||
uint32_t x7;
|
||||
uint32_t x8;
|
||||
uint32_t x9;
|
||||
uint32_t x10;
|
||||
uint32_t x11;
|
||||
uint32_t x12;
|
||||
uint32_t x13;
|
||||
uint32_t x14;
|
||||
uint32_t x15;
|
||||
uint32_t x16;
|
||||
uint32_t x17;
|
||||
uint32_t x18;
|
||||
uint32_t x19;
|
||||
uint32_t x20;
|
||||
uint32_t x21;
|
||||
uint32_t x22;
|
||||
uint32_t x23;
|
||||
uint32_t x24;
|
||||
uint32_t x25;
|
||||
uint32_t x26;
|
||||
uint32_t x27;
|
||||
uint32_t x28;
|
||||
uint32_t x29;
|
||||
uint32_t x30;
|
||||
uint32_t x31;
|
||||
uint32_t pc;
|
||||
};
|
||||
|
||||
struct FPU {
|
||||
uint32_t f0;
|
||||
uint32_t f1;
|
||||
uint32_t f2;
|
||||
uint32_t f3;
|
||||
uint32_t f4;
|
||||
uint32_t f5;
|
||||
uint32_t f6;
|
||||
uint32_t f7;
|
||||
uint32_t f8;
|
||||
uint32_t f9;
|
||||
uint32_t f10;
|
||||
uint32_t f11;
|
||||
uint32_t f12;
|
||||
uint32_t f13;
|
||||
uint32_t f14;
|
||||
uint32_t f15;
|
||||
uint32_t f16;
|
||||
uint32_t f17;
|
||||
uint32_t f18;
|
||||
uint32_t f19;
|
||||
uint32_t f20;
|
||||
uint32_t f21;
|
||||
uint32_t f22;
|
||||
uint32_t f23;
|
||||
uint32_t f24;
|
||||
uint32_t f25;
|
||||
uint32_t f26;
|
||||
uint32_t f27;
|
||||
uint32_t f28;
|
||||
uint32_t f29;
|
||||
uint32_t f30;
|
||||
uint32_t f31;
|
||||
uint32_t fcsr;
|
||||
};
|
||||
|
||||
struct EXC {
|
||||
uint32_t exception;
|
||||
uint32_t fsr;
|
||||
uint32_t far;
|
||||
};
|
||||
|
||||
struct CSR {
|
||||
uint32_t csr[1024];
|
||||
};
|
||||
|
||||
protected:
|
||||
enum {
|
||||
GPRRegSet = 2, // RV32_THREAD_STATE
|
||||
EXCRegSet = 3, // RV32_EXCEPTION_STATE
|
||||
FPURegSet = 4, // RV_FP32_STATE
|
||||
CSRRegSet1 = 6, // RV_CSR_STATE1
|
||||
CSRRegSet2 = 7, // RV_CSR_STATE2
|
||||
CSRRegSet3 = 8, // RV_CSR_STATE3
|
||||
CSRRegSet4 = 9, // RV_CSR_STATE4
|
||||
CSRRegSet = 10 // full 16kbyte CSR reg bank
|
||||
};
|
||||
|
||||
enum {
|
||||
GPRWordCount = sizeof(GPR) / sizeof(uint32_t),
|
||||
FPUWordCount = sizeof(FPU) / sizeof(uint32_t),
|
||||
EXCWordCount = sizeof(EXC) / sizeof(uint32_t),
|
||||
CSRWordCount = sizeof(CSR) / sizeof(uint32_t)
|
||||
};
|
||||
|
||||
enum { Read = 0, Write = 1, kNumErrors = 2 };
|
||||
|
||||
GPR gpr;
|
||||
FPU fpr;
|
||||
EXC exc;
|
||||
CSR csr;
|
||||
int gpr_errs[2]; // Read/Write errors
|
||||
int fpr_errs[2]; // Read/Write errors
|
||||
int exc_errs[2]; // Read/Write errors
|
||||
int csr_errs[2]; // Read/Write errors
|
||||
|
||||
void InvalidateAllRegisterStates() {
|
||||
SetError(GPRRegSet, Read, -1);
|
||||
SetError(FPURegSet, Read, -1);
|
||||
SetError(EXCRegSet, Read, -1);
|
||||
SetError(CSRRegSet, Read, -1);
|
||||
}
|
||||
|
||||
int GetError(int flavor, uint32_t err_idx) const {
|
||||
if (err_idx < kNumErrors) {
|
||||
switch (flavor) {
|
||||
// When getting all errors, just OR all values together to see if
|
||||
// we got any kind of error.
|
||||
case GPRRegSet:
|
||||
return gpr_errs[err_idx];
|
||||
case FPURegSet:
|
||||
return fpr_errs[err_idx];
|
||||
case EXCRegSet:
|
||||
return exc_errs[err_idx];
|
||||
case CSRRegSet:
|
||||
return csr_errs[err_idx];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SetError(int flavor, uint32_t err_idx, int err) {
|
||||
if (err_idx < kNumErrors) {
|
||||
switch (flavor) {
|
||||
case GPRRegSet:
|
||||
gpr_errs[err_idx] = err;
|
||||
return true;
|
||||
|
||||
case FPURegSet:
|
||||
fpr_errs[err_idx] = err;
|
||||
return true;
|
||||
|
||||
case EXCRegSet:
|
||||
exc_errs[err_idx] = err;
|
||||
return true;
|
||||
|
||||
case CSRRegSet:
|
||||
csr_errs[err_idx] = err;
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RegisterSetIsCached(int set) const { return GetError(set, Read) == 0; }
|
||||
|
||||
void LogGPR(lldb_private::Log *log, const char *title);
|
||||
|
||||
int ReadGPR(bool force);
|
||||
|
||||
int ReadFPU(bool force);
|
||||
|
||||
int ReadEXC(bool force);
|
||||
|
||||
int ReadCSR(bool force);
|
||||
|
||||
int WriteGPR();
|
||||
|
||||
int WriteFPU();
|
||||
|
||||
int WriteEXC();
|
||||
|
||||
int WriteCSR();
|
||||
|
||||
// Subclasses override these to do the actual reading.
|
||||
virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) = 0;
|
||||
|
||||
virtual int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpr) = 0;
|
||||
|
||||
virtual int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) = 0;
|
||||
|
||||
virtual int DoReadCSR(lldb::tid_t tid, int flavor, CSR &exc) = 0;
|
||||
|
||||
virtual int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
|
||||
|
||||
virtual int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpr) = 0;
|
||||
|
||||
virtual int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) = 0;
|
||||
|
||||
virtual int DoWriteCSR(lldb::tid_t tid, int flavor, const CSR &exc) = 0;
|
||||
|
||||
int ReadRegisterSet(uint32_t set, bool force);
|
||||
|
||||
int WriteRegisterSet(uint32_t set);
|
||||
|
||||
static uint32_t GetRegisterNumber(uint32_t reg_kind, uint32_t reg_num);
|
||||
|
||||
static int GetSetForNativeRegNum(int reg_num);
|
||||
|
||||
static size_t GetRegisterInfosCount();
|
||||
|
||||
static const lldb_private::RegisterInfo *GetRegisterInfos();
|
||||
};
|
||||
|
||||
#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_RISCV32_H
|
||||
7
lldb/test/API/macosx/riscv32-corefile/Makefile
Normal file
7
lldb/test/API/macosx/riscv32-corefile/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
MAKE_DSYM := NO
|
||||
CXX_SOURCES := create-empty-riscv-corefile.cpp
|
||||
EXE := create-empty-riscv-corefile
|
||||
|
||||
all: create-empty-riscv-corefile
|
||||
|
||||
include Makefile.rules
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Test that all of the GPR registers are read correctly from a riscv32 corefile."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class TestRV32MachOCorefile(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
@skipUnlessDarwin
|
||||
def test_riscv32_gpr_corefile_registers(self):
|
||||
self.build()
|
||||
create_corefile = self.getBuildArtifact("create-empty-riscv-corefile")
|
||||
corefile = self.getBuildArtifact("core")
|
||||
call(create_corefile + " " + corefile, shell=True)
|
||||
|
||||
target = self.dbg.CreateTarget("")
|
||||
process = target.LoadCore(corefile)
|
||||
|
||||
process = target.GetProcess()
|
||||
self.assertEqual(process.GetNumThreads(), 1)
|
||||
|
||||
thread = process.GetThreadAtIndex(0)
|
||||
self.assertEqual(thread.GetNumFrames(), 1)
|
||||
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
gpr_regs = frame.registers.GetValueAtIndex(0)
|
||||
|
||||
self.assertEqual(gpr_regs.GetName(), "General Purpose Registers")
|
||||
self.assertEqual(gpr_regs.GetNumChildren(), 33)
|
||||
regnames = [
|
||||
"zero",
|
||||
"ra",
|
||||
"sp",
|
||||
"gp",
|
||||
"tp",
|
||||
"t0",
|
||||
"t1",
|
||||
"t2",
|
||||
"fp",
|
||||
"s1",
|
||||
"a0",
|
||||
"a1",
|
||||
"a2",
|
||||
"a3",
|
||||
"a4",
|
||||
"a5",
|
||||
"a6",
|
||||
"a7",
|
||||
"s2",
|
||||
"s3",
|
||||
"s4",
|
||||
"s5",
|
||||
"s6",
|
||||
"s7",
|
||||
"s8",
|
||||
"s9",
|
||||
"s10",
|
||||
"s11",
|
||||
"t3",
|
||||
"t4",
|
||||
"t5",
|
||||
"t6",
|
||||
"pc",
|
||||
]
|
||||
|
||||
idx = 0
|
||||
while idx < len(regnames):
|
||||
self.assertEqual(gpr_regs.GetChildAtIndex(idx).GetName(), regnames[idx])
|
||||
idx = idx + 1
|
||||
|
||||
idx = 0
|
||||
while idx < len(regnames):
|
||||
val = idx | (idx << 8) | (idx << 16) | (idx << 24)
|
||||
self.assertEqual(gpr_regs.GetChildAtIndex(idx).GetValueAsUnsigned(), val)
|
||||
idx = idx + 1
|
||||
@@ -0,0 +1,116 @@
|
||||
#include <inttypes.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach/thread_status.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sys/errno.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <vector>
|
||||
|
||||
#define CPU_TYPE_RISCV 24
|
||||
#define CPU_SUBTYPE_RISCV_ALL 0
|
||||
#define RV32_THREAD_STATE 2
|
||||
// x0-x31 + pc, all 32-bit
|
||||
#define RV32_THREAD_STATE_COUNT 33
|
||||
|
||||
union uint32_buf {
|
||||
uint8_t bytebuf[4];
|
||||
uint32_t val;
|
||||
};
|
||||
|
||||
union uint64_buf {
|
||||
uint8_t bytebuf[8];
|
||||
uint64_t val;
|
||||
};
|
||||
|
||||
void add_uint64(std::vector<uint8_t> &buf, uint64_t val) {
|
||||
uint64_buf conv;
|
||||
conv.val = val;
|
||||
for (int i = 0; i < 8; i++)
|
||||
buf.push_back(conv.bytebuf[i]);
|
||||
}
|
||||
|
||||
void add_uint32(std::vector<uint8_t> &buf, uint32_t val) {
|
||||
uint32_buf conv;
|
||||
conv.val = val;
|
||||
for (int i = 0; i < 4; i++)
|
||||
buf.push_back(conv.bytebuf[i]);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> lc_thread_load_command() {
|
||||
std::vector<uint8_t> data;
|
||||
add_uint32(data, LC_THREAD); // thread_command.cmd
|
||||
add_uint32(data, 4 + 4 + 4 + 4 +
|
||||
(RV32_THREAD_STATE_COUNT * 4)); // thread_command.cmdsize
|
||||
add_uint32(data, RV32_THREAD_STATE); // thread_command.flavor
|
||||
add_uint32(data, RV32_THREAD_STATE_COUNT); // thread_command.count
|
||||
for (int i = 0; i < RV32_THREAD_STATE_COUNT; i++) {
|
||||
add_uint32(data, i | (i << 8) | (i << 16) | (i << 24));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr,
|
||||
"usage: create-empty-riscv-corefile output-corefile-name\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpu_type_t cputype = CPU_TYPE_RISCV;
|
||||
cpu_subtype_t cpusubtype = CPU_SUBTYPE_RISCV_ALL;
|
||||
|
||||
// An array of load commands (in the form of byte arrays)
|
||||
std::vector<std::vector<uint8_t>> load_commands;
|
||||
|
||||
// An array of corefile contents (page data, lc_note data, etc)
|
||||
std::vector<uint8_t> payload;
|
||||
|
||||
// First add all the load commands / payload so we can figure out how large
|
||||
// the load commands will actually be.
|
||||
load_commands.push_back(lc_thread_load_command());
|
||||
|
||||
int size_of_load_commands = 0;
|
||||
for (const auto &lc : load_commands)
|
||||
size_of_load_commands += lc.size();
|
||||
|
||||
int header_and_load_cmd_room =
|
||||
sizeof(struct mach_header_64) + size_of_load_commands;
|
||||
|
||||
// Erase the load commands / payload now that we know how much space is
|
||||
// needed, redo it.
|
||||
load_commands.clear();
|
||||
payload.clear();
|
||||
|
||||
load_commands.push_back(lc_thread_load_command());
|
||||
|
||||
struct mach_header mh;
|
||||
mh.magic = MH_MAGIC;
|
||||
mh.cputype = cputype;
|
||||
|
||||
mh.cpusubtype = cpusubtype;
|
||||
mh.filetype = MH_CORE;
|
||||
mh.ncmds = load_commands.size();
|
||||
mh.sizeofcmds = size_of_load_commands;
|
||||
mh.flags = 0;
|
||||
|
||||
FILE *f = fopen(argv[1], "w");
|
||||
|
||||
if (f == nullptr) {
|
||||
fprintf(stderr, "Unable to open file %s for writing\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fwrite(&mh, sizeof(struct mach_header), 1, f);
|
||||
|
||||
for (const auto &lc : load_commands)
|
||||
fwrite(lc.data(), lc.size(), 1, f);
|
||||
|
||||
fseek(f, header_and_load_cmd_room, SEEK_SET);
|
||||
|
||||
fwrite(payload.data(), payload.size(), 1, f);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
Reference in New Issue
Block a user