feat: initial support
This commit is contained in:
parent
dd2feddfd6
commit
5ddf0b48be
13 changed files with 449 additions and 42 deletions
41
.gitignore
vendored
41
.gitignore
vendored
|
@ -1,4 +1,7 @@
|
||||||
|
.cache/
|
||||||
|
.vscode/
|
||||||
.direnv/
|
.direnv/
|
||||||
|
build/
|
||||||
.pre-commit-config.yaml
|
.pre-commit-config.yaml
|
||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/c++,c,cmake
|
# Created by https://www.toptal.com/developers/gitignore/api/c++,c,cmake
|
||||||
|
@ -95,3 +98,41 @@ _deps
|
||||||
*-prefix/
|
*-prefix/
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/c++,c,cmake
|
# End of https://www.toptal.com/developers/gitignore/api/c++,c,cmake
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/c++
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=c++
|
||||||
|
|
||||||
|
### C++ ###
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/c++
|
||||||
|
|
|
@ -6,4 +6,3 @@ set(CMAKE_C_STANDARD 17)
|
||||||
|
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
|
21
flake.lock
21
flake.lock
|
@ -105,6 +105,26 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nur-xin": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1714033851,
|
||||||
|
"narHash": "sha256-Mi7m3p9vmtNOdyD1hLse/tzxDuV3bwP0gKrmOBPiQ4c=",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"rev": "809554f41ac44acc4b1ec21473746c2af9993f2f",
|
||||||
|
"revCount": 149,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.xinyang.life/xin/nur.git"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.xinyang.life/xin/nur.git"
|
||||||
|
}
|
||||||
|
},
|
||||||
"pre-commit-hooks": {
|
"pre-commit-hooks": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
|
@ -133,6 +153,7 @@
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
|
"nur-xin": "nur-xin",
|
||||||
"pre-commit-hooks": "pre-commit-hooks"
|
"pre-commit-hooks": "pre-commit-hooks"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
14
flake.nix
14
flake.nix
|
@ -2,6 +2,10 @@
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
nur-xin = {
|
||||||
|
url = "git+https://git.xinyang.life/xin/nur.git";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
pre-commit-hooks = {
|
pre-commit-hooks = {
|
||||||
url = "github:cachix/pre-commit-hooks.nix";
|
url = "github:cachix/pre-commit-hooks.nix";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
@ -11,7 +15,13 @@
|
||||||
outputs = { self, ... }@inputs: with inputs;
|
outputs = { self, ... }@inputs: with inputs;
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs { inherit system; };
|
pkgs = import nixpkgs {
|
||||||
|
inherit system; overlays = [
|
||||||
|
(self: super: {
|
||||||
|
mini-gdbstub = nur-xin.legacyPackages.${system}.mini-gdbstub;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
checks = {
|
checks = {
|
||||||
|
@ -35,6 +45,8 @@
|
||||||
clang-tools
|
clang-tools
|
||||||
cmake
|
cmake
|
||||||
gdb
|
gdb
|
||||||
|
cli11
|
||||||
|
mini-gdbstub
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
#ifndef _DIFFTEST_API_H_
|
|
||||||
#define _DIFFTEST_API_H_
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
enum {
|
|
||||||
ACT_NONE,
|
|
||||||
ACT_BREAKPOINT,
|
|
||||||
ACT_WATCH,
|
|
||||||
ACT_RWATCH,
|
|
||||||
ACT_WWATCH,
|
|
||||||
ACT_SHUTDOWN
|
|
||||||
} reason;
|
|
||||||
size_t data;
|
|
||||||
} gdb_action_t;
|
|
||||||
|
|
||||||
typedef enum { BP_SOFTWARE = 0, BP_WRITE, BP_READ, BP_ACCESS } bp_type_t;
|
|
||||||
|
|
||||||
struct target_ops {
|
|
||||||
void (*cont)(void *args, gdb_action_t *res);
|
|
||||||
void (*stepi)(void *args, gdb_action_t *res);
|
|
||||||
int (*read_reg)(void *args, int regno, size_t *value);
|
|
||||||
int (*write_reg)(void *args, int regno, size_t value);
|
|
||||||
int (*read_mem)(void *args, size_t addr, size_t len, void *val);
|
|
||||||
int (*write_mem)(void *args, size_t addr, size_t len, void *val);
|
|
||||||
bool (*set_bp)(void *args, size_t addr, bp_type_t type);
|
|
||||||
bool (*del_bp)(void *args, size_t addr, bp_type_t type);
|
|
||||||
void (*on_interrupt)(void *args);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
68
include/api.hpp
Normal file
68
include/api.hpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef _DIFFTEST_API_H_
|
||||||
|
#define _DIFFTEST_API_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <gdbstub.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Target dynamic library has to implement these functions
|
||||||
|
struct TargetOps {
|
||||||
|
typedef void (*cont_t)(void *args, gdb_action_t *res);
|
||||||
|
cont_t cont;
|
||||||
|
|
||||||
|
typedef void (*stepi_t)(void *args, gdb_action_t *res);
|
||||||
|
stepi_t stepi;
|
||||||
|
|
||||||
|
typedef int (*read_reg_t)(void *args, int regno, size_t *value);
|
||||||
|
read_reg_t read_reg;
|
||||||
|
|
||||||
|
typedef int (*write_reg_t)(void *args, int regno, size_t value);
|
||||||
|
write_reg_t write_reg;
|
||||||
|
|
||||||
|
typedef int (*read_mem_t)(void *args, size_t addr, size_t len, void *val);
|
||||||
|
read_mem_t read_mem;
|
||||||
|
|
||||||
|
typedef int (*write_mem_t)(void *args, size_t addr, size_t len, void *val);
|
||||||
|
write_mem_t write_mem;
|
||||||
|
|
||||||
|
typedef bool (*set_bp_t)(void *args, size_t addr, bp_type_t type);
|
||||||
|
set_bp_t set_bp;
|
||||||
|
|
||||||
|
typedef bool (*del_bp_t)(void *args, size_t addr, bp_type_t type);
|
||||||
|
del_bp_t del_bp;
|
||||||
|
|
||||||
|
typedef void (*on_interrupt_t)(void *args);
|
||||||
|
on_interrupt_t on_interrupt;
|
||||||
|
|
||||||
|
typedef void (*init_t)(void *args);
|
||||||
|
init_t init;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TargetMeta {
|
||||||
|
std::string name;
|
||||||
|
std::filesystem::path libpath;
|
||||||
|
void *dlhandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Target {
|
||||||
|
public:
|
||||||
|
TargetOps ops;
|
||||||
|
TargetMeta meta;
|
||||||
|
arch_info_t arch;
|
||||||
|
size_t argsize;
|
||||||
|
std::vector<uint8_t> args; // used as a buffer to store target specific values
|
||||||
|
|
||||||
|
gdb_action_t last_res;
|
||||||
|
|
||||||
|
Target(){};
|
||||||
|
Target(const std::string &name, const std::string &prefix,
|
||||||
|
const std::filesystem::path &path);
|
||||||
|
~Target();
|
||||||
|
|
||||||
|
bool is_on_breakpoint() const;
|
||||||
|
bool is_on_breakpoint(const gdb_action_t &res) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
14
include/config.hpp
Normal file
14
include/config.hpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include <CLI/App.hpp>
|
||||||
|
#include <CLI/CLI.hpp>
|
||||||
|
#include <CLI/Validators.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct Config {
|
||||||
|
std::filesystem::path memory_file;
|
||||||
|
std::vector<std::filesystem::path> refs;
|
||||||
|
std::filesystem::path dut;
|
||||||
|
int cli_parse(int argc, char **argv);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Config config;
|
|
@ -1,4 +1,73 @@
|
||||||
#ifndef _DIFFTEST_DIFFTEST_H_
|
#ifndef _DIFFTEST_DIFFTEST_H_
|
||||||
#define _DIFFTEST_DIFFTEST_H_
|
#define _DIFFTEST_DIFFTEST_H_
|
||||||
|
#include "api.hpp"
|
||||||
|
#include <filesystem>
|
||||||
|
#include <gdbstub.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
class Difftest {
|
||||||
|
private:
|
||||||
|
Target dut;
|
||||||
|
std::vector<Target> refs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Difftest(Target &&dut, std::vector<Target> &&refs);
|
||||||
|
|
||||||
|
void setup(const std::filesystem::path &memory_file);
|
||||||
|
gdb_action_t stepi();
|
||||||
|
gdb_action_t cont();
|
||||||
|
static bool check(Target &dut, Target &ref) {
|
||||||
|
for (int r = 0; r < dut.arch.reg_num; r++) {
|
||||||
|
size_t regdut = 0, regref = 0;
|
||||||
|
dut.ops.read_reg(dut.args.data(), r, ®dut);
|
||||||
|
ref.ops.read_reg(ref.args.data(), r, ®ref);
|
||||||
|
if (regdut != regref) {
|
||||||
|
std::cout << "reg: " << r << " dut: " << regdut << " ref: " << regref
|
||||||
|
<< std::endl;
|
||||||
|
throw std::runtime_error("Difftest failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
bool check_all();
|
||||||
|
|
||||||
|
class Iterator {
|
||||||
|
private:
|
||||||
|
Difftest &difftest;
|
||||||
|
size_t index;
|
||||||
|
bool on_dut;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Iterator(Difftest &difftest, size_t index, bool on_dut)
|
||||||
|
: difftest(difftest), index(index), on_dut(on_dut) {}
|
||||||
|
|
||||||
|
Iterator &operator++() {
|
||||||
|
if (on_dut) {
|
||||||
|
on_dut = false;
|
||||||
|
} else {
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Iterator &other) const {
|
||||||
|
return index != other.index || on_dut != other.on_dut;
|
||||||
|
}
|
||||||
|
|
||||||
|
Target &operator*() {
|
||||||
|
if (on_dut) {
|
||||||
|
return difftest.dut;
|
||||||
|
} else {
|
||||||
|
return difftest.refs.at(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Iterator begin() { return Iterator(*this, 0, true); }
|
||||||
|
|
||||||
|
Iterator end() { return Iterator(*this, refs.size(), false); }
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1,2 +1,3 @@
|
||||||
add_executable(test main.cpp)
|
add_executable(diffu cli.cpp difftest.cpp loader.cpp main.cpp)
|
||||||
|
target_link_libraries(diffu PRIVATE gdbstub)
|
||||||
|
set_target_properties(diffu PROPERTIES ENABLE_EXPORTS 1)
|
||||||
|
|
25
src/cli.cpp
Normal file
25
src/cli.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "config.hpp"
|
||||||
|
#include <CLI/App.hpp>
|
||||||
|
#include <CLI/Validators.hpp>
|
||||||
|
|
||||||
|
int Config::cli_parse(int argc, char **argv) {
|
||||||
|
CLI::App app;
|
||||||
|
app.add_option("-m,--memory", memory_file, "Content of memory")
|
||||||
|
->required()
|
||||||
|
->check(CLI::ExistingFile);
|
||||||
|
|
||||||
|
app.add_option("--ref", refs, "Reference dynamic library")
|
||||||
|
->required()
|
||||||
|
->check(CLI::ExistingFile);
|
||||||
|
|
||||||
|
app.add_option("--dut", dut, "Design under test")
|
||||||
|
->required()
|
||||||
|
->check(CLI::ExistingFile);
|
||||||
|
|
||||||
|
app.set_config("-c,--config")
|
||||||
|
->transform(CLI::FileOnDefaultPath("./difftest.toml"));
|
||||||
|
|
||||||
|
CLI11_PARSE(app, argc, argv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
98
src/difftest.cpp
Normal file
98
src/difftest.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#include "api.hpp"
|
||||||
|
#include <difftest.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
Difftest::Difftest(Target &&dut, std::vector<Target> &&refs) {
|
||||||
|
this->dut = std::move(dut);
|
||||||
|
this->refs = std::move(refs);
|
||||||
|
|
||||||
|
for (const auto &ref : refs) {
|
||||||
|
if (dut.arch.reg_byte != ref.arch.reg_byte ||
|
||||||
|
dut.arch.reg_num != ref.arch.reg_num) {
|
||||||
|
throw std::runtime_error("Ref and dut must have the same architecture");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Difftest::setup(const std::filesystem::path &memory_file) {
|
||||||
|
std::ifstream is = std::ifstream(memory_file, std::ios::binary);
|
||||||
|
|
||||||
|
// Seek to the end to determine the file size
|
||||||
|
is.seekg(0, std::ios::end);
|
||||||
|
std::streampos memsize = is.tellg();
|
||||||
|
is.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
std::vector<char> membuf(memsize);
|
||||||
|
is.read(membuf.data(), memsize);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
// Initialize memory
|
||||||
|
// TODO: reset vector should not be hardcoded
|
||||||
|
// for(auto target : *this) {
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it) {
|
||||||
|
auto &target = *it;
|
||||||
|
printf("init addr: %p\n", target.ops.init);
|
||||||
|
target.ops.init(target.args.data());
|
||||||
|
target.ops.write_mem(target.args.data(), 0x80000000UL, membuf.size(),
|
||||||
|
membuf.data());
|
||||||
|
target.ops.write_reg(target.args.data(), 32, 0x80000000UL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Difftest::check_all() {
|
||||||
|
for (auto &ref : refs) {
|
||||||
|
check(dut, ref);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_action_t Difftest::stepi() {
|
||||||
|
bool breakflag = false;
|
||||||
|
Target *pbreak;
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it) {
|
||||||
|
auto &target = *it;
|
||||||
|
target.ops.stepi(target.args.data(), &target.last_res);
|
||||||
|
if (target.is_on_breakpoint()) {
|
||||||
|
breakflag = true;
|
||||||
|
pbreak = ⌖
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breakflag) {
|
||||||
|
gdb_action_t ret = {.reason = gdb_action_t::ACT_BREAKPOINT};
|
||||||
|
pbreak->ops.read_reg(pbreak->args.data(), 32, &ret.data);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return {gdb_action_t::ACT_NONE, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_action_t Difftest::cont() {
|
||||||
|
bool breakflag = false;
|
||||||
|
Target *pbreak;
|
||||||
|
check_all();
|
||||||
|
std::cerr << "setup finished." << std::endl;
|
||||||
|
while (true) {
|
||||||
|
// for(auto &target : *this) {
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it) {
|
||||||
|
auto &target = *it;
|
||||||
|
target.ops.stepi(target.args.data(), &target.last_res);
|
||||||
|
|
||||||
|
if (target.is_on_breakpoint()) {
|
||||||
|
breakflag = true;
|
||||||
|
pbreak = ⌖
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check_all();
|
||||||
|
|
||||||
|
if (breakflag) {
|
||||||
|
gdb_action_t ret = {.reason = gdb_action_t::ACT_BREAKPOINT};
|
||||||
|
pbreak->ops.read_reg(pbreak->args.data(), 32, &ret.data);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {gdb_action_t::ACT_NONE, 0};
|
||||||
|
}
|
76
src/loader.cpp
Normal file
76
src/loader.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#include "api.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
Target::Target(const std::string &name, const std::string &func_prefix,
|
||||||
|
const std::filesystem::path &path) {
|
||||||
|
|
||||||
|
std::cout << path.c_str() << std::endl;
|
||||||
|
meta = {.name = name,
|
||||||
|
.libpath = path,
|
||||||
|
.dlhandle = dlopen(path.c_str(), RTLD_LAZY)};
|
||||||
|
|
||||||
|
if (!meta.dlhandle) {
|
||||||
|
throw std::runtime_error(dlerror());
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOAD_SYMBOL(ops, handle, prefix, name) \
|
||||||
|
do { \
|
||||||
|
ops.name = reinterpret_cast<decltype(TargetOps::name)>( \
|
||||||
|
dlsym(handle, (prefix + #name).c_str())); \
|
||||||
|
if (!ops.name) \
|
||||||
|
goto load_error; \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, cont);
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, stepi);
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, read_reg);
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, write_reg);
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, read_mem);
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, write_mem);
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, set_bp);
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, del_bp);
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, on_interrupt);
|
||||||
|
LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, init);
|
||||||
|
|
||||||
|
#undef LOAD_SYMBOL
|
||||||
|
|
||||||
|
size_t *argsize_sym;
|
||||||
|
argsize_sym = reinterpret_cast<size_t *>(dlsym(meta.dlhandle, "argsize"));
|
||||||
|
if (!argsize_sym)
|
||||||
|
goto load_error;
|
||||||
|
|
||||||
|
argsize = *argsize_sym;
|
||||||
|
args = std::vector<uint8_t>(argsize);
|
||||||
|
|
||||||
|
arch_info_t *arch_sym;
|
||||||
|
arch_sym =
|
||||||
|
reinterpret_cast<arch_info_t *>(dlsym(meta.dlhandle, "isa_arch_info"));
|
||||||
|
if (!arch_sym)
|
||||||
|
goto load_error;
|
||||||
|
return;
|
||||||
|
|
||||||
|
load_error:
|
||||||
|
std::string err = std::string(dlerror());
|
||||||
|
dlclose(meta.dlhandle);
|
||||||
|
throw std::runtime_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
Target::~Target() {
|
||||||
|
std::cout << "Destruct target " << meta.name << std::endl;
|
||||||
|
dlclose(meta.dlhandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Target::is_on_breakpoint() const { return is_on_breakpoint(last_res); }
|
||||||
|
|
||||||
|
bool Target::is_on_breakpoint(const gdb_action_t &res) const {
|
||||||
|
if (res.reason == gdb_action_t::ACT_BREAKPOINT ||
|
||||||
|
res.reason == gdb_action_t::ACT_RWATCH ||
|
||||||
|
res.reason == gdb_action_t::ACT_WATCH ||
|
||||||
|
res.reason == gdb_action_t::ACT_WWATCH) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
24
src/main.cpp
24
src/main.cpp
|
@ -1,5 +1,23 @@
|
||||||
#include <difftest.hpp>
|
#include "api.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "difftest.hpp"
|
||||||
|
|
||||||
using reg_t = uint32_t;
|
int main(int argc, char **argv) {
|
||||||
|
Config config;
|
||||||
|
int ret = 0;
|
||||||
|
ret = config.cli_parse(argc, argv);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
int main() { return 0; }
|
std::vector<Target> refs;
|
||||||
|
Target dut = Target{"dut", "nemu_", config.dut};
|
||||||
|
for (const auto &ref_libpath : config.refs) {
|
||||||
|
refs.emplace_back(ref_libpath.string(), "nemu_", ref_libpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Difftest difftest{std::move(dut), std::move(refs)};
|
||||||
|
difftest.setup(config.memory_file);
|
||||||
|
difftest.cont();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue