feat: initial support
This commit is contained in:
parent
dd2feddfd6
commit
5ddf0b48be
13 changed files with 449 additions and 42 deletions
|
@ -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_
|
||||
#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
|
Loading…
Add table
Add a link
Reference in a new issue