diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2024-04-04 20:46:32 -1000 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2024-05-15 08:55:19 +0200 |
commit | c0d691ab844db8cdf2be8f6cf43887cfff56e386 (patch) | |
tree | 39a9f14d5a7817fed53ba2c6f60f06fb98655dd5 /disas/disas-target.c | |
parent | b67c567b79f7f659814d102579d2b503b6d40ed4 (diff) |
disas: Split disas.c
The routines in disas-common.c are also used from disas-mon.c.
Otherwise the rest of disassembly is only used from tcg.
While we're at it, put host and target code into separate files.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'disas/disas-target.c')
-rw-r--r-- | disas/disas-target.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/disas/disas-target.c b/disas/disas-target.c new file mode 100644 index 0000000000..82313b2a67 --- /dev/null +++ b/disas/disas-target.c @@ -0,0 +1,84 @@ +/* + * Routines for target instruction disassembly. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "disas/disas.h" +#include "disas/capstone.h" +#include "disas-internal.h" + + +void target_disas(FILE *out, CPUState *cpu, uint64_t code, size_t size) +{ + uint64_t pc; + int count; + CPUDebug s; + + disas_initialize_debug_target(&s, cpu); + s.info.fprintf_func = fprintf; + s.info.stream = out; + s.info.buffer_vma = code; + s.info.buffer_length = size; + s.info.show_opcodes = true; + + if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) { + return; + } + + if (s.info.print_insn == NULL) { + s.info.print_insn = print_insn_od_target; + } + + for (pc = code; size > 0; pc += count, size -= count) { + fprintf(out, "0x%08" PRIx64 ": ", pc); + count = s.info.print_insn(pc, &s.info); + fprintf(out, "\n"); + if (count < 0) { + break; + } + if (size < count) { + fprintf(out, + "Disassembler disagrees with translator over instruction " + "decoding\n" + "Please report this to qemu-devel@nongnu.org\n"); + break; + } + } +} + +#ifdef CONFIG_PLUGIN +static void plugin_print_address(bfd_vma addr, struct disassemble_info *info) +{ + /* does nothing */ +} + +/* + * We should only be dissembling one instruction at a time here. If + * there is left over it usually indicates the front end has read more + * bytes than it needed. + */ +char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size) +{ + CPUDebug s; + GString *ds = g_string_new(NULL); + + disas_initialize_debug_target(&s, cpu); + s.info.fprintf_func = disas_gstring_printf; + s.info.stream = (FILE *)ds; /* abuse this slot */ + s.info.buffer_vma = addr; + s.info.buffer_length = size; + s.info.print_address_func = plugin_print_address; + + if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) { + ; /* done */ + } else if (s.info.print_insn) { + s.info.print_insn(addr, &s.info); + } else { + ; /* cannot disassemble -- return empty string */ + } + + /* Return the buffer, freeing the GString container. */ + return g_string_free(ds, false); +} +#endif /* CONFIG_PLUGIN */ |