mirror of https://gitlab.com/qemu-project/qemu
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
2.6 KiB
C
105 lines
2.6 KiB
C
/*
|
|
* Common routines for disassembly.
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "disas/disas.h"
|
|
#include "disas/capstone.h"
|
|
#include "hw/core/cpu.h"
|
|
#include "exec/tswap.h"
|
|
#include "disas-internal.h"
|
|
|
|
|
|
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
|
struct syminfo *syminfos = NULL;
|
|
|
|
/*
|
|
* Print an error message. We can assume that this is in response to
|
|
* an error return from {host,target}_read_memory.
|
|
*/
|
|
static void perror_memory(int status, bfd_vma memaddr,
|
|
struct disassemble_info *info)
|
|
{
|
|
if (status != EIO) {
|
|
/* Can't happen. */
|
|
info->fprintf_func(info->stream, "Unknown error %d\n", status);
|
|
} else {
|
|
/* Address between memaddr and memaddr + len was out of bounds. */
|
|
info->fprintf_func(info->stream,
|
|
"Address 0x%" PRIx64 " is out of bounds.\n",
|
|
memaddr);
|
|
}
|
|
}
|
|
|
|
/* Print address in hex. */
|
|
static void print_address(bfd_vma addr, struct disassemble_info *info)
|
|
{
|
|
info->fprintf_func(info->stream, "0x%" PRIx64, addr);
|
|
}
|
|
|
|
/* Stub prevents some fruitless earching in optabs disassemblers. */
|
|
static int symbol_at_address(bfd_vma addr, struct disassemble_info *info)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void disas_initialize_debug(CPUDebug *s)
|
|
{
|
|
memset(s, 0, sizeof(*s));
|
|
s->info.arch = bfd_arch_unknown;
|
|
s->info.cap_arch = -1;
|
|
s->info.cap_insn_unit = 4;
|
|
s->info.cap_insn_split = 4;
|
|
s->info.memory_error_func = perror_memory;
|
|
s->info.symbol_at_address_func = symbol_at_address;
|
|
}
|
|
|
|
void disas_initialize_debug_target(CPUDebug *s, CPUState *cpu)
|
|
{
|
|
disas_initialize_debug(s);
|
|
|
|
s->cpu = cpu;
|
|
s->info.print_address_func = print_address;
|
|
if (target_words_bigendian()) {
|
|
s->info.endian = BFD_ENDIAN_BIG;
|
|
} else {
|
|
s->info.endian = BFD_ENDIAN_LITTLE;
|
|
}
|
|
|
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
|
if (cc->disas_set_info) {
|
|
cc->disas_set_info(cpu, &s->info);
|
|
}
|
|
}
|
|
|
|
int disas_gstring_printf(FILE *stream, const char *fmt, ...)
|
|
{
|
|
/* We abuse the FILE parameter to pass a GString. */
|
|
GString *s = (GString *)stream;
|
|
int initial_len = s->len;
|
|
va_list va;
|
|
|
|
va_start(va, fmt);
|
|
g_string_append_vprintf(s, fmt, va);
|
|
va_end(va);
|
|
|
|
return s->len - initial_len;
|
|
}
|
|
|
|
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
|
const char *lookup_symbol(uint64_t orig_addr)
|
|
{
|
|
const char *symbol = "";
|
|
struct syminfo *s;
|
|
|
|
for (s = syminfos; s; s = s->next) {
|
|
symbol = s->lookup_symbol(s, orig_addr);
|
|
if (symbol[0] != '\0') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return symbol;
|
|
}
|