mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-21 12:53:01 +00:00
Capstone disassembler
-----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJZ8bGHAAoJEGTfOOivfiFfOXQH/jc3BbQ+ulxvQSgA3rI2JE1e Ww5FK5HEs4qZU3hz4EtE2Cd5p7qV5I4tWRtbxzc6BGBwLsfz3a60Abx7726sZiH0 ZuULTsWXQ/71XfZHQysgOSoy36G8xj/1yvrMWHjDCfWp/pzz479YXWSSn2TWEHpI jI6nKP5ALdv5XTAaglGaNzqVeWgjKXJn4O8qZFS7axj7hndzLFguymfm8rV8DAdd LRuYWOizzzJ0dcaO/HHyLTzSl7rR0g+DmcOAuFCREy4f+r6tXijwiirB5f7ZJiqc hgEBq/6NfztW2+pAUSxqI2Kuq1zVETTpZORH1+UxvVk9GPu1ouYldMx0NrYhDtc= =fC5W -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-dis-20171026' into staging Capstone disassembler # gpg: Signature made Thu 26 Oct 2017 10:57:27 BST # gpg: using RSA key 0x64DF38E8AF7E215F # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-dis-20171026: disas: Add capstone as submodule disas: Remove monitor_disas_is_physical ppc: Support Capstone in disas_set_info arm: Support Capstone in disas_set_info i386: Support Capstone in disas_set_info disas: Support the Capstone disassembler library disas: Remove unused flags arguments target/arm: Don't set INSN_ARM_BE32 for CONFIG_USER_ONLY target/arm: Move BE32 disassembler fixup target/ppc: Convert to disas_set_info hook target/i386: Convert to disas_set_info hook Signed-off-by: Peter Maydell <peter.maydell@linaro.org> # Conflicts: # target/i386/cpu.c # target/ppc/translate_init.c
This commit is contained in:
commit
6e6430a821
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -37,3 +37,6 @@
|
||||
[submodule "ui/keycodemapdb"]
|
||||
path = ui/keycodemapdb
|
||||
url = git://git.qemu.org/keycodemapdb.git
|
||||
[submodule "capstone"]
|
||||
path = capstone
|
||||
url = git://git.qemu.org/capstone.git
|
||||
|
15
Makefile
15
Makefile
@ -383,6 +383,21 @@ subdir-dtc: .git-submodule-status dtc/libfdt dtc/tests
|
||||
dtc/%: .git-submodule-status
|
||||
mkdir -p $@
|
||||
|
||||
# Overriding CFLAGS causes us to lose defines added in the sub-makefile.
|
||||
# Not overriding CFLAGS leads to mis-matches between compilation modes.
|
||||
# Therefore we replicate some of the logic in the sub-makefile.
|
||||
# Remove all the extra -Warning flags that QEMU uses that Capstone doesn't;
|
||||
# no need to annoy QEMU developers with such things.
|
||||
CAP_CFLAGS = $(patsubst -W%,,$(CFLAGS) $(QEMU_CFLAGS))
|
||||
CAP_CFLAGS += -DCAPSTONE_USE_SYS_DYN_MEM
|
||||
CAP_CFLAGS += -DCAPSTONE_HAS_ARM
|
||||
CAP_CFLAGS += -DCAPSTONE_HAS_ARM64
|
||||
CAP_CFLAGS += -DCAPSTONE_HAS_POWERPC
|
||||
CAP_CFLAGS += -DCAPSTONE_HAS_X86
|
||||
|
||||
subdir-capstone: .git-submodule-status
|
||||
$(call quiet-command,$(MAKE) -C $(SRC_PATH)/capstone CAPSTONE_SHARED=no BUILDDIR="$(BUILD_DIR)/capstone" CC="$(CC)" AR="$(AR)" LD="$(LD)" CFLAGS="$(CAP_CFLAGS)" $(SUBDIR_MAKEFLAGS) $(BUILD_DIR)/capstone/$(LIBCAPSTONE))
|
||||
|
||||
$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) \
|
||||
$(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
|
||||
|
||||
|
1
capstone
Submodule
1
capstone
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 22ead3e0bfdb87516656453336160e0a37b066bf
|
72
configure
vendored
72
configure
vendored
@ -375,6 +375,7 @@ opengl_dmabuf="no"
|
||||
cpuid_h="no"
|
||||
avx2_opt="no"
|
||||
zlib="yes"
|
||||
capstone=""
|
||||
lzo=""
|
||||
snappy=""
|
||||
bzip2=""
|
||||
@ -1294,6 +1295,14 @@ for opt do
|
||||
error_exit "vhost-user isn't available on win32"
|
||||
fi
|
||||
;;
|
||||
--disable-capstone) capstone="no"
|
||||
;;
|
||||
--enable-capstone) capstone="yes"
|
||||
;;
|
||||
--enable-capstone=git) capstone="git"
|
||||
;;
|
||||
--enable-capstone=system) capstone="system"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown option $opt"
|
||||
echo "Try '$0 --help' for more information"
|
||||
@ -1541,6 +1550,7 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
vxhs Veritas HyperScale vDisk backend support
|
||||
crypto-afalg Linux AF_ALG crypto backend driver
|
||||
vhost-user vhost-user support
|
||||
capstone capstone disassembler support
|
||||
|
||||
NOTE: The object files are built at the place where configure is launched
|
||||
EOF
|
||||
@ -4410,6 +4420,58 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# capstone
|
||||
|
||||
case "$capstone" in
|
||||
"" | yes)
|
||||
if $pkg_config capstone; then
|
||||
capstone=system
|
||||
elif test -e "${source_path}/.git" ; then
|
||||
capstone=git
|
||||
elif test -e "${source_path}/capstone/Makefile" ; then
|
||||
capstone=internal
|
||||
elif test -z "$capstone" ; then
|
||||
capstone=no
|
||||
else
|
||||
feature_not_found "capstone" "Install capstone devel or git submodule"
|
||||
fi
|
||||
;;
|
||||
|
||||
system)
|
||||
if ! $pkg_config capstone; then
|
||||
feature_not_found "capstone" "Install capstone devel"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$capstone" in
|
||||
git | internal)
|
||||
if test "$capstone" = git; then
|
||||
git_submodules="${git_submodules} capstone"
|
||||
fi
|
||||
mkdir -p capstone
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS -I\$(SRC_PATH)/capstone/include"
|
||||
if test "$mingw32" = "yes"; then
|
||||
LIBCAPSTONE=capstone.lib
|
||||
else
|
||||
LIBCAPSTONE=libcapstone.a
|
||||
fi
|
||||
LIBS="-L\$(BUILD_DIR)/capstone -lcapstone $LIBS"
|
||||
;;
|
||||
|
||||
system)
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $($pkg_config --cflags capstone)"
|
||||
LIBS="$($pkg_config --libs capstone) $LIBS"
|
||||
;;
|
||||
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
error_exit "Unknown state for capstone: $capstone"
|
||||
;;
|
||||
esac
|
||||
|
||||
##########################################
|
||||
# check if we have fdatasync
|
||||
|
||||
@ -5468,6 +5530,7 @@ echo "jemalloc support $jemalloc"
|
||||
echo "avx2 optimization $avx2_opt"
|
||||
echo "replication support $replication"
|
||||
echo "VxHS block device $vxhs"
|
||||
echo "capstone $capstone"
|
||||
|
||||
if test "$sdl_too_old" = "yes"; then
|
||||
echo "-> Your SDL version is too old - please upgrade to have SDL support"
|
||||
@ -6142,6 +6205,9 @@ fi
|
||||
if test "$ivshmem" = "yes" ; then
|
||||
echo "CONFIG_IVSHMEM=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$capstone" != "no" ; then
|
||||
echo "CONFIG_CAPSTONE=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
# Hold two types of flag:
|
||||
# CONFIG_THREAD_SETNAME_BYTHREAD - we've got a way of setting the name on
|
||||
@ -6624,6 +6690,12 @@ done # for target in $targets
|
||||
if [ "$dtc_internal" = "yes" ]; then
|
||||
echo "config-host.h: subdir-dtc" >> $config_host_mak
|
||||
fi
|
||||
if [ "$capstone" = "git" -o "$capstone" = "internal" ]; then
|
||||
echo "config-host.h: subdir-capstone" >> $config_host_mak
|
||||
fi
|
||||
if test -n "$LIBCAPSTONE"; then
|
||||
echo "LIBCAPSTONE=$LIBCAPSTONE" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$numa" = "yes"; then
|
||||
echo "CONFIG_NUMA=y" >> $config_host_mak
|
||||
|
308
disas.c
308
disas.c
@ -6,6 +6,7 @@
|
||||
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "disas/capstone.h"
|
||||
|
||||
typedef struct CPUDebug {
|
||||
struct disassemble_info info;
|
||||
@ -171,15 +172,195 @@ static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
|
||||
return print_insn_objdump(pc, info, "OBJD-T");
|
||||
}
|
||||
|
||||
/* Disassemble this for me please... (debugging). 'flags' has the following
|
||||
values:
|
||||
i386 - 1 means 16 bit code, 2 means 64 bit code
|
||||
ppc - bits 0:15 specify (optionally) the machine instruction set;
|
||||
bit 16 indicates little endian.
|
||||
other targets - unused
|
||||
*/
|
||||
#ifdef CONFIG_CAPSTONE
|
||||
/* Temporary storage for the capstone library. This will be alloced via
|
||||
malloc with a size private to the library; thus there's no reason not
|
||||
to share this across calls and across host vs target disassembly. */
|
||||
static __thread cs_insn *cap_insn;
|
||||
|
||||
/* Initialize the Capstone library. */
|
||||
/* ??? It would be nice to cache this. We would need one handle for the
|
||||
host and one for the target. For most targets we can reset specific
|
||||
parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change
|
||||
CS_ARCH_* in this way. Thus we would need to be able to close and
|
||||
re-open the target handle with a different arch for the target in order
|
||||
to handle AArch64 vs AArch32 mode switching. */
|
||||
static cs_err cap_disas_start(disassemble_info *info, csh *handle)
|
||||
{
|
||||
cs_mode cap_mode = info->cap_mode;
|
||||
cs_err err;
|
||||
|
||||
cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN
|
||||
: CS_MODE_LITTLE_ENDIAN);
|
||||
|
||||
err = cs_open(info->cap_arch, cap_mode, handle);
|
||||
if (err != CS_ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ??? There probably ought to be a better place to put this. */
|
||||
if (info->cap_arch == CS_ARCH_X86) {
|
||||
/* We don't care about errors (if for some reason the library
|
||||
is compiled without AT&T syntax); the user will just have
|
||||
to deal with the Intel syntax. */
|
||||
cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
|
||||
}
|
||||
|
||||
/* "Disassemble" unknown insns as ".byte W,X,Y,Z". */
|
||||
cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
|
||||
|
||||
/* Allocate temp space for cs_disasm_iter. */
|
||||
if (cap_insn == NULL) {
|
||||
cap_insn = cs_malloc(*handle);
|
||||
if (cap_insn == NULL) {
|
||||
cs_close(handle);
|
||||
return CS_ERR_MEM;
|
||||
}
|
||||
}
|
||||
return CS_ERR_OK;
|
||||
}
|
||||
|
||||
/* Disassemble SIZE bytes at PC for the target. */
|
||||
static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size)
|
||||
{
|
||||
uint8_t cap_buf[1024];
|
||||
csh handle;
|
||||
cs_insn *insn;
|
||||
size_t csize = 0;
|
||||
|
||||
if (cap_disas_start(info, &handle) != CS_ERR_OK) {
|
||||
return false;
|
||||
}
|
||||
insn = cap_insn;
|
||||
|
||||
while (1) {
|
||||
size_t tsize = MIN(sizeof(cap_buf) - csize, size);
|
||||
const uint8_t *cbuf = cap_buf;
|
||||
|
||||
target_read_memory(pc + csize, cap_buf + csize, tsize, info);
|
||||
csize += tsize;
|
||||
size -= tsize;
|
||||
|
||||
while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
|
||||
(*info->fprintf_func)(info->stream,
|
||||
"0x%08" PRIx64 ": %-12s %s\n",
|
||||
insn->address, insn->mnemonic,
|
||||
insn->op_str);
|
||||
}
|
||||
|
||||
/* If the target memory is not consumed, go back for more... */
|
||||
if (size != 0) {
|
||||
/* ... taking care to move any remaining fractional insn
|
||||
to the beginning of the buffer. */
|
||||
if (csize != 0) {
|
||||
memmove(cap_buf, cbuf, csize);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Since the target memory is consumed, we should not have
|
||||
a remaining fractional insn. */
|
||||
if (csize != 0) {
|
||||
(*info->fprintf_func)(info->stream,
|
||||
"Disassembler disagrees with translator "
|
||||
"over instruction decoding\n"
|
||||
"Please report this to qemu-devel@nongnu.org\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cs_close(&handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Disassemble SIZE bytes at CODE for the host. */
|
||||
static bool cap_disas_host(disassemble_info *info, void *code, size_t size)
|
||||
{
|
||||
csh handle;
|
||||
const uint8_t *cbuf;
|
||||
cs_insn *insn;
|
||||
uint64_t pc;
|
||||
|
||||
if (cap_disas_start(info, &handle) != CS_ERR_OK) {
|
||||
return false;
|
||||
}
|
||||
insn = cap_insn;
|
||||
|
||||
cbuf = code;
|
||||
pc = (uintptr_t)code;
|
||||
|
||||
while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) {
|
||||
(*info->fprintf_func)(info->stream,
|
||||
"0x%08" PRIx64 ": %-12s %s\n",
|
||||
insn->address, insn->mnemonic,
|
||||
insn->op_str);
|
||||
}
|
||||
if (size != 0) {
|
||||
(*info->fprintf_func)(info->stream,
|
||||
"Disassembler disagrees with TCG over instruction encoding\n"
|
||||
"Please report this to qemu-devel@nongnu.org\n");
|
||||
}
|
||||
|
||||
cs_close(&handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Disassemble COUNT insns at PC for the target. */
|
||||
static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
|
||||
{
|
||||
uint8_t cap_buf[32];
|
||||
csh handle;
|
||||
cs_insn *insn;
|
||||
size_t csize = 0;
|
||||
|
||||
if (cap_disas_start(info, &handle) != CS_ERR_OK) {
|
||||
return false;
|
||||
}
|
||||
insn = cap_insn;
|
||||
|
||||
while (1) {
|
||||
/* We want to read memory for one insn, but generically we do not
|
||||
know how much memory that is. We have a small buffer which is
|
||||
known to be sufficient for all supported targets. Try to not
|
||||
read beyond the page, Just In Case. For even more simplicity,
|
||||
ignore the actual target page size and use a 1k boundary. If
|
||||
that turns out to be insufficient, we'll come back around the
|
||||
loop and read more. */
|
||||
uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024);
|
||||
size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc);
|
||||
const uint8_t *cbuf = cap_buf;
|
||||
|
||||
/* Make certain that we can make progress. */
|
||||
assert(tsize != 0);
|
||||
info->read_memory_func(pc, cap_buf + csize, tsize, info);
|
||||
csize += tsize;
|
||||
|
||||
if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
|
||||
(*info->fprintf_func)(info->stream,
|
||||
"0x%08" PRIx64 ": %-12s %s\n",
|
||||
insn->address, insn->mnemonic,
|
||||
insn->op_str);
|
||||
if (--count <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
memmove(cap_buf, cbuf, csize);
|
||||
}
|
||||
|
||||
cs_close(&handle);
|
||||
return true;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
#else
|
||||
# define cap_disas_target(i, p, s) false
|
||||
# define cap_disas_host(i, p, s) false
|
||||
# define cap_disas_monitor(i, p, c) false
|
||||
#endif /* CONFIG_CAPSTONE */
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
||||
target_ulong size, int flags)
|
||||
target_ulong size)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
target_ulong pc;
|
||||
@ -193,6 +374,8 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
||||
s.info.buffer_vma = code;
|
||||
s.info.buffer_length = size;
|
||||
s.info.print_address_func = generic_print_address;
|
||||
s.info.cap_arch = -1;
|
||||
s.info.cap_mode = 0;
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
s.info.endian = BFD_ENDIAN_BIG;
|
||||
@ -204,32 +387,10 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
||||
cc->disas_set_info(cpu, &s.info);
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
if (flags == 2) {
|
||||
s.info.mach = bfd_mach_x86_64;
|
||||
} else if (flags == 1) {
|
||||
s.info.mach = bfd_mach_i386_i8086;
|
||||
} else {
|
||||
s.info.mach = bfd_mach_i386_i386;
|
||||
if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
|
||||
return;
|
||||
}
|
||||
s.info.print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_PPC)
|
||||
if ((flags >> 16) & 1) {
|
||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||
}
|
||||
if (flags & 0xFFFF) {
|
||||
/* If we have a precise definition of the instruction set, use it. */
|
||||
s.info.mach = flags & 0xFFFF;
|
||||
} else {
|
||||
#ifdef TARGET_PPC64
|
||||
s.info.mach = bfd_mach_ppc64;
|
||||
#else
|
||||
s.info.mach = bfd_mach_ppc;
|
||||
#endif
|
||||
}
|
||||
s.info.disassembler_options = (char *)"any";
|
||||
s.info.print_insn = print_insn_ppc;
|
||||
#endif
|
||||
|
||||
if (s.info.print_insn == NULL) {
|
||||
s.info.print_insn = print_insn_od_target;
|
||||
}
|
||||
@ -237,18 +398,6 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
||||
for (pc = code; size > 0; pc += count, size -= count) {
|
||||
fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
|
||||
count = s.info.print_insn(pc, &s.info);
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
uint8_t b;
|
||||
fprintf(out, " {");
|
||||
for(i = 0; i < count; i++) {
|
||||
target_read_memory(pc + i, &b, 1, &s.info);
|
||||
fprintf(out, " %02x", b);
|
||||
}
|
||||
fprintf(out, " }");
|
||||
}
|
||||
#endif
|
||||
fprintf(out, "\n");
|
||||
if (count < 0)
|
||||
break;
|
||||
@ -276,6 +425,8 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
s.info.buffer = code;
|
||||
s.info.buffer_vma = (uintptr_t)code;
|
||||
s.info.buffer_length = size;
|
||||
s.info.cap_arch = -1;
|
||||
s.info.cap_mode = 0;
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
s.info.endian = BFD_ENDIAN_BIG;
|
||||
@ -287,14 +438,23 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
#elif defined(__i386__)
|
||||
s.info.mach = bfd_mach_i386_i386;
|
||||
print_insn = print_insn_i386;
|
||||
s.info.cap_arch = CS_ARCH_X86;
|
||||
s.info.cap_mode = CS_MODE_32;
|
||||
#elif defined(__x86_64__)
|
||||
s.info.mach = bfd_mach_x86_64;
|
||||
print_insn = print_insn_i386;
|
||||
s.info.cap_arch = CS_ARCH_X86;
|
||||
s.info.cap_mode = CS_MODE_64;
|
||||
#elif defined(_ARCH_PPC)
|
||||
s.info.disassembler_options = (char *)"any";
|
||||
print_insn = print_insn_ppc;
|
||||
s.info.cap_arch = CS_ARCH_PPC;
|
||||
# ifdef _ARCH_PPC64
|
||||
s.info.cap_mode = CS_MODE_64;
|
||||
# endif
|
||||
#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
|
||||
print_insn = print_insn_arm_a64;
|
||||
s.info.cap_arch = CS_ARCH_ARM64;
|
||||
#elif defined(__alpha__)
|
||||
print_insn = print_insn_alpha;
|
||||
#elif defined(__sparc__)
|
||||
@ -302,6 +462,8 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
s.info.mach = bfd_mach_sparc_v9b;
|
||||
#elif defined(__arm__)
|
||||
print_insn = print_insn_arm;
|
||||
s.info.cap_arch = CS_ARCH_ARM;
|
||||
/* TCG only generates code for arm mode. */
|
||||
#elif defined(__MIPSEB__)
|
||||
print_insn = print_insn_big_mips;
|
||||
#elif defined(__MIPSEL__)
|
||||
@ -313,6 +475,11 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
#elif defined(__hppa__)
|
||||
print_insn = print_insn_hppa;
|
||||
#endif
|
||||
|
||||
if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (print_insn == NULL) {
|
||||
print_insn = print_insn_od_host;
|
||||
}
|
||||
@ -345,26 +512,17 @@ const char *lookup_symbol(target_ulong orig_addr)
|
||||
|
||||
#include "monitor/monitor.h"
|
||||
|
||||
static int monitor_disas_is_physical;
|
||||
|
||||
static int
|
||||
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info)
|
||||
{
|
||||
CPUDebug *s = container_of(info, CPUDebug, info);
|
||||
|
||||
if (monitor_disas_is_physical) {
|
||||
cpu_physical_memory_read(memaddr, myaddr, length);
|
||||
} else {
|
||||
cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
|
||||
}
|
||||
cpu_physical_memory_read(memaddr, myaddr, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Disassembler for the monitor.
|
||||
See target_disas for a description of flags. */
|
||||
/* Disassembler for the monitor. */
|
||||
void monitor_disas(Monitor *mon, CPUState *cpu,
|
||||
target_ulong pc, int nb_insn, int is_physical, int flags)
|
||||
target_ulong pc, int nb_insn, int is_physical)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
int count, i;
|
||||
@ -373,11 +531,12 @@ void monitor_disas(Monitor *mon, CPUState *cpu,
|
||||
INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
|
||||
|
||||
s.cpu = cpu;
|
||||
monitor_disas_is_physical = is_physical;
|
||||
s.info.read_memory_func = monitor_read_memory;
|
||||
s.info.read_memory_func
|
||||
= (is_physical ? physical_read_memory : target_read_memory);
|
||||
s.info.print_address_func = generic_print_address;
|
||||
|
||||
s.info.buffer_vma = pc;
|
||||
s.info.cap_arch = -1;
|
||||
s.info.cap_mode = 0;
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
s.info.endian = BFD_ENDIAN_BIG;
|
||||
@ -389,31 +548,10 @@ void monitor_disas(Monitor *mon, CPUState *cpu,
|
||||
cc->disas_set_info(cpu, &s.info);
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
if (flags == 2) {
|
||||
s.info.mach = bfd_mach_x86_64;
|
||||
} else if (flags == 1) {
|
||||
s.info.mach = bfd_mach_i386_i8086;
|
||||
} else {
|
||||
s.info.mach = bfd_mach_i386_i386;
|
||||
if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) {
|
||||
return;
|
||||
}
|
||||
s.info.print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_PPC)
|
||||
if (flags & 0xFFFF) {
|
||||
/* If we have a precise definition of the instruction set, use it. */
|
||||
s.info.mach = flags & 0xFFFF;
|
||||
} else {
|
||||
#ifdef TARGET_PPC64
|
||||
s.info.mach = bfd_mach_ppc64;
|
||||
#else
|
||||
s.info.mach = bfd_mach_ppc;
|
||||
#endif
|
||||
}
|
||||
if ((flags >> 16) & 1) {
|
||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||
}
|
||||
s.info.print_insn = print_insn_ppc;
|
||||
#endif
|
||||
|
||||
if (!s.info.print_insn) {
|
||||
monitor_printf(mon, "0x" TARGET_FMT_lx
|
||||
": Asm output not supported on this arch\n", pc);
|
||||
|
21
disas/arm.c
21
disas/arm.c
@ -70,6 +70,17 @@ static void floatformat_to_double (unsigned char *data, double *dest)
|
||||
*dest = u.f;
|
||||
}
|
||||
|
||||
static int arm_read_memory(bfd_vma memaddr, bfd_byte *b, int length,
|
||||
struct disassemble_info *info)
|
||||
{
|
||||
assert((info->flags & INSN_ARM_BE32) == 0 || length == 2 || length == 4);
|
||||
|
||||
if ((info->flags & INSN_ARM_BE32) != 0 && length == 2) {
|
||||
memaddr ^= 2;
|
||||
}
|
||||
return info->read_memory_func(memaddr, b, length, info);
|
||||
}
|
||||
|
||||
/* End of qemu specific additions. */
|
||||
|
||||
struct opcode32
|
||||
@ -3810,7 +3821,7 @@ find_ifthen_state (bfd_vma pc, struct disassemble_info *info,
|
||||
return;
|
||||
}
|
||||
addr -= 2;
|
||||
status = info->read_memory_func (addr, (bfd_byte *)b, 2, info);
|
||||
status = arm_read_memory (addr, (bfd_byte *)b, 2, info);
|
||||
if (status)
|
||||
return;
|
||||
|
||||
@ -3882,7 +3893,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
|
||||
info->bytes_per_chunk = size;
|
||||
printer = print_insn_data;
|
||||
|
||||
status = info->read_memory_func (pc, (bfd_byte *)b, size, info);
|
||||
status = arm_read_memory (pc, (bfd_byte *)b, size, info);
|
||||
given = 0;
|
||||
if (little)
|
||||
for (i = size - 1; i >= 0; i--)
|
||||
@ -3899,7 +3910,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
|
||||
info->bytes_per_chunk = 4;
|
||||
size = 4;
|
||||
|
||||
status = info->read_memory_func (pc, (bfd_byte *)b, 4, info);
|
||||
status = arm_read_memory (pc, (bfd_byte *)b, 4, info);
|
||||
if (little)
|
||||
given = (b[0]) | (b[1] << 8) | (b[2] << 16) | ((unsigned)b[3] << 24);
|
||||
else
|
||||
@ -3915,7 +3926,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
|
||||
info->bytes_per_chunk = 2;
|
||||
size = 2;
|
||||
|
||||
status = info->read_memory_func (pc, (bfd_byte *)b, 2, info);
|
||||
status = arm_read_memory (pc, (bfd_byte *)b, 2, info);
|
||||
if (little)
|
||||
given = (b[0]) | (b[1] << 8);
|
||||
else
|
||||
@ -3929,7 +3940,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
|
||||
|| (given & 0xF800) == 0xF000
|
||||
|| (given & 0xF800) == 0xE800)
|
||||
{
|
||||
status = info->read_memory_func (pc + 2, (bfd_byte *)b, 2, info);
|
||||
status = arm_read_memory (pc + 2, (bfd_byte *)b, 2, info);
|
||||
if (little)
|
||||
given = (b[0]) | (b[1] << 8) | (given << 16);
|
||||
else
|
||||
|
@ -307,12 +307,6 @@ typedef struct disassemble_info {
|
||||
(bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info);
|
||||
|
||||
/* A place to stash the real read_memory_func if read_memory_func wants to
|
||||
do some funky address arithmetic or similar (e.g. for ARM BE32 mode). */
|
||||
int (*read_memory_inner_func)
|
||||
(bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info);
|
||||
|
||||
/* Function which should be called if we get an error that we can't
|
||||
recover from. STATUS is the errno value from read_memory_func and
|
||||
MEMADDR is the address that we were trying to read. INFO is a
|
||||
@ -377,6 +371,10 @@ typedef struct disassemble_info {
|
||||
/* Command line options specific to the target disassembler. */
|
||||
char * disassembler_options;
|
||||
|
||||
/* Options for Capstone disassembly. */
|
||||
int cap_arch;
|
||||
int cap_mode;
|
||||
|
||||
} disassemble_info;
|
||||
|
||||
|
||||
@ -479,7 +477,6 @@ int generic_symbol_at_address(bfd_vma, struct disassemble_info *);
|
||||
(INFO).buffer_vma = 0, \
|
||||
(INFO).buffer_length = 0, \
|
||||
(INFO).read_memory_func = buffer_read_memory, \
|
||||
(INFO).read_memory_inner_func = NULL, \
|
||||
(INFO).memory_error_func = perror_memory, \
|
||||
(INFO).print_address_func = generic_print_address, \
|
||||
(INFO).print_insn = NULL, \
|
||||
|
38
include/disas/capstone.h
Normal file
38
include/disas/capstone.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef QEMU_CAPSTONE_H
|
||||
#define QEMU_CAPSTONE_H 1
|
||||
|
||||
#ifdef CONFIG_CAPSTONE
|
||||
|
||||
#include <capstone.h>
|
||||
|
||||
#else
|
||||
|
||||
/* Just enough to allow backends to init without ifdefs. */
|
||||
|
||||
#define CS_ARCH_ARM -1
|
||||
#define CS_ARCH_ARM64 -1
|
||||
#define CS_ARCH_MIPS -1
|
||||
#define CS_ARCH_X86 -1
|
||||
#define CS_ARCH_PPC -1
|
||||
#define CS_ARCH_SPARC -1
|
||||
#define CS_ARCH_SYSZ -1
|
||||
|
||||
#define CS_MODE_LITTLE_ENDIAN 0
|
||||
#define CS_MODE_BIG_ENDIAN 0
|
||||
#define CS_MODE_ARM 0
|
||||
#define CS_MODE_16 0
|
||||
#define CS_MODE_32 0
|
||||
#define CS_MODE_64 0
|
||||
#define CS_MODE_THUMB 0
|
||||
#define CS_MODE_MCLASS 0
|
||||
#define CS_MODE_V8 0
|
||||
#define CS_MODE_MICRO 0
|
||||
#define CS_MODE_MIPS3 0
|
||||
#define CS_MODE_MIPS32R6 0
|
||||
#define CS_MODE_MIPSGP64 0
|
||||
#define CS_MODE_V9 0
|
||||
#define CS_MODE_MIPS32 0
|
||||
#define CS_MODE_MIPS64 0
|
||||
|
||||
#endif /* CONFIG_CAPSTONE */
|
||||
#endif /* QEMU_CAPSTONE_H */
|
@ -9,10 +9,10 @@
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void disas(FILE *out, void *code, unsigned long size);
|
||||
void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
||||
target_ulong size, int flags);
|
||||
target_ulong size);
|
||||
|
||||
void monitor_disas(Monitor *mon, CPUState *cpu,
|
||||
target_ulong pc, int nb_insn, int is_physical, int flags);
|
||||
target_ulong pc, int nb_insn, int is_physical);
|
||||
|
||||
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
||||
const char *lookup_symbol(target_ulong orig_addr);
|
||||
|
@ -38,9 +38,9 @@ static inline void log_cpu_state_mask(int mask, CPUState *cpu, int flags)
|
||||
#ifdef NEED_CPU_H
|
||||
/* disas() and target_disas() to qemu_logfile: */
|
||||
static inline void log_target_disas(CPUState *cpu, target_ulong start,
|
||||
target_ulong len, int flags)
|
||||
target_ulong len)
|
||||
{
|
||||
target_disas(qemu_logfile, cpu, start, len, flags);
|
||||
target_disas(qemu_logfile, cpu, start, len);
|
||||
}
|
||||
|
||||
static inline void log_disas(void *code, unsigned long size)
|
||||
|
29
monitor.c
29
monitor.c
@ -1309,34 +1309,7 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize,
|
||||
}
|
||||
|
||||
if (format == 'i') {
|
||||
int flags = 0;
|
||||
#ifdef TARGET_I386
|
||||
CPUArchState *env = mon_get_cpu_env();
|
||||
if (wsize == 2) {
|
||||
flags = 1;
|
||||
} else if (wsize == 4) {
|
||||
flags = 0;
|
||||
} else {
|
||||
/* as default we use the current CS size */
|
||||
flags = 0;
|
||||
if (env) {
|
||||
#ifdef TARGET_X86_64
|
||||
if ((env->efer & MSR_EFER_LMA) &&
|
||||
(env->segs[R_CS].flags & DESC_L_MASK))
|
||||
flags = 2;
|
||||
else
|
||||
#endif
|
||||
if (!(env->segs[R_CS].flags & DESC_B_MASK))
|
||||
flags = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef TARGET_PPC
|
||||
CPUArchState *env = mon_get_cpu_env();
|
||||
flags = msr_le << 16;
|
||||
flags |= env->bfd_mach;
|
||||
#endif
|
||||
monitor_disas(mon, cs, addr, count, is_physical, flags);
|
||||
monitor_disas(mon, cs, addr, count, is_physical);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3038,7 +3038,7 @@ static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||
static void alpha_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size, 1);
|
||||
log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps alpha_tr_ops = {
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "kvm_arm.h"
|
||||
#include "disas/capstone.h"
|
||||
|
||||
static void arm_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
@ -473,25 +474,11 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
|
||||
return print_insn_arm(pc | 1, info);
|
||||
}
|
||||
|
||||
static int arm_read_memory_func(bfd_vma memaddr, bfd_byte *b,
|
||||
int length, struct disassemble_info *info)
|
||||
{
|
||||
assert(info->read_memory_inner_func);
|
||||
assert((info->flags & INSN_ARM_BE32) == 0 || length == 2 || length == 4);
|
||||
|
||||
if ((info->flags & INSN_ARM_BE32) != 0 && length == 2) {
|
||||
assert(info->endian == BFD_ENDIAN_LITTLE);
|
||||
return info->read_memory_inner_func(memaddr ^ 2, (bfd_byte *)b, 2,
|
||||
info);
|
||||
} else {
|
||||
return info->read_memory_inner_func(memaddr, b, length, info);
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
|
||||
{
|
||||
ARMCPU *ac = ARM_CPU(cpu);
|
||||
CPUARMState *env = &ac->env;
|
||||
bool sctlr_b;
|
||||
|
||||
if (is_a64(env)) {
|
||||
/* We might not be compiled with the A64 disassembler
|
||||
@ -501,26 +488,40 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
|
||||
#if defined(CONFIG_ARM_A64_DIS)
|
||||
info->print_insn = print_insn_arm_a64;
|
||||
#endif
|
||||
} else if (env->thumb) {
|
||||
info->print_insn = print_insn_thumb1;
|
||||
info->cap_arch = CS_ARCH_ARM64;
|
||||
} else {
|
||||
info->print_insn = print_insn_arm;
|
||||
int cap_mode;
|
||||
if (env->thumb) {
|
||||
info->print_insn = print_insn_thumb1;
|
||||
cap_mode = CS_MODE_THUMB;
|
||||
} else {
|
||||
info->print_insn = print_insn_arm;
|
||||
cap_mode = CS_MODE_ARM;
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
cap_mode |= CS_MODE_V8;
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
cap_mode |= CS_MODE_MCLASS;
|
||||
}
|
||||
info->cap_arch = CS_ARCH_ARM;
|
||||
info->cap_mode = cap_mode;
|
||||
}
|
||||
if (bswap_code(arm_sctlr_b(env))) {
|
||||
|
||||
sctlr_b = arm_sctlr_b(env);
|
||||
if (bswap_code(sctlr_b)) {
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
info->endian = BFD_ENDIAN_LITTLE;
|
||||
#else
|
||||
info->endian = BFD_ENDIAN_BIG;
|
||||
#endif
|
||||
}
|
||||
if (info->read_memory_inner_func == NULL) {
|
||||
info->read_memory_inner_func = info->read_memory_func;
|
||||
info->read_memory_func = arm_read_memory_func;
|
||||
}
|
||||
info->flags &= ~INSN_ARM_BE32;
|
||||
if (arm_sctlr_b(env)) {
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (sctlr_b) {
|
||||
info->flags |= INSN_ARM_BE32;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz)
|
||||
|
@ -11423,8 +11423,7 @@ static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size,
|
||||
4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size);
|
||||
}
|
||||
|
||||
const TranslatorOps aarch64_translator_ops = {
|
||||
|
@ -12372,8 +12372,7 @@ static void arm_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size,
|
||||
dc->thumb | (dc->sctlr_b << 1));
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps arm_translator_ops = {
|
||||
|
@ -3296,8 +3296,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||
qemu_log_lock();
|
||||
qemu_log("--------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start,
|
||||
env->pregs[PR_VR]);
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start);
|
||||
qemu_log("\nisize=%d osize=%d\n",
|
||||
dc->pc - pc_start, tcg_op_buf_count());
|
||||
qemu_log_unlock();
|
||||
|
@ -3902,7 +3902,7 @@ static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
|
||||
break;
|
||||
default:
|
||||
qemu_log("IN: %s\n", lookup_symbol(tb->pc));
|
||||
log_target_disas(cs, tb->pc, tb->size, 1);
|
||||
log_target_disas(cs, tb->pc, tb->size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,8 @@
|
||||
#include "hw/i386/apic_internal.h"
|
||||
#endif
|
||||
|
||||
#include "disas/capstone.h"
|
||||
|
||||
|
||||
/* Cache topology CPUID constants: */
|
||||
|
||||
@ -4093,6 +4095,22 @@ static bool x86_cpu_has_work(CPUState *cs)
|
||||
!(env->hflags & HF_SMM_MASK));
|
||||
}
|
||||
|
||||
static void x86_disas_set_info(CPUState *cs, disassemble_info *info)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
CPUX86State *env = &cpu->env;
|
||||
|
||||
info->mach = (env->hflags & HF_CS64_MASK ? bfd_mach_x86_64
|
||||
: env->hflags & HF_CS32_MASK ? bfd_mach_i386_i386
|
||||
: bfd_mach_i386_i8086);
|
||||
info->print_insn = print_insn_i386;
|
||||
|
||||
info->cap_arch = CS_ARCH_X86;
|
||||
info->cap_mode = (env->hflags & HF_CS64_MASK ? CS_MODE_64
|
||||
: env->hflags & HF_CS32_MASK ? CS_MODE_32
|
||||
: CS_MODE_16);
|
||||
}
|
||||
|
||||
static Property x86_cpu_properties[] = {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* apic_id = 0 by default for *-user, see commit 9886e834 */
|
||||
@ -4215,6 +4233,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
||||
#ifdef CONFIG_TCG
|
||||
cc->tcg_initialize = tcg_x86_init;
|
||||
#endif
|
||||
cc->disas_set_info = x86_disas_set_info;
|
||||
|
||||
dc->user_creatable = true;
|
||||
}
|
||||
|
@ -8548,15 +8548,9 @@ static void i386_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
int disas_flags = !dc->code32;
|
||||
|
||||
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
#ifdef TARGET_X86_64
|
||||
if (dc->code64) {
|
||||
disas_flags = 2;
|
||||
}
|
||||
#endif
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size, disas_flags);
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps i386_tr_ops = {
|
||||
|
@ -1155,7 +1155,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||
&& qemu_log_in_addr_range(pc_start)) {
|
||||
qemu_log_lock();
|
||||
qemu_log("\n");
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start);
|
||||
qemu_log("\nisize=%d osize=%d\n",
|
||||
dc->pc - pc_start, tcg_op_buf_count());
|
||||
qemu_log_unlock();
|
||||
|
@ -5623,7 +5623,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
||||
qemu_log_lock();
|
||||
qemu_log("----------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
@ -1809,7 +1809,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||
qemu_log_lock();
|
||||
qemu_log("--------------\n");
|
||||
#if DISAS_GNU
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start);
|
||||
#endif
|
||||
qemu_log("\nisize=%d osize=%d\n",
|
||||
dc->pc - pc_start, tcg_op_buf_count());
|
||||
|
@ -20369,7 +20369,7 @@ done_generating:
|
||||
&& qemu_log_in_addr_range(pc_start)) {
|
||||
qemu_log_lock();
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
|
||||
log_target_disas(cs, pc_start, ctx.pc - pc_start);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
@ -906,7 +906,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
||||
&& qemu_log_in_addr_range(tb->pc)) {
|
||||
qemu_log_lock();
|
||||
qemu_log("IN: %s\n", lookup_symbol(tb->pc));
|
||||
log_target_disas(cs, tb->pc, dc->pc - tb->pc, 0);
|
||||
log_target_disas(cs, tb->pc, dc->pc - tb->pc);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
@ -1650,7 +1650,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
||||
&& qemu_log_in_addr_range(pc_start)) {
|
||||
log_target_disas(cs, pc_start, tb->size, 0);
|
||||
log_target_disas(cs, pc_start, tb->size);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
@ -7397,12 +7397,9 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||
#if defined(DEBUG_DISAS)
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
||||
&& qemu_log_in_addr_range(pc_start)) {
|
||||
int flags;
|
||||
flags = env->bfd_mach;
|
||||
flags |= ctx.le_mode << 16;
|
||||
qemu_log_lock();
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, ctx.nip - pc_start, flags);
|
||||
log_target_disas(cs, pc_start, ctx.nip - pc_start);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "mmu-book3s-v3.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "disas/capstone.h"
|
||||
|
||||
//#define PPC_DUMP_CPU
|
||||
//#define PPC_DEBUG_SPR
|
||||
@ -10515,6 +10516,31 @@ static gchar *ppc_gdb_arch_name(CPUState *cs)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ppc_disas_set_info(CPUState *cs, disassemble_info *info)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
if ((env->hflags >> MSR_LE) & 1) {
|
||||
info->endian = BFD_ENDIAN_LITTLE;
|
||||
}
|
||||
info->mach = env->bfd_mach;
|
||||
if (!env->bfd_mach) {
|
||||
#ifdef TARGET_PPC64
|
||||
info->mach = bfd_mach_ppc64;
|
||||
#else
|
||||
info->mach = bfd_mach_ppc;
|
||||
#endif
|
||||
}
|
||||
info->disassembler_options = (char *)"any";
|
||||
info->print_insn = print_insn_ppc;
|
||||
|
||||
info->cap_arch = CS_ARCH_PPC;
|
||||
#ifdef TARGET_PPC64
|
||||
info->cap_mode = CS_MODE_64;
|
||||
#endif
|
||||
}
|
||||
|
||||
static Property ppc_cpu_properties[] = {
|
||||
DEFINE_PROP_BOOL("pre-2.8-migration", PowerPCCPU, pre_2_8_migration, false),
|
||||
DEFINE_PROP_BOOL("pre-2.10-migration", PowerPCCPU, pre_2_10_migration,
|
||||
@ -10581,7 +10607,8 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#ifdef CONFIG_TCG
|
||||
cc->tcg_initialize = ppc_translate_init;
|
||||
#endif
|
||||
|
||||
cc->disas_set_info = ppc_disas_set_info;
|
||||
|
||||
dc->fw_name = "PowerPC,UNKNOWN";
|
||||
}
|
||||
|
||||
|
@ -5982,7 +5982,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||
qemu_log("IN: EXECUTE %016" PRIx64 "\n", dc.ex_value);
|
||||
} else {
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, dc.pc - pc_start, 1);
|
||||
log_target_disas(cs, pc_start, dc.pc - pc_start);
|
||||
qemu_log("\n");
|
||||
}
|
||||
qemu_log_unlock();
|
||||
|
@ -2336,7 +2336,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||
&& qemu_log_in_addr_range(pc_start)) {
|
||||
qemu_log_lock();
|
||||
qemu_log("IN:\n"); /* , lookup_symbol(pc_start)); */
|
||||
log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
|
||||
log_target_disas(cs, pc_start, ctx.pc - pc_start);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
@ -5849,7 +5849,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock * tb)
|
||||
qemu_log_lock();
|
||||
qemu_log("--------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, last_pc + 4 - pc_start, 0);
|
||||
log_target_disas(cs, pc_start, last_pc + 4 - pc_start);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
@ -8837,7 +8837,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||
&& qemu_log_in_addr_range(pc_start)) {
|
||||
qemu_log_lock();
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, ctx.pc - pc_start, 0);
|
||||
log_target_disas(cs, pc_start, ctx.pc - pc_start);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
@ -2027,7 +2027,7 @@ done_generating:
|
||||
qemu_log_lock();
|
||||
qemu_log("----------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
@ -3247,7 +3247,7 @@ done:
|
||||
qemu_log_lock();
|
||||
qemu_log("----------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, dc.pc - pc_start, 0);
|
||||
log_target_disas(cs, pc_start, dc.pc - pc_start);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user