From patchwork Thu Jun 9 12:56:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antoine Tremblay X-Patchwork-Id: 12901 Received: (qmail 65922 invoked by alias); 9 Jun 2016 12:56:49 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 65733 invoked by uid 89); 9 Jun 2016 12:56:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, SPF_PASS autolearn=ham version=3.3.2 spammy=stc, smc, rfe, Switch X-HELO: usplmg20.ericsson.net Received: from usplmg20.ericsson.net (HELO usplmg20.ericsson.net) (198.24.6.45) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Thu, 09 Jun 2016 12:56:36 +0000 Received: from EUSAAHC001.ericsson.se (Unknown_Domain [147.117.188.75]) by usplmg20.ericsson.net (Symantec Mail Security) with SMTP id 7C.D8.09012.F2E59575; Thu, 9 Jun 2016 14:16:47 +0200 (CEST) Received: from elxa4wqvvz1.dyn.mo.ca.am.ericsson.se (147.117.188.8) by smtps-am.internal.ericsson.com (147.117.188.75) with Microsoft SMTP Server (TLS) id 14.3.294.0; Thu, 9 Jun 2016 08:56:29 -0400 From: Antoine Tremblay To: CC: Simon Marchi Subject: [PATCH v2 07/17] Move ARM instruction decode functions to arch/arm-insn-reloc.c Date: Thu, 9 Jun 2016 08:56:05 -0400 Message-ID: <1465476975-25062-8-git-send-email-antoine.tremblay@ericsson.com> In-Reply-To: <1465476975-25062-1-git-send-email-antoine.tremblay@ericsson.com> References: <1465476975-25062-1-git-send-email-antoine.tremblay@ericsson.com> MIME-Version: 1.0 X-IsSubscribed: yes From: Simon Marchi This patch moves arm instruction decoding functions (for relocation purposes) to a shared location in arch/. No changes to the code itself. gdb/ChangeLog: * Makefile.in (ALL_TARGET_OBS): Add arm-insn-reloc.o. (HFILES_NO_SRCDIR): Add arch/arm-insn-reloc.h (arm-insn-reloc.o): New rule.. * arch/arm-insn-reloc.c: New file. * arch/arm-insn-reloc.h: New file. * configure.tgt (arm-*-*-linux*): Add arm-insn-reloc.o. * arm-tdep.c (struct arm_insn_reloc_visitor): Move to arch/arm-insn-reloc.c. (arm_decode_misc_memhint_neon): Likewise. (arm_decode_unconditional): Likewise. (arm_decode_miscellaneous): Likewise. (arm_decode_dp_misc): Likewise. (arm_decode_ld_st_word_ubyte): Likewise. (arm_decode_media): Likewise. (arm_decode_b_bl_ldmstm): Likewise. (arm_decode_ext_reg_ld_st): Likewise. (arm_decode_svc_copro): Likewise. (arm_relocate_insn_arm): Likewise. --- gdb/Makefile.in | 15 +- gdb/arch/arm-insn-reloc.c | 472 ++++++++++++++++++++++++++++++++++++++++++++++ gdb/arch/arm-insn-reloc.h | 49 +++++ gdb/arm-tdep.c | 471 +-------------------------------------------- gdb/configure.tgt | 2 +- 5 files changed, 535 insertions(+), 474 deletions(-) create mode 100644 gdb/arch/arm-insn-reloc.c create mode 100644 gdb/arch/arm-insn-reloc.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 60cfc97..3440e44 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -657,8 +657,13 @@ ALL_64_TARGET_OBS = \ # All other target-dependent objects files (used with --enable-targets=all). ALL_TARGET_OBS = \ - armbsd-tdep.o arm.o arm-linux.o arm-linux-tdep.o \ - arm-get-next-pcs.o arm-symbian-tdep.o \ + armbsd-tdep.o \ + arm.o \ + arm-linux.o \ + arm-linux-tdep.o \ + arm-get-next-pcs.o \ + arm-symbian-tdep.o \ + arm-insn-reloc.o \ armnbsd-tdep.o armobsd-tdep.o \ arm-tdep.o arm-wince-tdep.o \ avr-tdep.o \ @@ -988,7 +993,7 @@ common/common-exceptions.h target/target.h common/symbol.h \ common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \ common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\ nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \ -tid-parse.h ser-event.h +tid-parse.h ser-event.h arch/arm-insn-reloc.h # Header files that already have srcdir in them, or which are in objdir. @@ -2308,6 +2313,10 @@ arm-linux.o: ${srcdir}/arch/arm-linux.c $(COMPILE) $(srcdir)/arch/arm-linux.c $(POSTCOMPILE) +arm-insn-reloc.o: ${srcdir}/arch/arm-insn-reloc.c + $(COMPILE) $(srcdir)/arch/arm-insn-reloc.c + $(POSTCOMPILE) + arm-get-next-pcs.o: ${srcdir}/arch/arm-get-next-pcs.c $(COMPILE) $(srcdir)/arch/arm-get-next-pcs.c $(POSTCOMPILE) diff --git a/gdb/arch/arm-insn-reloc.c b/gdb/arch/arm-insn-reloc.c new file mode 100644 index 0000000..adf6243 --- /dev/null +++ b/gdb/arch/arm-insn-reloc.c @@ -0,0 +1,472 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "common-defs.h" + +#include "arm.h" +#include "arm-insn-reloc.h" + +static int +arm_decode_misc_memhint_neon (uint32_t insn, + struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7); + unsigned int rn = bits (insn, 16, 19); + + if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0) + return visitor->others (insn, "cps", data); + else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1) + return visitor->others (insn, "setend", data); + else if ((op1 & 0x60) == 0x20) + return visitor->others (insn, "neon dataproc", data); + else if ((op1 & 0x71) == 0x40) + return visitor->others (insn, "neon elt/struct load/store", data); + else if ((op1 & 0x77) == 0x41) + return visitor->others (insn, "unallocated mem hint", data); + else if ((op1 & 0x77) == 0x45) + return visitor->preload (insn, data); /* pli. */ + else if ((op1 & 0x77) == 0x51) + { + if (rn != 0xf) + return visitor->preload (insn, data); /* pld/pldw. */ + else + return visitor->unpred (insn, data); + } + else if ((op1 & 0x77) == 0x55) + return visitor->preload (insn, data); /* pld/pldw. */ + else if (op1 == 0x57) + switch (op2) + { + case 0x1: return visitor->others (insn, "clrex", data); + case 0x4: return visitor->others (insn, "dsb", data); + case 0x5: return visitor->others (insn, "dmb", data); + case 0x6: return visitor->others (insn, "isb", data); + default: return visitor->unpred (insn, data); + } + else if ((op1 & 0x63) == 0x43) + return visitor->unpred (insn, data); + else if ((op2 & 0x1) == 0x0) + switch (op1 & ~0x80) + { + case 0x61: + return visitor->others (insn, "unallocated mem hint", data); + case 0x65: + return visitor->preload_reg (insn, data); /* pli reg. */ + case 0x71: case 0x75: + /* pld/pldw reg. */ + return visitor->preload_reg (insn, data); + case 0x63: case 0x67: case 0x73: case 0x77: + return visitor->unpred (insn, data); + default: + return visitor->undef (insn, data); + } + else + return visitor->undef (insn, data); /* Probably unreachable. */ +} + +static int +arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + if (bit (insn, 27) == 0) + return arm_decode_misc_memhint_neon (insn, visitor, data); + /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx. */ + else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20)) + { + case 0x0: case 0x2: + return visitor->others (insn, "srs", data); + + case 0x1: case 0x3: + return visitor->others (insn, "rfe", data); + + case 0x4: case 0x5: case 0x6: case 0x7: + return visitor->b_bl_blx (insn, data); + + case 0x8: + switch ((insn & 0xe00000) >> 21) + { + case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: + /* stc/stc2. */ + return visitor->copro_load_store (insn, data); + + case 0x2: + return visitor->others (insn, "mcrr/mcrr2", data); + + default: + return visitor->undef (insn, data); + } + + case 0x9: + { + int rn_f = (bits (insn, 16, 19) == 0xf); + switch ((insn & 0xe00000) >> 21) + { + case 0x1: case 0x3: + /* ldc/ldc2 imm (undefined for rn == pc). */ + return rn_f ? visitor->undef (insn, data) + : visitor->copro_load_store (insn, data); + + case 0x2: + return visitor->others (insn, "mrrc/mrrc2", data); + + case 0x4: case 0x5: case 0x6: case 0x7: + /* ldc/ldc2 lit (undefined for rn != pc). */ + return rn_f ? visitor->copro_load_store (insn, data) + : visitor->undef (insn, data); + + default: + return visitor->undef (insn, data); + } + } + + case 0xa: + return visitor->others (insn, "stc/stc2", data); + + case 0xb: + if (bits (insn, 16, 19) == 0xf) + /* ldc/ldc2 lit. */ + return visitor->copro_load_store (insn, data); + else + return visitor->undef (insn, data); + + case 0xc: + if (bit (insn, 4)) + return visitor->others (insn, "mcr/mcr2", data); + else + return visitor->others (insn, "cdp/cdp2", data); + + case 0xd: + if (bit (insn, 4)) + return visitor->others (insn, "mrc/mrc2", data); + else + return visitor->others (insn, "cdp/cdp2", data); + + default: + return visitor->undef (insn, data); + } +} + + +/* Decode miscellaneous instructions in dp/misc encoding space. */ + +static int +arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + unsigned int op2 = bits (insn, 4, 6); + unsigned int op = bits (insn, 21, 22); + + switch (op2) + { + case 0x0: + return visitor->others (insn, "mrs/msr", data); + + case 0x1: + if (op == 0x1) /* bx. */ + return visitor->bx_blx_reg (insn, data); + else if (op == 0x3) + return visitor->others (insn, "clz", data); + else + return visitor->undef (insn, data); + + case 0x2: + if (op == 0x1) + /* Not really supported. */ + return visitor->others (insn, "bxj", data); + else + return visitor->undef (insn, data); + + case 0x3: + if (op == 0x1) + return visitor->bx_blx_reg (insn, data); /* blx register. */ + else + return visitor->undef (insn, data); + + case 0x5: + return visitor->others (insn, "saturating add/sub", data); + + case 0x7: + if (op == 0x1) + return visitor->others (insn, "bkpt", data); + else if (op == 0x3) + /* Not really supported. */ + return visitor->others (insn, "smc", data); + + default: + return visitor->undef (insn, data); + } +} + +static int +arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + if (bit (insn, 25)) + switch (bits (insn, 20, 24)) + { + case 0x10: + return visitor->others (insn, "movw", data); + + case 0x14: + return visitor->others (insn, "movt", data); + + case 0x12: + case 0x16: + return visitor->others (insn, "msr imm", data); + + default: + return visitor->alu_imm (insn, data); + } + else + { + uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7); + + if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0) + return visitor->alu_reg (insn, data); + else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1) + return visitor->alu_shifted_reg (insn, data); + else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0) + return arm_decode_miscellaneous (insn, visitor, data); + else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8) + return visitor->others (insn, "halfword mul/mla", data); + else if ((op1 & 0x10) == 0x00 && op2 == 0x9) + return visitor->others (insn, "mul/mla", data); + else if ((op1 & 0x10) == 0x10 && op2 == 0x9) + return visitor->others (insn, "synch", data); + else if (op2 == 0xb || (op2 & 0xd) == 0xd) + /* 2nd arg means "unprivileged". */ + return visitor->extra_ld_st (insn, data, (op1 & 0x12) == 0x02); + } + + /* Should be unreachable. */ + return 1; +} + + +static int +arm_decode_ld_st_word_ubyte (uint32_t insn, + struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + int a = bit (insn, 25), b = bit (insn, 4); + uint32_t op1 = bits (insn, 20, 24); + + if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02) + || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b)) + return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 0); + else if ((!a && (op1 & 0x17) == 0x02) + || (a && (op1 & 0x17) == 0x02 && !b)) + return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 1); + else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03) + || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b)) + return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 0); + else if ((!a && (op1 & 0x17) == 0x03) + || (a && (op1 & 0x17) == 0x03 && !b)) + return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 1); + else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06) + || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b)) + return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 0); + else if ((!a && (op1 & 0x17) == 0x06) + || (a && (op1 & 0x17) == 0x06 && !b)) + return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 1); + else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07) + || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b)) + return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 0); + else if ((!a && (op1 & 0x17) == 0x07) + || (a && (op1 & 0x17) == 0x07 && !b)) + return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 1); + + /* Should be unreachable. */ + return 1; +} + +static int +arm_decode_media (uint32_t insn, struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + switch (bits (insn, 20, 24)) + { + case 0x00: case 0x01: case 0x02: case 0x03: + return visitor->others (insn, "parallel add/sub signed", data); + + case 0x04: case 0x05: case 0x06: case 0x07: + return visitor->others (insn, "parallel add/sub unsigned", data); + + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + return visitor->others (insn, "decode/pack/unpack/saturate/reverse", + data); + + case 0x18: + if (bits (insn, 5, 7) == 0) /* op2. */ + { + if (bits (insn, 12, 15) == 0xf) + return visitor->others (insn, "usad8", data); + else + return visitor->others (insn, "usada8", data); + } + else + return visitor->undef (insn, data); + + case 0x1a: case 0x1b: + if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */ + return visitor->others (insn, "sbfx", data); + else + return visitor->undef (insn, data); + + case 0x1c: case 0x1d: + if (bits (insn, 5, 6) == 0x0) /* op2[1:0]. */ + { + if (bits (insn, 0, 3) == 0xf) + return visitor->others (insn, "bfc", data); + else + return visitor->others (insn, "bfi", data); + } + else + return visitor->undef (insn, data); + + case 0x1e: case 0x1f: + if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */ + return visitor->others (insn, "ubfx", data); + else + return visitor->undef (insn, data); + } + + /* Should be unreachable. */ + return 1; +} + +static int +arm_decode_b_bl_ldmstm (uint32_t insn, struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + if (bit (insn, 25)) + return visitor->b_bl_blx (insn, data); + else + return visitor->block_xfer (insn, data); +} + +static int +arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + unsigned int opcode = bits (insn, 20, 24); + + switch (opcode) + { + case 0x04: case 0x05: /* VFP/Neon mrrc/mcrr. */ + return visitor->others (insn, "vfp/neon mrrc/mcrr", data); + + case 0x08: case 0x0a: case 0x0c: case 0x0e: + case 0x12: case 0x16: + return visitor->others (insn, "vfp/neon vstm/vpush", data); + + case 0x09: case 0x0b: case 0x0d: case 0x0f: + case 0x13: case 0x17: + return visitor->others (insn, "vfp/neon vldm/vpop", data); + + case 0x10: case 0x14: case 0x18: case 0x1c: /* vstr. */ + case 0x11: case 0x15: case 0x19: case 0x1d: /* vldr. */ + /* Note: no writeback for these instructions. Bit 25 will always be + zero though (via caller), so the following works OK. */ + return visitor->copro_load_store (insn, data); + } + + /* Should be unreachable. */ + return 1; +} + + +static int +arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + unsigned int op1 = bits (insn, 20, 25); + int op = bit (insn, 4); + unsigned int coproc = bits (insn, 8, 11); + + if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa) + return arm_decode_ext_reg_ld_st (insn, visitor, data); + else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00 + && (coproc & 0xe) != 0xa) + /* stc/stc2. */ + return visitor->copro_load_store (insn, data); + else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00 + && (coproc & 0xe) != 0xa) + /* ldc/ldc2 imm/lit. */ + return visitor->copro_load_store (insn, data); + else if ((op1 & 0x3e) == 0x00) + return visitor->undef (insn, data); + else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa) + return visitor->others (insn, "neon 64bit xfer", data); + else if (op1 == 0x04 && (coproc & 0xe) != 0xa) + return visitor->others (insn, "mcrr/mcrr2", data); + else if (op1 == 0x05 && (coproc & 0xe) != 0xa) + return visitor->others (insn, "mrrc/mrrc2", data); + else if ((op1 & 0x30) == 0x20 && !op) + { + if ((coproc & 0xe) == 0xa) + return visitor->others (insn, "vfp dataproc", data); + else + return visitor->others (insn, "cdp/cdp2", data); + } + else if ((op1 & 0x30) == 0x20 && op) + return visitor->others (insn, "neon 8/16/32 bit xfer", data); + else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa) + return visitor->others (insn, "mcr/mcr2", data); + else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa) + return visitor->others (insn, "mrc/mrc2", data); + else if ((op1 & 0x30) == 0x30) + return visitor->svc (insn, data); + else + return visitor->undef (insn, data); /* Possibly unreachable. */ +} + +int +arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data) +{ + int err = 1; + + if ((insn & 0xf0000000) == 0xf0000000) + err = arm_decode_unconditional (insn, visitor, data); + else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24)) + { + case 0x0: case 0x1: case 0x2: case 0x3: + err = arm_decode_dp_misc (insn, visitor, data); + break; + + case 0x4: case 0x5: case 0x6: + err = arm_decode_ld_st_word_ubyte (insn, visitor, data); + break; + + case 0x7: + err = arm_decode_media (insn, visitor, data); + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + err = arm_decode_b_bl_ldmstm (insn, visitor, data); + break; + + case 0xc: case 0xd: case 0xe: case 0xf: + err = arm_decode_svc_copro (insn, visitor, data); + break; + } + + return err; +} diff --git a/gdb/arch/arm-insn-reloc.h b/gdb/arch/arm-insn-reloc.h new file mode 100644 index 0000000..18d3916 --- /dev/null +++ b/gdb/arch/arm-insn-reloc.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef ARM_INSN_RELOC_H +#define ARM_INSN_RELOC_H + +struct arm_insn_reloc_data; + +struct arm_insn_reloc_visitor +{ + int (*alu_imm) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*alu_reg) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*alu_shifted_reg) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*b_bl_blx) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*block_xfer) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*bx_blx_reg) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*copro_load_store) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*extra_ld_st) (uint32_t insn, struct arm_insn_reloc_data *data, + int unprivileged); + int (*ldr_str_ldrb_strb) (uint32_t insn, struct arm_insn_reloc_data *data, + int load, int size, int usermode); + int (*others) (uint32_t insn, const char *iname, + struct arm_insn_reloc_data *data); + int (*preload) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*preload_reg) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*svc) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*undef) (uint32_t insn, struct arm_insn_reloc_data *data); + int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data); +}; + +extern int arm_relocate_insn (uint32_t insn, + struct arm_insn_reloc_visitor *visitor, + struct arm_insn_reloc_data *data); + +#endif /* ARM_INSN_RELOC_H */ diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 0f35eb3..1af4d36 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -47,6 +47,7 @@ #include "arch/arm.h" #include "arch/arm-get-next-pcs.h" +#include "arch/arm-insn-reloc.h" #include "arm-tdep.h" #include "gdb/sim-arm.h" @@ -4480,28 +4481,6 @@ struct arm_insn_reloc_data struct regcache *regs; }; -struct arm_insn_reloc_visitor -{ - int (*alu_imm) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*alu_reg) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*alu_shifted_reg) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*b_bl_blx) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*block_xfer) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*bx_blx_reg) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*copro_load_store) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*extra_ld_st) (uint32_t insn, struct arm_insn_reloc_data *data, - int unprivileged); - int (*ldr_str_ldrb_strb) (uint32_t insn, struct arm_insn_reloc_data *data, - int load, int size, int usermode); - int (*others) (uint32_t insn, const char *iname, - struct arm_insn_reloc_data *data); - int (*preload) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*preload_reg) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*svc) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*undef) (uint32_t insn, struct arm_insn_reloc_data *data); - int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data); -}; - struct thumb_32bit_insn_reloc_visitor { int (*alu_imm) (uint16_t insn1, uint16_t insn2, @@ -6525,375 +6504,6 @@ arm_copy_unpred (uint32_t insn, struct arm_insn_reloc_data *data) /* The decode_* functions are instruction decoding helpers. They mostly follow the presentation in the ARM ARM. */ -static int -arm_decode_misc_memhint_neon (uint32_t insn, - struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7); - unsigned int rn = bits (insn, 16, 19); - - if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0) - return visitor->others (insn, "cps", data); - else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1) - return visitor->others (insn, "setend", data); - else if ((op1 & 0x60) == 0x20) - return visitor->others (insn, "neon dataproc", data); - else if ((op1 & 0x71) == 0x40) - return visitor->others (insn, "neon elt/struct load/store", data); - else if ((op1 & 0x77) == 0x41) - return visitor->others (insn, "unallocated mem hint", data); - else if ((op1 & 0x77) == 0x45) - return visitor->preload (insn, data); /* pli. */ - else if ((op1 & 0x77) == 0x51) - { - if (rn != 0xf) - return visitor->preload (insn, data); /* pld/pldw. */ - else - return visitor->unpred (insn, data); - } - else if ((op1 & 0x77) == 0x55) - return visitor->preload (insn, data); /* pld/pldw. */ - else if (op1 == 0x57) - switch (op2) - { - case 0x1: return visitor->others (insn, "clrex", data); - case 0x4: return visitor->others (insn, "dsb", data); - case 0x5: return visitor->others (insn, "dmb", data); - case 0x6: return visitor->others (insn, "isb", data); - default: return visitor->unpred (insn, data); - } - else if ((op1 & 0x63) == 0x43) - return visitor->unpred (insn, data); - else if ((op2 & 0x1) == 0x0) - switch (op1 & ~0x80) - { - case 0x61: - return visitor->others (insn, "unallocated mem hint", data); - case 0x65: - return visitor->preload_reg (insn, data); /* pli reg. */ - case 0x71: case 0x75: - /* pld/pldw reg. */ - return visitor->preload_reg (insn, data); - case 0x63: case 0x67: case 0x73: case 0x77: - return visitor->unpred (insn, data); - default: - return visitor->undef (insn, data); - } - else - return visitor->undef (insn, data); /* Probably unreachable. */ -} - -static int -arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - if (bit (insn, 27) == 0) - return arm_decode_misc_memhint_neon (insn, visitor, data); - /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx. */ - else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20)) - { - case 0x0: case 0x2: - return visitor->others (insn, "srs", data); - - case 0x1: case 0x3: - return visitor->others (insn, "rfe", data); - - case 0x4: case 0x5: case 0x6: case 0x7: - return visitor->b_bl_blx (insn, data); - - case 0x8: - switch ((insn & 0xe00000) >> 21) - { - case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: - /* stc/stc2. */ - return visitor->copro_load_store (insn, data); - - case 0x2: - return visitor->others (insn, "mcrr/mcrr2", data); - - default: - return visitor->undef (insn, data); - } - - case 0x9: - { - int rn_f = (bits (insn, 16, 19) == 0xf); - switch ((insn & 0xe00000) >> 21) - { - case 0x1: case 0x3: - /* ldc/ldc2 imm (undefined for rn == pc). */ - return rn_f ? visitor->undef (insn, data) - : visitor->copro_load_store (insn, data); - - case 0x2: - return visitor->others (insn, "mrrc/mrrc2", data); - - case 0x4: case 0x5: case 0x6: case 0x7: - /* ldc/ldc2 lit (undefined for rn != pc). */ - return rn_f ? visitor->copro_load_store (insn, data) - : visitor->undef (insn, data); - - default: - return visitor->undef (insn, data); - } - } - - case 0xa: - return visitor->others (insn, "stc/stc2", data); - - case 0xb: - if (bits (insn, 16, 19) == 0xf) - /* ldc/ldc2 lit. */ - return visitor->copro_load_store (insn, data); - else - return visitor->undef (insn, data); - - case 0xc: - if (bit (insn, 4)) - return visitor->others (insn, "mcr/mcr2", data); - else - return visitor->others (insn, "cdp/cdp2", data); - - case 0xd: - if (bit (insn, 4)) - return visitor->others (insn, "mrc/mrc2", data); - else - return visitor->others (insn, "cdp/cdp2", data); - - default: - return visitor->undef (insn, data); - } -} - -/* Decode miscellaneous instructions in dp/misc encoding space. */ - -static int -arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - unsigned int op2 = bits (insn, 4, 6); - unsigned int op = bits (insn, 21, 22); - - switch (op2) - { - case 0x0: - return visitor->others (insn, "mrs/msr", data); - - case 0x1: - if (op == 0x1) /* bx. */ - return visitor->bx_blx_reg (insn, data); - else if (op == 0x3) - return visitor->others (insn, "clz", data); - else - return visitor->undef (insn, data); - - case 0x2: - if (op == 0x1) - /* Not really supported. */ - return visitor->others (insn, "bxj", data); - else - return visitor->undef (insn, data); - - case 0x3: - if (op == 0x1) - return visitor->bx_blx_reg (insn, data); /* blx register. */ - else - return visitor->undef (insn, data); - - case 0x5: - return visitor->others (insn, "saturating add/sub", data); - - case 0x7: - if (op == 0x1) - return visitor->others (insn, "bkpt", data); - else if (op == 0x3) - /* Not really supported. */ - return visitor->others (insn, "smc", data); - - default: - return visitor->undef (insn, data); - } -} - -static int -arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - if (bit (insn, 25)) - switch (bits (insn, 20, 24)) - { - case 0x10: - return visitor->others (insn, "movw", data); - - case 0x14: - return visitor->others (insn, "movt", data); - - case 0x12: - case 0x16: - return visitor->others (insn, "msr imm", data); - - default: - return visitor->alu_imm (insn, data); - } - else - { - uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7); - - if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0) - return visitor->alu_reg (insn, data); - else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1) - return visitor->alu_shifted_reg (insn, data); - else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0) - return arm_decode_miscellaneous (insn, visitor, data); - else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8) - return visitor->others (insn, "halfword mul/mla", data); - else if ((op1 & 0x10) == 0x00 && op2 == 0x9) - return visitor->others (insn, "mul/mla", data); - else if ((op1 & 0x10) == 0x10 && op2 == 0x9) - return visitor->others (insn, "synch", data); - else if (op2 == 0xb || (op2 & 0xd) == 0xd) - /* 2nd arg means "unprivileged". */ - return visitor->extra_ld_st (insn, data, (op1 & 0x12) == 0x02); - } - - /* Should be unreachable. */ - return 1; -} - -static int -arm_decode_ld_st_word_ubyte (uint32_t insn, - struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - int a = bit (insn, 25), b = bit (insn, 4); - uint32_t op1 = bits (insn, 20, 24); - - if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02) - || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b)) - return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 0); - else if ((!a && (op1 & 0x17) == 0x02) - || (a && (op1 & 0x17) == 0x02 && !b)) - return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 1); - else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03) - || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b)) - return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 0); - else if ((!a && (op1 & 0x17) == 0x03) - || (a && (op1 & 0x17) == 0x03 && !b)) - return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 1); - else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06) - || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b)) - return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 0); - else if ((!a && (op1 & 0x17) == 0x06) - || (a && (op1 & 0x17) == 0x06 && !b)) - return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 1); - else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07) - || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b)) - return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 0); - else if ((!a && (op1 & 0x17) == 0x07) - || (a && (op1 & 0x17) == 0x07 && !b)) - return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 1); - - /* Should be unreachable. */ - return 1; -} - -static int -arm_decode_media (uint32_t insn, struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - switch (bits (insn, 20, 24)) - { - case 0x00: case 0x01: case 0x02: case 0x03: - return visitor->others (insn, "parallel add/sub signed", data); - - case 0x04: case 0x05: case 0x06: case 0x07: - return visitor->others (insn, "parallel add/sub unsigned", data); - - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - return visitor->others (insn, "decode/pack/unpack/saturate/reverse", - data); - - case 0x18: - if (bits (insn, 5, 7) == 0) /* op2. */ - { - if (bits (insn, 12, 15) == 0xf) - return visitor->others (insn, "usad8", data); - else - return visitor->others (insn, "usada8", data); - } - else - return visitor->undef (insn, data); - - case 0x1a: case 0x1b: - if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */ - return visitor->others (insn, "sbfx", data); - else - return visitor->undef (insn, data); - - case 0x1c: case 0x1d: - if (bits (insn, 5, 6) == 0x0) /* op2[1:0]. */ - { - if (bits (insn, 0, 3) == 0xf) - return visitor->others (insn, "bfc", data); - else - return visitor->others (insn, "bfi", data); - } - else - return visitor->undef (insn, data); - - case 0x1e: case 0x1f: - if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */ - return visitor->others (insn, "ubfx", data); - else - return visitor->undef (insn, data); - } - - /* Should be unreachable. */ - return 1; -} - -static int -arm_decode_b_bl_ldmstm (uint32_t insn, struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - if (bit (insn, 25)) - return visitor->b_bl_blx (insn, data); - else - return visitor->block_xfer (insn, data); -} - -static int -arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - unsigned int opcode = bits (insn, 20, 24); - - switch (opcode) - { - case 0x04: case 0x05: /* VFP/Neon mrrc/mcrr. */ - return visitor->others (insn, "vfp/neon mrrc/mcrr", data); - - case 0x08: case 0x0a: case 0x0c: case 0x0e: - case 0x12: case 0x16: - return visitor->others (insn, "vfp/neon vstm/vpush", data); - - case 0x09: case 0x0b: case 0x0d: case 0x0f: - case 0x13: case 0x17: - return visitor->others (insn, "vfp/neon vldm/vpop", data); - - case 0x10: case 0x14: case 0x18: case 0x1c: /* vstr. */ - case 0x11: case 0x15: case 0x19: case 0x1d: /* vldr. */ - /* Note: no writeback for these instructions. Bit 25 will always be - zero though (via caller), so the following works OK. */ - return visitor->copro_load_store (insn, data); - } - - /* Should be unreachable. */ - return 1; -} - /* Decode shifted register instructions. */ static int @@ -6949,51 +6559,6 @@ thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2, } static int -arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - unsigned int op1 = bits (insn, 20, 25); - int op = bit (insn, 4); - unsigned int coproc = bits (insn, 8, 11); - - if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa) - return arm_decode_ext_reg_ld_st (insn, visitor, data); - else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00 - && (coproc & 0xe) != 0xa) - /* stc/stc2. */ - return visitor->copro_load_store (insn, data); - else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00 - && (coproc & 0xe) != 0xa) - /* ldc/ldc2 imm/lit. */ - return visitor->copro_load_store (insn, data); - else if ((op1 & 0x3e) == 0x00) - return visitor->undef (insn, data); - else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa) - return visitor->others (insn, "neon 64bit xfer", data); - else if (op1 == 0x04 && (coproc & 0xe) != 0xa) - return visitor->others (insn, "mcrr/mcrr2", data); - else if (op1 == 0x05 && (coproc & 0xe) != 0xa) - return visitor->others (insn, "mrrc/mrrc2", data); - else if ((op1 & 0x30) == 0x20 && !op) - { - if ((coproc & 0xe) == 0xa) - return visitor->others (insn, "vfp dataproc", data); - else - return visitor->others (insn, "cdp/cdp2", data); - } - else if ((op1 & 0x30) == 0x20 && op) - return visitor->others (insn, "neon 8/16/32 bit xfer", data); - else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa) - return visitor->others (insn, "mcr/mcr2", data); - else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa) - return visitor->others (insn, "mrc/mrc2", data); - else if ((op1 & 0x30) == 0x30) - return visitor->svc (insn, data); - else - return visitor->undef (insn, data); /* Possibly unreachable. */ -} - -static int thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2, struct thumb_32bit_insn_reloc_visitor *visitor, struct arm_insn_reloc_data *data) @@ -7614,40 +7179,6 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2, } -static int -arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_visitor *visitor, - struct arm_insn_reloc_data *data) -{ - int err = 1; - - if ((insn & 0xf0000000) == 0xf0000000) - err = arm_decode_unconditional (insn, visitor, data); - else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24)) - { - case 0x0: case 0x1: case 0x2: case 0x3: - err = arm_decode_dp_misc (insn, visitor, data); - break; - - case 0x4: case 0x5: case 0x6: - err = arm_decode_ld_st_word_ubyte (insn, visitor, data); - break; - - case 0x7: - err = arm_decode_media (insn, visitor, data); - break; - - case 0x8: case 0x9: case 0xa: case 0xb: - err = arm_decode_b_bl_ldmstm (insn, visitor, data); - break; - - case 0xc: case 0xd: case 0xe: case 0xf: - err = arm_decode_svc_copro (insn, visitor, data); - break; - } - - return err; -} - static struct arm_insn_reloc_visitor arm_insn_reloc_visitor = { arm_copy_alu_imm, diff --git a/gdb/configure.tgt b/gdb/configure.tgt index cd8e05d..b33d76d 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -91,7 +91,7 @@ arm*-wince-pe | arm*-*-mingw32ce*) ;; arm*-*-linux*) # Target: ARM based machine running GNU/Linux - gdb_target_obs="arm.o arm-linux.o arm-get-next-pcs.o arm-tdep.o \ + gdb_target_obs="arm.o arm-linux.o arm-get-next-pcs.o arm-insn-reloc.o arm-tdep.o \ arm-linux-tdep.o glibc-tdep.o \ solib-svr4.o symfile-mem.o linux-tdep.o linux-record.o" build_gdbserver=yes