Skip to content

Commit

Permalink
Add QMP callback
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Fasano committed Dec 6, 2023
1 parent 8d661ba commit a37039a
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 7 deletions.
35 changes: 35 additions & 0 deletions panda/include/panda/callbacks/cb-defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ typedef enum panda_cb_type {
PANDA_CB_HD_WRITE, // Each HDD write
PANDA_CB_GUEST_HYPERCALL, // Hypercall from the guest (e.g. CPUID)
PANDA_CB_MONITOR, // Monitor callback
PANDA_CB_QMP, // QMP callback
PANDA_CB_CPU_RESTORE_STATE, // In cpu_restore_state() (fault/exception)
PANDA_CB_BEFORE_LOADVM, // at start of replay, before loadvm
PANDA_CB_ASID_CHANGED, // When CPU asid (address space identifier) changes
Expand Down Expand Up @@ -592,6 +593,23 @@ typedef union panda_cb {
*/
int (*monitor)(Monitor *mon, const char *cmd);

/* Callback ID: PANDA_CB_QMP
qmp:
Called when someone sends an unhandled QMP command
Arguments:
char *command: the command string as json
char *args: the arguments string as json
char **result: pointer to a json result or NULL
Helper call location: TBA
Return value:
bool: true IFF the command was handled by the plugin
*/
bool (*qmp)(char *command, char* args, char **result);


/* Callback ID: PANDA_CB_CPU_RESTORE_STATE
Expand Down Expand Up @@ -1544,6 +1562,23 @@ typedef union panda_cb_with_context {
*/
int (*monitor)(void* context, Monitor *mon, const char *cmd);

/* Callback ID: PANDA_CB_QMP
qmp:
Called when someone sends an unhandled QMP command
Arguments:
char *command: the command string as json
char *args: the arguments string as json
char **result: pointer to a json result or NULL
Helper call location: TBA
Return value:
bool: true IFF the command was handled by the plugin
*/
bool (*qmp)(void* context, char *command, char* args, char **result);


/* Callback ID: PANDA_CB_CPU_RESTORE_STATE
Expand Down
1 change: 1 addition & 0 deletions panda/include/panda/callbacks/cb-support.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ bool panda_callbacks_after_find_fast(CPUState *cpu, TranslationBlock *tb, bool b
int panda_callbacks_insn_exec(CPUState *env, target_ptr_t pc);
int panda_callbacks_after_insn_exec(CPUState *env, target_ptr_t pc);
int panda_callbacks_monitor(Monitor *mon, const char *cmd);
bool panda_callbacks_qmp(char *command, char *args, char **result);
int panda_callbacks_before_loadvm(void);
void panda_callbacks_replay_hd_transfer(CPUState *env, uint32_t type, target_ptr_t src_addr, target_ptr_t dest_addr, size_t num_bytes);
void panda_callbacks_after_machine_init(CPUState *env);
Expand Down
1 change: 1 addition & 0 deletions panda/include/panda/callbacks/cb-trampolines.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ void panda_cb_trampoline_phys_mem_after_write(void* context, CPUState *env, targ
int panda_cb_trampoline_insn_exec(void* context, CPUState *env, target_ptr_t pc);
int panda_cb_trampoline_after_insn_exec(void* context, CPUState *env, target_ptr_t pc);
int panda_cb_trampoline_monitor(void* context, Monitor *mon, const char *cmd);
bool panda_cb_trampoline_qmp(void* context, char *command, char *args, char **result);
//int panda_cb_trampoline_before_loadvm(void* context);
void panda_cb_trampoline_replay_hd_transfer(void* context, CPUState *env, uint32_t type, target_ptr_t src_addr, target_ptr_t dest_addr, size_t num_bytes);
void panda_cb_trampoline_after_machine_init(void* context, CPUState *env);
Expand Down
1 change: 1 addition & 0 deletions panda/src/callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ panda_cb_with_context panda_get_cb_trampoline(panda_cb_type type) {
CASE_CB_TRAMPOLINE(HD_WRITE,hd_write)
CASE_CB_TRAMPOLINE(GUEST_HYPERCALL,guest_hypercall)
CASE_CB_TRAMPOLINE(MONITOR,monitor)
CASE_CB_TRAMPOLINE(QMP,qmp)
CASE_CB_TRAMPOLINE(CPU_RESTORE_STATE,cpu_restore_state)

//CASE_CB_TRAMPOLINE(BEFORE_LOADVM,before_loadvm)
Expand Down
2 changes: 2 additions & 0 deletions panda/src/cb-support.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ void panda_cb_trampoline_start_block_exec(void* context, CPUState *cpu, Translat
// these aren't used
MAKE_CALLBACK(void, HD_READ, hd_read, CPUState*, env);
MAKE_CALLBACK(void, HD_WRITE, hd_write, CPUState*, env);

MAKE_CALLBACK(int, MONITOR, monitor, Monitor*, mon, const char*, cmd);
MAKE_CALLBACK(bool, QMP, qmp, char*, cmd, char*, args, char **, result);

// Helper - get a physical address
static inline hwaddr get_paddr(CPUState *cpu, target_ptr_t addr, void *ram_ptr) {
Expand Down
47 changes: 40 additions & 7 deletions qapi/qmp-dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "qapi/qmp/qjson.h"
#include "qapi-types.h"
#include "qapi/qmp/qerror.h"
//#include "panda/callbacks/cb-support.h"
extern bool panda_callbacks_qmp(char *command, char* args, char **result);

static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
{
Expand Down Expand Up @@ -83,24 +85,55 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,

command = qdict_get_str(dict, "execute");
cmd = qmp_find_command(cmds, command);

if (!qdict_haskey(dict, "arguments")) {
args = qdict_new();
} else {
args = qdict_get_qdict(dict, "arguments");
QINCREF(args);
}

if (cmd == NULL) {
// Call any PANDA consumers of the unhandled command
// Provide them with arguments in json format.
// If any plugin returns true, we assume it handled the command
// and we expect a json output in result.
char *result = NULL;
const QString* cmd_args_q = qobject_to_json(QOBJECT(args));
const char *cmd_args = qstring_get_str(cmd_args_q);

if (panda_callbacks_qmp((char*)command, (char*)cmd_args, &result)) {
if (result != NULL) {
// We have a return value from the callback. Let's convert it to a qobject
ret = qobject_from_json(result, &local_err);
if (local_err) {
printf("PANDA ERROR decoding result json in callback");
error_propagate(errp, local_err);
return NULL;
}
}

if (!ret) {
printf("PANDA WARNING: a qmp callback consumer returned TRUE without providing \
a return value! Creating empty dictionary");

ret = QOBJECT(qdict_new());
}
QDECREF(args);
return ret;
}

error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
"The command %s has not been found", command);
return NULL;
}

if (!cmd->enabled) {
error_setg(errp, "The command %s has been disabled for this instance",
command);
return NULL;
}

if (!qdict_haskey(dict, "arguments")) {
args = qdict_new();
} else {
args = qdict_get_qdict(dict, "arguments");
QINCREF(args);
}

cmd->fn(args, &ret, &local_err);
if (local_err) {
error_propagate(errp, local_err);
Expand Down

0 comments on commit a37039a

Please sign in to comment.