* [RFC] patch to refactor ppc64 specific code from ppc-linux-tdep @ 2012-12-27 21:36 Andreas Tobler 2013-01-19 13:46 ` Andreas Tobler 2013-01-21 15:50 ` Pedro Alves 0 siblings, 2 replies; 6+ messages in thread From: Andreas Tobler @ 2012-12-27 21:36 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: Type: text/plain, Size: 1714 bytes --] Hi all, in order to avoid code duplication for the FreeBSD powerpc port I started to cut off common code from ppc-linux-tdep.c into a new file to be used for FreeBSD and GNU/Linux PowerPC 64-bit. The file name is open so far. Better namings are welcome. Attached my first attempt, tested on GNU/Linux ppc64, Fedora 17 and on x86_64-*freebsd* with --eanble-targets=all. On the Linux side I do not see any regression. So far I have only covered functions which I can use on FreeBSD powerpc64. There might be others too but I do not see any for now. I'd appreciate comments, corrections. TIA, Andreas 2012-12-19 Andreas Tobler <andreast@neon.andreas.nets> * Makefile.in (ALL_TARGET_OBS): Add new file ppc64-common-tdep.o (HFILES_NO_SRCDIR): Likewise. (ALLDEPFILES): Likewise. * configure.tgt: Add new file for powerpc-linux. * ppc64-common-tdep.h: New file. * ppc64-common-tdep.c New file. (insn_d, insn_ds, insn_xfx, read_insn) (insns_match_pattern, insn_d_field, insn_ds_field) (ppc64_desc_entry_point): Move from ppc-linux-tdep.c to here. (PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN) (PPC64_STANDARD_LINKAGE2_LEN): Likewise and use ARRAY_SIZE macro. (ppc64_standard_linkage1_target, ppc64_standard_linkage2_target) (ppc64_standard_linkage3_target, ppc64_skip_trampoline_code): Move from ppc-linux-tdep.c to here. (ppc64_convert_from_func_ptr_addr): Rename it from ppc64_linux_convert_from_func_ptr_addr to ppc64_convert_from_func_ptr_addr and move it from ppc-linux-tdep.c to here. * ppc-linux-tdep.c: Include ppc64-common-tdep.h. Removed above functions. (ppc_linux_init_abi): Rename ppc64_linux_convert_from_func_ptr_addr to ppc64_linux_convert_from_func_ptr_addr. [-- Attachment #2: ppc64_common.diff --] [-- Type: text/plain, Size: 35203 bytes --] diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5ded1a5..0987f00 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -563,7 +563,7 @@ ALL_TARGET_OBS = \ mt-tdep.o \ nto-tdep.o \ ppc-linux-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o ppc-sysv-tdep.o \ - rl78-tdep.o \ + ppc64-common-tdep.o rl78-tdep.o \ rs6000-aix-tdep.o rs6000-tdep.o ppc-ravenscar-thread.o \ rs6000-lynx178-tdep.o \ rx-tdep.o \ @@ -804,7 +804,8 @@ amd64-linux-tdep.h linespec.h i387-tdep.h mn10300-tdep.h \ sparc64-tdep.h monitor.h ppcobsd-tdep.h srec.h solib-pa64.h \ coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \ m68k-tdep.h spu-tdep.h jv-lang.h environ.h solib-irix.h amd64-tdep.h \ -doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h rs6000-tdep.h \ +doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-common-tdep.h \ +rs6000-tdep.h \ common/gdb_locale.h common/gdb_dirent.h arch-utils.h trad-frame.h gnu-nat.h \ language.h nbsd-tdep.h solib-svr4.h \ macroexp.h ui-file.h regcache.h gdb_string.h tracepoint.h i386-tdep.h \ @@ -1479,7 +1480,7 @@ ALLDEPFILES = \ solib-osf.c \ somread.c solib-som.c \ posix-hdep.c \ - ppc-sysv-tdep.c ppc-linux-nat.c ppc-linux-tdep.c \ + ppc-sysv-tdep.c ppc-linux-nat.c ppc-linux-tdep.c ppc64-common-tdep.c \ ppcnbsd-nat.c ppcnbsd-tdep.c \ ppcobsd-nat.c ppcobsd-tdep.c \ procfs.c \ diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 5b77bb2..dca490d 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -405,7 +405,8 @@ powerpc-*-aix* | rs6000-*-*) powerpc-*-linux* | powerpc64-*-linux*) # Target: PowerPC running Linux gdb_target_obs="rs6000-tdep.o ppc-linux-tdep.o ppc-sysv-tdep.o \ - solib-svr4.o solib-spu.o spu-multiarch.o \ + ppc64-common-tdep.o solib-svr4.o solib-spu.o \ + spu-multiarch.o \ glibc-tdep.o symfile-mem.o linux-tdep.o \ ravenscar-thread.o ppc-ravenscar-thread.o" gdb_sim=../sim/ppc/libsim.a diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index f88d697..f3dec40 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -37,6 +37,7 @@ #include "solist.h" #include "ppc-tdep.h" #include "ppc-linux-tdep.h" +#include "ppc64-common-tdep.h" #include "glibc-tdep.h" #include "trad-frame.h" #include "frame-unwind.h" @@ -255,277 +256,6 @@ ppc_linux_return_value (struct gdbarch *gdbarch, struct value *function, readbuf, writebuf); } -/* Macros for matching instructions. Note that, since all the - operands are masked off before they're or-ed into the instruction, - you can use -1 to make masks. */ - -#define insn_d(opcd, rts, ra, d) \ - ((((opcd) & 0x3f) << 26) \ - | (((rts) & 0x1f) << 21) \ - | (((ra) & 0x1f) << 16) \ - | ((d) & 0xffff)) - -#define insn_ds(opcd, rts, ra, d, xo) \ - ((((opcd) & 0x3f) << 26) \ - | (((rts) & 0x1f) << 21) \ - | (((ra) & 0x1f) << 16) \ - | ((d) & 0xfffc) \ - | ((xo) & 0x3)) - -#define insn_xfx(opcd, rts, spr, xo) \ - ((((opcd) & 0x3f) << 26) \ - | (((rts) & 0x1f) << 21) \ - | (((spr) & 0x1f) << 16) \ - | (((spr) & 0x3e0) << 6) \ - | (((xo) & 0x3ff) << 1)) - -/* Read a PPC instruction from memory. PPC instructions are always - big-endian, no matter what endianness the program is running in, so - we can't use read_memory_integer or one of its friends here. */ -static unsigned int -read_insn (CORE_ADDR pc) -{ - unsigned char buf[4]; - - read_memory (pc, buf, 4); - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; -} - - -/* An instruction to match. */ -struct insn_pattern -{ - unsigned int mask; /* mask the insn with this... */ - unsigned int data; /* ...and see if it matches this. */ - int optional; /* If non-zero, this insn may be absent. */ -}; - -/* Return non-zero if the instructions at PC match the series - described in PATTERN, or zero otherwise. PATTERN is an array of - 'struct insn_pattern' objects, terminated by an entry whose mask is - zero. - - When the match is successful, fill INSN[i] with what PATTERN[i] - matched. If PATTERN[i] is optional, and the instruction wasn't - present, set INSN[i] to 0 (which is not a valid PPC instruction). - INSN should have as many elements as PATTERN. Note that, if - PATTERN contains optional instructions which aren't present in - memory, then INSN will have holes, so INSN[i] isn't necessarily the - i'th instruction in memory. */ -static int -insns_match_pattern (CORE_ADDR pc, - struct insn_pattern *pattern, - unsigned int *insn) -{ - int i; - - for (i = 0; pattern[i].mask; i++) - { - insn[i] = read_insn (pc); - if ((insn[i] & pattern[i].mask) == pattern[i].data) - pc += 4; - else if (pattern[i].optional) - insn[i] = 0; - else - return 0; - } - - return 1; -} - - -/* Return the 'd' field of the d-form instruction INSN, properly - sign-extended. */ -static CORE_ADDR -insn_d_field (unsigned int insn) -{ - return ((((CORE_ADDR) insn & 0xffff) ^ 0x8000) - 0x8000); -} - - -/* Return the 'ds' field of the ds-form instruction INSN, with the two - zero bits concatenated at the right, and properly - sign-extended. */ -static CORE_ADDR -insn_ds_field (unsigned int insn) -{ - return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000); -} - - -/* If DESC is the address of a 64-bit PowerPC GNU/Linux function - descriptor, return the descriptor's entry point. */ -static CORE_ADDR -ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - /* The first word of the descriptor is the entry point. */ - return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order); -} - - -/* Pattern for the standard linkage function. These are built by - build_plt_stub in elf64-ppc.c, whose GLINK argument is always - zero. */ -static struct insn_pattern ppc64_standard_linkage1[] = - { - /* addis r12, r2, <any> */ - { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, - - /* std r2, 40(r1) */ - { -1, insn_ds (62, 2, 1, 40, 0), 0 }, - - /* ld r11, <any>(r12) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, - - /* addis r12, r12, 1 <optional> */ - { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, - - /* ld r2, <any>(r12) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, - - /* addis r12, r12, 1 <optional> */ - { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, - - /* mtctr r11 */ - { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, - - /* ld r11, <any>(r12) <optional> */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, - - /* bctr */ - { -1, 0x4e800420, 0 }, - - { 0, 0, 0 } - }; -#define PPC64_STANDARD_LINKAGE1_LEN \ - (sizeof (ppc64_standard_linkage1) / sizeof (ppc64_standard_linkage1[0])) - -static struct insn_pattern ppc64_standard_linkage2[] = - { - /* addis r12, r2, <any> */ - { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, - - /* std r2, 40(r1) */ - { -1, insn_ds (62, 2, 1, 40, 0), 0 }, - - /* ld r11, <any>(r12) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, - - /* addi r12, r12, <any> <optional> */ - { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 }, - - /* mtctr r11 */ - { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, - - /* ld r2, <any>(r12) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, - - /* ld r11, <any>(r12) <optional> */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, - - /* bctr */ - { -1, 0x4e800420, 0 }, - - { 0, 0, 0 } - }; -#define PPC64_STANDARD_LINKAGE2_LEN \ - (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0])) - -static struct insn_pattern ppc64_standard_linkage3[] = - { - /* std r2, 40(r1) */ - { -1, insn_ds (62, 2, 1, 40, 0), 0 }, - - /* ld r11, <any>(r2) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 }, - - /* addi r2, r2, <any> <optional> */ - { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 }, - - /* mtctr r11 */ - { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, - - /* ld r11, <any>(r2) <optional> */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 }, - - /* ld r2, <any>(r2) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 }, - - /* bctr */ - { -1, 0x4e800420, 0 }, - - { 0, 0, 0 } - }; -#define PPC64_STANDARD_LINKAGE3_LEN \ - (sizeof (ppc64_standard_linkage3) / sizeof (ppc64_standard_linkage3[0])) - - -/* When the dynamic linker is doing lazy symbol resolution, the first - call to a function in another object will go like this: - - - The user's function calls the linkage function: - - 100007c4: 4b ff fc d5 bl 10000498 - 100007c8: e8 41 00 28 ld r2,40(r1) - - - The linkage function loads the entry point (and other stuff) from - the function descriptor in the PLT, and jumps to it: - - 10000498: 3d 82 00 00 addis r12,r2,0 - 1000049c: f8 41 00 28 std r2,40(r1) - 100004a0: e9 6c 80 98 ld r11,-32616(r12) - 100004a4: e8 4c 80 a0 ld r2,-32608(r12) - 100004a8: 7d 69 03 a6 mtctr r11 - 100004ac: e9 6c 80 a8 ld r11,-32600(r12) - 100004b0: 4e 80 04 20 bctr - - - But since this is the first time that PLT entry has been used, it - sends control to its glink entry. That loads the number of the - PLT entry and jumps to the common glink0 code: - - 10000c98: 38 00 00 00 li r0,0 - 10000c9c: 4b ff ff dc b 10000c78 - - - The common glink0 code then transfers control to the dynamic - linker's fixup code: - - 10000c78: e8 41 00 28 ld r2,40(r1) - 10000c7c: 3d 82 00 00 addis r12,r2,0 - 10000c80: e9 6c 80 80 ld r11,-32640(r12) - 10000c84: e8 4c 80 88 ld r2,-32632(r12) - 10000c88: 7d 69 03 a6 mtctr r11 - 10000c8c: e9 6c 80 90 ld r11,-32624(r12) - 10000c90: 4e 80 04 20 bctr - - Eventually, this code will figure out how to skip all of this, - including the dynamic linker. At the moment, we just get through - the linkage function. */ - -/* If the current thread is about to execute a series of instructions - at PC matching the ppc64_standard_linkage pattern, and INSN is the result - from that pattern match, return the code address to which the - standard linkage function will send them. (This doesn't deal with - dynamic linker lazy symbol resolution stubs.) */ -static CORE_ADDR -ppc64_standard_linkage1_target (struct frame_info *frame, - CORE_ADDR pc, unsigned int *insn) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - /* The address of the function descriptor this linkage function - references. */ - CORE_ADDR desc - = ((CORE_ADDR) get_frame_register_unsigned (frame, - tdep->ppc_gp0_regnum + 2) - + (insn_d_field (insn[0]) << 16) - + insn_ds_field (insn[2])); - - /* The first word of the descriptor is the entry point. Return that. */ - return ppc64_desc_entry_point (gdbarch, desc); -} - static struct core_regset_section ppc_linux_vsx_regset_sections[] = { { ".reg", 48 * 4, "general-purpose" }, @@ -574,43 +304,6 @@ static struct core_regset_section ppc64_linux_fp_regset_sections[] = { NULL, 0} }; -static CORE_ADDR -ppc64_standard_linkage2_target (struct frame_info *frame, - CORE_ADDR pc, unsigned int *insn) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - /* The address of the function descriptor this linkage function - references. */ - CORE_ADDR desc - = ((CORE_ADDR) get_frame_register_unsigned (frame, - tdep->ppc_gp0_regnum + 2) - + (insn_d_field (insn[0]) << 16) - + insn_ds_field (insn[2])); - - /* The first word of the descriptor is the entry point. Return that. */ - return ppc64_desc_entry_point (gdbarch, desc); -} - -static CORE_ADDR -ppc64_standard_linkage3_target (struct frame_info *frame, - CORE_ADDR pc, unsigned int *insn) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - /* The address of the function descriptor this linkage function - references. */ - CORE_ADDR desc - = ((CORE_ADDR) get_frame_register_unsigned (frame, - tdep->ppc_gp0_regnum + 2) - + insn_ds_field (insn[1])); - - /* The first word of the descriptor is the entry point. Return that. */ - return ppc64_desc_entry_point (gdbarch, desc); -} - /* PLT stub in executable. */ static struct insn_pattern powerpc32_plt_stub[] = { @@ -692,109 +385,6 @@ ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) return target; } -/* Given that we've begun executing a call trampoline at PC, return - the entry point of the function the trampoline will go to. */ -static CORE_ADDR -ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) -{ - unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN]; - unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN]; - unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN]; - CORE_ADDR target; - - if (insns_match_pattern (pc, ppc64_standard_linkage1, - ppc64_standard_linkage1_insn)) - pc = ppc64_standard_linkage1_target (frame, pc, - ppc64_standard_linkage1_insn); - else if (insns_match_pattern (pc, ppc64_standard_linkage2, - ppc64_standard_linkage2_insn)) - pc = ppc64_standard_linkage2_target (frame, pc, - ppc64_standard_linkage2_insn); - else if (insns_match_pattern (pc, ppc64_standard_linkage3, - ppc64_standard_linkage3_insn)) - pc = ppc64_standard_linkage3_target (frame, pc, - ppc64_standard_linkage3_insn); - else - return 0; - - /* The PLT descriptor will either point to the already resolved target - address, or else to a glink stub. As the latter carry synthetic @plt - symbols, find_solib_trampoline_target should be able to resolve them. */ - target = find_solib_trampoline_target (frame, pc); - return target? target : pc; -} - - -/* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC64 - GNU/Linux. - - Usually a function pointer's representation is simply the address - of the function. On GNU/Linux on the PowerPC however, a function - pointer may be a pointer to a function descriptor. - - For PPC64, a function descriptor is a TOC entry, in a data section, - which contains three words: the first word is the address of the - function, the second word is the TOC pointer (r2), and the third word - is the static chain value. - - Throughout GDB it is currently assumed that a function pointer contains - the address of the function, which is not easy to fix. In addition, the - conversion of a function address to a function pointer would - require allocation of a TOC entry in the inferior's memory space, - with all its drawbacks. To be able to call C++ virtual methods in - the inferior (which are called via function pointers), - find_function_addr uses this function to get the function address - from a function pointer. - - If ADDR points at what is clearly a function descriptor, transform - it into the address of the corresponding function, if needed. Be - conservative, otherwise GDB will do the transformation on any - random addresses such as occur when there is no symbol table. */ - -static CORE_ADDR -ppc64_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch, - CORE_ADDR addr, - struct target_ops *targ) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct target_section *s = target_section_by_addr (targ, addr); - - /* Check if ADDR points to a function descriptor. */ - if (s && strcmp (s->the_bfd_section->name, ".opd") == 0) - { - /* There may be relocations that need to be applied to the .opd - section. Unfortunately, this function may be called at a time - where these relocations have not yet been performed -- this can - happen for example shortly after a library has been loaded with - dlopen, but ld.so has not yet applied the relocations. - - To cope with both the case where the relocation has been applied, - and the case where it has not yet been applied, we do *not* read - the (maybe) relocated value from target memory, but we instead - read the non-relocated value from the BFD, and apply the relocation - offset manually. - - This makes the assumption that all .opd entries are always relocated - by the same offset the section itself was relocated. This should - always be the case for GNU/Linux executables and shared libraries. - Note that other kind of object files (e.g. those added via - add-symbol-files) will currently never end up here anyway, as this - function accesses *target* sections only; only the main exec and - shared libraries are ever added to the target. */ - - gdb_byte buf[8]; - int res; - - res = bfd_get_section_contents (s->bfd, s->the_bfd_section, - &buf, addr - s->addr, 8); - if (res != 0) - return extract_unsigned_integer (buf, 8, byte_order) - - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr; - } - - return addr; -} - /* Wrappers to handle Linux-only registers. */ static void @@ -1743,7 +1333,7 @@ ppc_linux_init_abi (struct gdbarch_info info, /* Handle PPC GNU/Linux 64-bit function pointers (which are really function descriptors). */ set_gdbarch_convert_from_func_ptr_addr - (gdbarch, ppc64_linux_convert_from_func_ptr_addr); + (gdbarch, ppc64_convert_from_func_ptr_addr); /* Shared library handling. */ set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code); diff --git a/gdb/ppc64-common-tdep.c b/gdb/ppc64-common-tdep.c new file mode 100644 index 0000000..ee53ce9 --- /dev/null +++ b/gdb/ppc64-common-tdep.c @@ -0,0 +1,426 @@ +/* Common target-dependent code for ppc64 GDB, the GNU debugger. + + Copyright (C) 2012 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 <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "frame.h" +#include "gdbcore.h" +#include "ppc-tdep.h" +#include "ppc64-common-tdep.h" + +/* Macros for matching instructions. Note that, since all the + operands are masked off before they're or-ed into the instruction, + you can use -1 to make masks. */ + +#define insn_d(opcd, rts, ra, d) \ + ((((opcd) & 0x3f) << 26) \ + | (((rts) & 0x1f) << 21) \ + | (((ra) & 0x1f) << 16) \ + | ((d) & 0xffff)) + +#define insn_ds(opcd, rts, ra, d, xo) \ + ((((opcd) & 0x3f) << 26) \ + | (((rts) & 0x1f) << 21) \ + | (((ra) & 0x1f) << 16) \ + | ((d) & 0xfffc) \ + | ((xo) & 0x3)) + +#define insn_xfx(opcd, rts, spr, xo) \ + ((((opcd) & 0x3f) << 26) \ + | (((rts) & 0x1f) << 21) \ + | (((spr) & 0x1f) << 16) \ + | (((spr) & 0x3e0) << 6) \ + | (((xo) & 0x3ff) << 1)) + +/* Read a PPC instruction from memory. PPC instructions are always + big-endian, no matter what endianness the program is running in, so + we can hardcode BFD_ENDIAN_BIG for read_memory_unsigned_integer. */ + +static unsigned int +read_insn (CORE_ADDR pc) +{ + return read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG); +} + +/* Return non-zero if the instructions at PC match the series + described in PATTERN, or zero otherwise. PATTERN is an array of + 'struct insn_pattern' objects, terminated by an entry whose mask is + zero. + + When the match is successful, fill INSN[i] with what PATTERN[i] + matched. If PATTERN[i] is optional, and the instruction wasn't + present, set INSN[i] to 0 (which is not a valid PPC instruction). + INSN should have as many elements as PATTERN. Note that, if + PATTERN contains optional instructions which aren't present in + memory, then INSN will have holes, so INSN[i] isn't necessarily the + i'th instruction in memory. */ + +int +insns_match_pattern (CORE_ADDR pc, struct insn_pattern *pattern, + unsigned int *insn) +{ + int i; + + for (i = 0; pattern[i].mask; i++) + { + insn[i] = read_insn (pc); + if ((insn[i] & pattern[i].mask) == pattern[i].data) + pc += 4; + else if (pattern[i].optional) + insn[i] = 0; + else + return 0; + } + + return 1; +} + +/* Return the 'd' field of the d-form instruction INSN, properly + sign-extended. */ + +CORE_ADDR +insn_d_field (unsigned int insn) +{ + return ((((CORE_ADDR) insn & 0xffff) ^ 0x8000) - 0x8000); +} + +/* Return the 'ds' field of the ds-form instruction INSN, with the two + zero bits concatenated at the right, and properly + sign-extended. */ + +static CORE_ADDR +insn_ds_field (unsigned int insn) +{ + return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000); +} + +/* If DESC is the address of a 64-bit PowerPC FreeBSD function + descriptor, return the descriptor's entry point. */ + +static CORE_ADDR +ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + /* The first word of the descriptor is the entry point. */ + return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order); +} + +/* Pattern for the standard linkage function. These are built by + build_plt_stub in elf64-ppc.c, whose GLINK argument is always + zero. */ + +static struct insn_pattern ppc64_standard_linkage1[] = + { + /* addis r12, r2, <any> */ + { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, + + /* std r2, 40(r1) */ + { -1, insn_ds (62, 2, 1, 40, 0), 0 }, + + /* ld r11, <any>(r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, + + /* addis r12, r12, 1 <optional> */ + { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, + + /* ld r2, <any>(r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, + + /* addis r12, r12, 1 <optional> */ + { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, + + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + + /* ld r11, <any>(r12) <optional> */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, + + /* bctr */ + { -1, 0x4e800420, 0 }, + + { 0, 0, 0 } + }; + +#define PPC64_STANDARD_LINKAGE1_LEN ARRAY_SIZE (ppc64_standard_linkage1) + +static struct insn_pattern ppc64_standard_linkage2[] = + { + /* addis r12, r2, <any> */ + { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, + + /* std r2, 40(r1) */ + { -1, insn_ds (62, 2, 1, 40, 0), 0 }, + + /* ld r11, <any>(r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, + + /* addi r12, r12, <any> <optional> */ + { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 }, + + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + + /* ld r2, <any>(r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, + + /* ld r11, <any>(r12) <optional> */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, + + /* bctr */ + { -1, 0x4e800420, 0 }, + + { 0, 0, 0 } + }; + +#define PPC64_STANDARD_LINKAGE2_LEN ARRAY_SIZE (ppc64_standard_linkage2) + +static struct insn_pattern ppc64_standard_linkage3[] = + { + /* std r2, 40(r1) */ + { -1, insn_ds (62, 2, 1, 40, 0), 0 }, + + /* ld r11, <any>(r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 }, + + /* addi r2, r2, <any> <optional> */ + { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 }, + + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + + /* ld r11, <any>(r2) <optional> */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 }, + + /* ld r2, <any>(r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 }, + + /* bctr */ + { -1, 0x4e800420, 0 }, + + { 0, 0, 0 } + }; + +#define PPC64_STANDARD_LINKAGE3_LEN ARRAY_SIZE (ppc64_standard_linkage3) + +/* When the dynamic linker is doing lazy symbol resolution, the first + call to a function in another object will go like this: + + - The user's function calls the linkage function: + + 100007c4: 4b ff fc d5 bl 10000498 + 100007c8: e8 41 00 28 ld r2,40(r1) + + - The linkage function loads the entry point (and other stuff) from + the function descriptor in the PLT, and jumps to it: + + 10000498: 3d 82 00 00 addis r12,r2,0 + 1000049c: f8 41 00 28 std r2,40(r1) + 100004a0: e9 6c 80 98 ld r11,-32616(r12) + 100004a4: e8 4c 80 a0 ld r2,-32608(r12) + 100004a8: 7d 69 03 a6 mtctr r11 + 100004ac: e9 6c 80 a8 ld r11,-32600(r12) + 100004b0: 4e 80 04 20 bctr + + - But since this is the first time that PLT entry has been used, it + sends control to its glink entry. That loads the number of the + PLT entry and jumps to the common glink0 code: + + 10000c98: 38 00 00 00 li r0,0 + 10000c9c: 4b ff ff dc b 10000c78 + + - The common glink0 code then transfers control to the dynamic + linker's fixup code: + + 10000c78: e8 41 00 28 ld r2,40(r1) + 10000c7c: 3d 82 00 00 addis r12,r2,0 + 10000c80: e9 6c 80 80 ld r11,-32640(r12) + 10000c84: e8 4c 80 88 ld r2,-32632(r12) + 10000c88: 7d 69 03 a6 mtctr r11 + 10000c8c: e9 6c 80 90 ld r11,-32624(r12) + 10000c90: 4e 80 04 20 bctr + + Eventually, this code will figure out how to skip all of this, + including the dynamic linker. At the moment, we just get through + the linkage function. */ + +/* If the current thread is about to execute a series of instructions + at PC matching the ppc64_standard_linkage pattern, and INSN is the result + from that pattern match, return the code address to which the + standard linkage function will send them. (This doesn't deal with + dynamic linker lazy symbol resolution stubs.) */ + +static CORE_ADDR +ppc64_standard_linkage1_target (struct frame_info *frame, + CORE_ADDR pc, unsigned int *insn) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* The address of the function descriptor this linkage function + references. */ + CORE_ADDR desc + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + (insn_d_field (insn[0]) << 16) + + insn_ds_field (insn[2])); + + /* The first word of the descriptor is the entry point. Return that. */ + return ppc64_desc_entry_point (gdbarch, desc); +} + +static CORE_ADDR +ppc64_standard_linkage2_target (struct frame_info *frame, + CORE_ADDR pc, unsigned int *insn) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* The address of the function descriptor this linkage function + references. */ + CORE_ADDR desc + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + (insn_d_field (insn[0]) << 16) + + insn_ds_field (insn[2])); + + /* The first word of the descriptor is the entry point. Return that. */ + return ppc64_desc_entry_point (gdbarch, desc); +} + +static CORE_ADDR +ppc64_standard_linkage3_target (struct frame_info *frame, + CORE_ADDR pc, unsigned int *insn) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* The address of the function descriptor this linkage function + references. */ + CORE_ADDR desc + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + insn_ds_field (insn[1])); + + /* The first word of the descriptor is the entry point. Return that. */ + return ppc64_desc_entry_point (gdbarch, desc); +} + + +/* Given that we've begun executing a call trampoline at PC, return + the entry point of the function the trampoline will go to. */ + +CORE_ADDR +ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +{ + unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN]; + unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN]; + unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN]; + CORE_ADDR target; + + if (insns_match_pattern (pc, ppc64_standard_linkage1, + ppc64_standard_linkage1_insn)) + pc = ppc64_standard_linkage1_target (frame, pc, + ppc64_standard_linkage1_insn); + else if (insns_match_pattern (pc, ppc64_standard_linkage2, + ppc64_standard_linkage2_insn)) + pc = ppc64_standard_linkage2_target (frame, pc, + ppc64_standard_linkage2_insn); + else if (insns_match_pattern (pc, ppc64_standard_linkage3, + ppc64_standard_linkage3_insn)) + pc = ppc64_standard_linkage3_target (frame, pc, + ppc64_standard_linkage3_insn); + else + return 0; + + /* The PLT descriptor will either point to the already resolved target + address, or else to a glink stub. As the latter carry synthetic @plt + symbols, find_solib_trampoline_target should be able to resolve them. */ + target = find_solib_trampoline_target (frame, pc); + return target ? target : pc; +} + +/* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC64 + GNU/Linux. + + Usually a function pointer's representation is simply the address + of the function. On GNU/Linux on the PowerPC however, a function + pointer may be a pointer to a function descriptor. + + For PPC64, a function descriptor is a TOC entry, in a data section, + which contains three words: the first word is the address of the + function, the second word is the TOC pointer (r2), and the third word + is the static chain value. + + Throughout GDB it is currently assumed that a function pointer contains + the address of the function, which is not easy to fix. In addition, the + conversion of a function address to a function pointer would + require allocation of a TOC entry in the inferior's memory space, + with all its drawbacks. To be able to call C++ virtual methods in + the inferior (which are called via function pointers), + find_function_addr uses this function to get the function address + from a function pointer. + + If ADDR points at what is clearly a function descriptor, transform + it into the address of the corresponding function, if needed. Be + conservative, otherwise GDB will do the transformation on any + random addresses such as occur when there is no symbol table. */ + +CORE_ADDR +ppc64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, + CORE_ADDR addr, + struct target_ops *targ) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct target_section *s = target_section_by_addr (targ, addr); + + /* Check if ADDR points to a function descriptor. */ + if (s && strcmp (s->the_bfd_section->name, ".opd") == 0) + { + /* There may be relocations that need to be applied to the .opd + section. Unfortunately, this function may be called at a time + where these relocations have not yet been performed -- this can + happen for example shortly after a library has been loaded with + dlopen, but ld.so has not yet applied the relocations. + + To cope with both the case where the relocation has been applied, + and the case where it has not yet been applied, we do *not* read + the (maybe) relocated value from target memory, but we instead + read the non-relocated value from the BFD, and apply the relocation + offset manually. + + This makes the assumption that all .opd entries are always relocated + by the same offset the section itself was relocated. This should + always be the case for GNU/Linux executables and shared libraries. + Note that other kind of object files (e.g. those added via + add-symbol-files) will currently never end up here anyway, as this + function accesses *target* sections only; only the main exec and + shared libraries are ever added to the target. */ + + gdb_byte buf[8]; + int res; + + res = bfd_get_section_contents (s->bfd, s->the_bfd_section, + &buf, addr - s->addr, 8); + if (res != 0) + return extract_unsigned_integer (buf, 8, byte_order) + - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr; + } + + return addr; +} diff --git a/gdb/ppc64-common-tdep.h b/gdb/ppc64-common-tdep.h new file mode 100644 index 0000000..57fe8de --- /dev/null +++ b/gdb/ppc64-common-tdep.h @@ -0,0 +1,49 @@ +/* Common target-dependent code for ppc64. + + Copyright (C) 2012 + 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 <http://www.gnu.org/licenses/>. */ + +#ifndef PPC64_COMMON_TDEP_H +#define PPC64_COMMON_TDEP_H + +/* An instruction to match. */ + +struct insn_pattern +{ + unsigned int mask; /* mask the insn with this... */ + unsigned int data; /* ...and see if it matches this. */ + int optional; /* If non-zero, this insn may be absent. */ +}; + +struct gdbarch; +struct frame_info; +struct target_ops; + +int +insns_match_pattern (CORE_ADDR pc, struct insn_pattern *pattern, + unsigned int *insn); +CORE_ADDR +insn_d_field (unsigned int insn); + +CORE_ADDR +ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc); +CORE_ADDR +ppc64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, + CORE_ADDR addr, struct target_ops *targ); + +#endif /* PPC64_COMMON_TDEP_H */ ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] patch to refactor ppc64 specific code from ppc-linux-tdep 2012-12-27 21:36 [RFC] patch to refactor ppc64 specific code from ppc-linux-tdep Andreas Tobler @ 2013-01-19 13:46 ` Andreas Tobler 2013-01-21 15:50 ` Pedro Alves 1 sibling, 0 replies; 6+ messages in thread From: Andreas Tobler @ 2013-01-19 13:46 UTC (permalink / raw) To: gdb-patches Ping? Thanks, Andreas On 27.12.12 22:36, Andreas Tobler wrote: > Hi all, > > in order to avoid code duplication for the FreeBSD powerpc port I > started to cut off common code from ppc-linux-tdep.c into a new file to > be used for FreeBSD and GNU/Linux PowerPC 64-bit. The file name is open > so far. Better namings are welcome. > > Attached my first attempt, tested on GNU/Linux ppc64, Fedora 17 and on > x86_64-*freebsd* with --eanble-targets=all. On the Linux side I do not > see any regression. > So far I have only covered functions which I can use on FreeBSD > powerpc64. There might be others too but I do not see any for now. > > I'd appreciate comments, corrections. > > TIA, > Andreas > > 2012-12-19 Andreas Tobler <andreast@neon.andreas.nets> > > * Makefile.in (ALL_TARGET_OBS): Add new file ppc64-common-tdep.o > (HFILES_NO_SRCDIR): Likewise. > (ALLDEPFILES): Likewise. > * configure.tgt: Add new file for powerpc-linux. > * ppc64-common-tdep.h: New file. > * ppc64-common-tdep.c New file. > (insn_d, insn_ds, insn_xfx, read_insn) > (insns_match_pattern, insn_d_field, insn_ds_field) > (ppc64_desc_entry_point): Move from ppc-linux-tdep.c to here. > (PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN) > (PPC64_STANDARD_LINKAGE2_LEN): Likewise and use ARRAY_SIZE macro. > (ppc64_standard_linkage1_target, ppc64_standard_linkage2_target) > (ppc64_standard_linkage3_target, ppc64_skip_trampoline_code): Move > from ppc-linux-tdep.c to here. > (ppc64_convert_from_func_ptr_addr): Rename it from > ppc64_linux_convert_from_func_ptr_addr to > ppc64_convert_from_func_ptr_addr and move it from ppc-linux-tdep.c to > here. > * ppc-linux-tdep.c: Include ppc64-common-tdep.h. > Removed above functions. > (ppc_linux_init_abi): Rename > ppc64_linux_convert_from_func_ptr_addr to > ppc64_linux_convert_from_func_ptr_addr. > > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] patch to refactor ppc64 specific code from ppc-linux-tdep 2012-12-27 21:36 [RFC] patch to refactor ppc64 specific code from ppc-linux-tdep Andreas Tobler 2013-01-19 13:46 ` Andreas Tobler @ 2013-01-21 15:50 ` Pedro Alves 2013-01-26 16:24 ` Andreas Tobler 1 sibling, 1 reply; 6+ messages in thread From: Pedro Alves @ 2013-01-21 15:50 UTC (permalink / raw) To: Andreas Tobler; +Cc: gdb-patches Hi Andreas, On 12/27/2012 09:36 PM, Andreas Tobler wrote: > in order to avoid code duplication for the FreeBSD powerpc port I > started to cut off common code from ppc-linux-tdep.c into a new file to > be used for FreeBSD and GNU/Linux PowerPC 64-bit. The file name is open > so far. Better namings are welcome. Thanks for doing this. IMO, the "common" monitor is practically meaningless, and raises the question of what's different between ppc64-common-tdep.c, and an hypothetical ppc64-tdep.c, and/or the rs6000-tdep.c, as the second would be about common ppc64 bits, and the latter, extant, _is also_ about common ppc bits. IOW, if we need a new ppc function in the future that's be used by several OSs, how do we decide where it goes? "common" doesn't give any clue. So I'd suggest ppc64-linbsd-tdep.c, and/or rs6000-tdep.c/ppc64-tdep.c, for shared code that is not OS specific (yeah, rs6000-tdep.c is a misnomer nowadays). > > Attached my first attempt, tested on GNU/Linux ppc64, Fedora 17 and on > x86_64-*freebsd* with --eanble-targets=all. On the Linux side I do not > see any regression. > So far I have only covered functions which I can use on FreeBSD > powerpc64. There might be others too but I do not see any for now. > > I'd appreciate comments, corrections. > > TIA, > Andreas > > 2012-12-19 Andreas Tobler <andreast@neon.andreas.nets> > > * Makefile.in (ALL_TARGET_OBS): Add new file ppc64-common-tdep.o Missing period. > (HFILES_NO_SRCDIR): Likewise. > (ALLDEPFILES): Likewise. > * configure.tgt: Add new file for powerpc-linux. > * ppc64-common-tdep.h: New file. > * ppc64-common-tdep.c New file. > (insn_d, insn_ds, insn_xfx, read_insn) > (insns_match_pattern, insn_d_field, insn_ds_field) > (ppc64_desc_entry_point): Move from ppc-linux-tdep.c to here. > (PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN) > (PPC64_STANDARD_LINKAGE2_LEN): Likewise and use ARRAY_SIZE macro. > (ppc64_standard_linkage1_target, ppc64_standard_linkage2_target) > (ppc64_standard_linkage3_target, ppc64_skip_trampoline_code): Move > from ppc-linux-tdep.c to here. > (ppc64_convert_from_func_ptr_addr): Rename it from > ppc64_linux_convert_from_func_ptr_addr to > ppc64_convert_from_func_ptr_addr and move it from ppc-linux-tdep.c to > here. > * ppc-linux-tdep.c: Include ppc64-common-tdep.h. > Removed above functions. > (ppc_linux_init_abi): Rename > ppc64_linux_convert_from_func_ptr_addr to > ppc64_linux_convert_from_func_ptr_addr. > +/* An instruction to match. */ > + > +struct insn_pattern ... > + > +int > +insns_match_pattern (CORE_ADDR pc, struct insn_pattern *pattern, > + unsigned int *insn); > +CORE_ADDR > +insn_d_field (unsigned int insn); These look like basic architecture/instruction pattern matching. I suggest moving to ppc-tdep.h/rs6000-tdep.c instead. If we're making these extern, then it'd be good to add a "ppc_" or "ppc64_" prefix (could be a separate step). Also, GDB's convention is that the function name goes on the first column in function definitions only, not declarations, and that declarations in .h files get an explicit "extern". Otherwise looks fine to me. -- Pedro Alves ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] patch to refactor ppc64 specific code from ppc-linux-tdep 2013-01-21 15:50 ` Pedro Alves @ 2013-01-26 16:24 ` Andreas Tobler 2013-02-01 19:00 ` Pedro Alves 0 siblings, 1 reply; 6+ messages in thread From: Andreas Tobler @ 2013-01-26 16:24 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 3407 bytes --] Hi Pedro, On 21.01.13 16:49, Pedro Alves wrote: > On 12/27/2012 09:36 PM, Andreas Tobler wrote: > >> in order to avoid code duplication for the FreeBSD powerpc port I >> started to cut off common code from ppc-linux-tdep.c into a new file to >> be used for FreeBSD and GNU/Linux PowerPC 64-bit. The file name is open >> so far. Better namings are welcome. > > Thanks for doing this. > > IMO, the "common" monitor is practically meaningless, and raises the question > of what's different between ppc64-common-tdep.c, and > an hypothetical ppc64-tdep.c, and/or the rs6000-tdep.c, as the > second would be about common ppc64 bits, and the latter, extant, _is also_ > about common ppc bits. IOW, if we need a new ppc function in the future that's > be used by several OSs, how do we decide where it goes? "common" doesn't > give any clue. So I'd suggest ppc64-linbsd-tdep.c, and/or > rs6000-tdep.c/ppc64-tdep.c, for shared code that is not OS specific (yeah, > rs6000-tdep.c is a misnomer nowadays). First, thank you for the review. I attached a revised version of the patch including the CL below. I hope I matched your points. I decided to leave ppc64-linbsd-tdep.c away and use ppc64-tdep.c|h with the changes mentioned below to ppc-tdep.h/rs6000-tdep.c Tested on ppc64-linux and on FreeBSD amd64 with an --enable-targets=all. >> +/* An instruction to match. */ >> + >> +struct insn_pattern > ... >> + >> +int >> +insns_match_pattern (CORE_ADDR pc, struct insn_pattern *pattern, >> + unsigned int *insn); >> +CORE_ADDR >> +insn_d_field (unsigned int insn); > > These look like basic architecture/instruction pattern matching. > I suggest moving to ppc-tdep.h/rs6000-tdep.c instead. Done. > If we're making these extern, then it'd be good to add a "ppc_" or > "ppc64_" prefix (could be a separate step). Done with ppc_ since the instructions could be used on ppc and ppc64 > Also, GDB's convention is that the function name goes on the first > column in function definitions only, not declarations, and that > declarations in .h files get an explicit "extern". Done, not sure if I need the extern on ppc64-tdep.h too? > Otherwise looks fine to me. Again, thank you! Andreas 2013-01-26 Andreas Tobler <andreast@fgznet.ch> * Makefile.in (ALL_TARGET_OBS): Add new file ppc64-tdep.o. (HFILES_NO_SRCDIR): Likewise. (ALLDEPFILES): Likewise. * configure.tgt: Add new file for powerpc-linux. * ppc64-tdep.h: New file. * ppc64-tdep.c: New file. (insn_d, insn_ds, insn_xfx, ppc64_desc_entry_point): Move from ppc-linux-tdep.c to here. (PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN) (PPC64_STANDARD_LINKAGE2_LEN): Likewise and use ARRAY_SIZE macro. (ppc64_standard_linkage1_target, ppc64_standard_linkage2_target) (ppc64_standard_linkage3_target, ppc64_skip_trampoline_code): Move from ppc-linux-tdep.c to here. (ppc64_convert_from_func_ptr_addr): Rename it from ppc64_linux_convert_from_func_ptr_addr to ppc64_convert_from_func_ptr_addr and move it from ppc-linux-tdep.c to here. * rs6000-tdep.c: (read_insn): Move from ppc-linux-tdep.c to here. (insns_match_pattern, insn_d_field, insn_ds_field): Move from ppc-linux-tdep.c to here and rename them with the ppc_ prefix. * ppc-linux-tdep.c: Include ppc64-tdep.h. Removed above functions. (ppc_linux_init_abi): Rename ppc64_linux_convert_from_func_ptr_addr to ppc64_convert_from_func_ptr_addr. [-- Attachment #2: ppc64_tdep_1diff --] [-- Type: text/plain, Size: 37395 bytes --] diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 68d545e..e0e08ca 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -565,7 +565,7 @@ ALL_TARGET_OBS = \ mt-tdep.o \ nto-tdep.o \ ppc-linux-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o ppc-sysv-tdep.o \ - rl78-tdep.o \ + ppc64-tdep.o rl78-tdep.o \ rs6000-aix-tdep.o rs6000-tdep.o ppc-ravenscar-thread.o \ rs6000-lynx178-tdep.o \ rx-tdep.o \ @@ -807,7 +807,7 @@ amd64-linux-tdep.h linespec.h i387-tdep.h mn10300-tdep.h \ sparc64-tdep.h monitor.h ppcobsd-tdep.h srec.h solib-pa64.h \ coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \ m68k-tdep.h spu-tdep.h jv-lang.h environ.h solib-irix.h amd64-tdep.h \ -doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h rs6000-tdep.h \ +doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h rs6000-tdep.h \ common/gdb_locale.h common/gdb_dirent.h arch-utils.h trad-frame.h gnu-nat.h \ language.h nbsd-tdep.h solib-svr4.h \ macroexp.h ui-file.h regcache.h gdb_string.h tracepoint.h i386-tdep.h \ @@ -1487,7 +1487,7 @@ ALLDEPFILES = \ solib-osf.c \ somread.c solib-som.c \ posix-hdep.c \ - ppc-sysv-tdep.c ppc-linux-nat.c ppc-linux-tdep.c \ + ppc-sysv-tdep.c ppc-linux-nat.c ppc-linux-tdep.c ppc64-tdep.c \ ppcnbsd-nat.c ppcnbsd-tdep.c \ ppcobsd-nat.c ppcobsd-tdep.c \ procfs.c \ diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 5b77bb2..2b4eea0 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -405,7 +405,8 @@ powerpc-*-aix* | rs6000-*-*) powerpc-*-linux* | powerpc64-*-linux*) # Target: PowerPC running Linux gdb_target_obs="rs6000-tdep.o ppc-linux-tdep.o ppc-sysv-tdep.o \ - solib-svr4.o solib-spu.o spu-multiarch.o \ + ppc64-tdep.o solib-svr4.o solib-spu.o \ + spu-multiarch.o \ glibc-tdep.o symfile-mem.o linux-tdep.o \ ravenscar-thread.o ppc-ravenscar-thread.o" gdb_sim=../sim/ppc/libsim.a diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 135dc75..cdf362f 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -35,6 +35,7 @@ #include "solib.h" #include "solist.h" #include "ppc-tdep.h" +#include "ppc64-tdep.h" #include "ppc-linux-tdep.h" #include "glibc-tdep.h" #include "trad-frame.h" @@ -254,277 +255,6 @@ ppc_linux_return_value (struct gdbarch *gdbarch, struct value *function, readbuf, writebuf); } -/* Macros for matching instructions. Note that, since all the - operands are masked off before they're or-ed into the instruction, - you can use -1 to make masks. */ - -#define insn_d(opcd, rts, ra, d) \ - ((((opcd) & 0x3f) << 26) \ - | (((rts) & 0x1f) << 21) \ - | (((ra) & 0x1f) << 16) \ - | ((d) & 0xffff)) - -#define insn_ds(opcd, rts, ra, d, xo) \ - ((((opcd) & 0x3f) << 26) \ - | (((rts) & 0x1f) << 21) \ - | (((ra) & 0x1f) << 16) \ - | ((d) & 0xfffc) \ - | ((xo) & 0x3)) - -#define insn_xfx(opcd, rts, spr, xo) \ - ((((opcd) & 0x3f) << 26) \ - | (((rts) & 0x1f) << 21) \ - | (((spr) & 0x1f) << 16) \ - | (((spr) & 0x3e0) << 6) \ - | (((xo) & 0x3ff) << 1)) - -/* Read a PPC instruction from memory. PPC instructions are always - big-endian, no matter what endianness the program is running in, so - we can't use read_memory_integer or one of its friends here. */ -static unsigned int -read_insn (CORE_ADDR pc) -{ - unsigned char buf[4]; - - read_memory (pc, buf, 4); - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; -} - - -/* An instruction to match. */ -struct insn_pattern -{ - unsigned int mask; /* mask the insn with this... */ - unsigned int data; /* ...and see if it matches this. */ - int optional; /* If non-zero, this insn may be absent. */ -}; - -/* Return non-zero if the instructions at PC match the series - described in PATTERN, or zero otherwise. PATTERN is an array of - 'struct insn_pattern' objects, terminated by an entry whose mask is - zero. - - When the match is successful, fill INSN[i] with what PATTERN[i] - matched. If PATTERN[i] is optional, and the instruction wasn't - present, set INSN[i] to 0 (which is not a valid PPC instruction). - INSN should have as many elements as PATTERN. Note that, if - PATTERN contains optional instructions which aren't present in - memory, then INSN will have holes, so INSN[i] isn't necessarily the - i'th instruction in memory. */ -static int -insns_match_pattern (CORE_ADDR pc, - struct insn_pattern *pattern, - unsigned int *insn) -{ - int i; - - for (i = 0; pattern[i].mask; i++) - { - insn[i] = read_insn (pc); - if ((insn[i] & pattern[i].mask) == pattern[i].data) - pc += 4; - else if (pattern[i].optional) - insn[i] = 0; - else - return 0; - } - - return 1; -} - - -/* Return the 'd' field of the d-form instruction INSN, properly - sign-extended. */ -static CORE_ADDR -insn_d_field (unsigned int insn) -{ - return ((((CORE_ADDR) insn & 0xffff) ^ 0x8000) - 0x8000); -} - - -/* Return the 'ds' field of the ds-form instruction INSN, with the two - zero bits concatenated at the right, and properly - sign-extended. */ -static CORE_ADDR -insn_ds_field (unsigned int insn) -{ - return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000); -} - - -/* If DESC is the address of a 64-bit PowerPC GNU/Linux function - descriptor, return the descriptor's entry point. */ -static CORE_ADDR -ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - /* The first word of the descriptor is the entry point. */ - return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order); -} - - -/* Pattern for the standard linkage function. These are built by - build_plt_stub in elf64-ppc.c, whose GLINK argument is always - zero. */ -static struct insn_pattern ppc64_standard_linkage1[] = - { - /* addis r12, r2, <any> */ - { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, - - /* std r2, 40(r1) */ - { -1, insn_ds (62, 2, 1, 40, 0), 0 }, - - /* ld r11, <any>(r12) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, - - /* addis r12, r12, 1 <optional> */ - { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, - - /* ld r2, <any>(r12) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, - - /* addis r12, r12, 1 <optional> */ - { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, - - /* mtctr r11 */ - { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, - - /* ld r11, <any>(r12) <optional> */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, - - /* bctr */ - { -1, 0x4e800420, 0 }, - - { 0, 0, 0 } - }; -#define PPC64_STANDARD_LINKAGE1_LEN \ - (sizeof (ppc64_standard_linkage1) / sizeof (ppc64_standard_linkage1[0])) - -static struct insn_pattern ppc64_standard_linkage2[] = - { - /* addis r12, r2, <any> */ - { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, - - /* std r2, 40(r1) */ - { -1, insn_ds (62, 2, 1, 40, 0), 0 }, - - /* ld r11, <any>(r12) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, - - /* addi r12, r12, <any> <optional> */ - { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 }, - - /* mtctr r11 */ - { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, - - /* ld r2, <any>(r12) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, - - /* ld r11, <any>(r12) <optional> */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, - - /* bctr */ - { -1, 0x4e800420, 0 }, - - { 0, 0, 0 } - }; -#define PPC64_STANDARD_LINKAGE2_LEN \ - (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0])) - -static struct insn_pattern ppc64_standard_linkage3[] = - { - /* std r2, 40(r1) */ - { -1, insn_ds (62, 2, 1, 40, 0), 0 }, - - /* ld r11, <any>(r2) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 }, - - /* addi r2, r2, <any> <optional> */ - { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 }, - - /* mtctr r11 */ - { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, - - /* ld r11, <any>(r2) <optional> */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 }, - - /* ld r2, <any>(r2) */ - { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 }, - - /* bctr */ - { -1, 0x4e800420, 0 }, - - { 0, 0, 0 } - }; -#define PPC64_STANDARD_LINKAGE3_LEN \ - (sizeof (ppc64_standard_linkage3) / sizeof (ppc64_standard_linkage3[0])) - - -/* When the dynamic linker is doing lazy symbol resolution, the first - call to a function in another object will go like this: - - - The user's function calls the linkage function: - - 100007c4: 4b ff fc d5 bl 10000498 - 100007c8: e8 41 00 28 ld r2,40(r1) - - - The linkage function loads the entry point (and other stuff) from - the function descriptor in the PLT, and jumps to it: - - 10000498: 3d 82 00 00 addis r12,r2,0 - 1000049c: f8 41 00 28 std r2,40(r1) - 100004a0: e9 6c 80 98 ld r11,-32616(r12) - 100004a4: e8 4c 80 a0 ld r2,-32608(r12) - 100004a8: 7d 69 03 a6 mtctr r11 - 100004ac: e9 6c 80 a8 ld r11,-32600(r12) - 100004b0: 4e 80 04 20 bctr - - - But since this is the first time that PLT entry has been used, it - sends control to its glink entry. That loads the number of the - PLT entry and jumps to the common glink0 code: - - 10000c98: 38 00 00 00 li r0,0 - 10000c9c: 4b ff ff dc b 10000c78 - - - The common glink0 code then transfers control to the dynamic - linker's fixup code: - - 10000c78: e8 41 00 28 ld r2,40(r1) - 10000c7c: 3d 82 00 00 addis r12,r2,0 - 10000c80: e9 6c 80 80 ld r11,-32640(r12) - 10000c84: e8 4c 80 88 ld r2,-32632(r12) - 10000c88: 7d 69 03 a6 mtctr r11 - 10000c8c: e9 6c 80 90 ld r11,-32624(r12) - 10000c90: 4e 80 04 20 bctr - - Eventually, this code will figure out how to skip all of this, - including the dynamic linker. At the moment, we just get through - the linkage function. */ - -/* If the current thread is about to execute a series of instructions - at PC matching the ppc64_standard_linkage pattern, and INSN is the result - from that pattern match, return the code address to which the - standard linkage function will send them. (This doesn't deal with - dynamic linker lazy symbol resolution stubs.) */ -static CORE_ADDR -ppc64_standard_linkage1_target (struct frame_info *frame, - CORE_ADDR pc, unsigned int *insn) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - /* The address of the function descriptor this linkage function - references. */ - CORE_ADDR desc - = ((CORE_ADDR) get_frame_register_unsigned (frame, - tdep->ppc_gp0_regnum + 2) - + (insn_d_field (insn[0]) << 16) - + insn_ds_field (insn[2])); - - /* The first word of the descriptor is the entry point. Return that. */ - return ppc64_desc_entry_point (gdbarch, desc); -} - static struct core_regset_section ppc_linux_vsx_regset_sections[] = { { ".reg", 48 * 4, "general-purpose" }, @@ -573,45 +303,8 @@ static struct core_regset_section ppc64_linux_fp_regset_sections[] = { NULL, 0} }; -static CORE_ADDR -ppc64_standard_linkage2_target (struct frame_info *frame, - CORE_ADDR pc, unsigned int *insn) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - /* The address of the function descriptor this linkage function - references. */ - CORE_ADDR desc - = ((CORE_ADDR) get_frame_register_unsigned (frame, - tdep->ppc_gp0_regnum + 2) - + (insn_d_field (insn[0]) << 16) - + insn_ds_field (insn[2])); - - /* The first word of the descriptor is the entry point. Return that. */ - return ppc64_desc_entry_point (gdbarch, desc); -} - -static CORE_ADDR -ppc64_standard_linkage3_target (struct frame_info *frame, - CORE_ADDR pc, unsigned int *insn) -{ - struct gdbarch *gdbarch = get_frame_arch (frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - /* The address of the function descriptor this linkage function - references. */ - CORE_ADDR desc - = ((CORE_ADDR) get_frame_register_unsigned (frame, - tdep->ppc_gp0_regnum + 2) - + insn_ds_field (insn[1])); - - /* The first word of the descriptor is the entry point. Return that. */ - return ppc64_desc_entry_point (gdbarch, desc); -} - /* PLT stub in executable. */ -static struct insn_pattern powerpc32_plt_stub[] = +static struct ppc_insn_pattern powerpc32_plt_stub[] = { { 0xffff0000, 0x3d600000, 0 }, /* lis r11, xxxx */ { 0xffff0000, 0x816b0000, 0 }, /* lwz r11, xxxx(r11) */ @@ -621,7 +314,7 @@ static struct insn_pattern powerpc32_plt_stub[] = }; /* PLT stub in shared library. */ -static struct insn_pattern powerpc32_plt_stub_so[] = +static struct ppc_insn_pattern powerpc32_plt_stub_so[] = { { 0xffff0000, 0x817e0000, 0 }, /* lwz r11, xxxx(r30) */ { 0xffffffff, 0x7d6903a6, 0 }, /* mtctr r11 */ @@ -666,134 +359,32 @@ ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR target = 0; - if (insns_match_pattern (pc, powerpc32_plt_stub, insnbuf)) + if (ppc_insns_match_pattern (pc, powerpc32_plt_stub, insnbuf)) { /* Insn pattern is lis r11, xxxx lwz r11, xxxx(r11) Branch target is in r11. */ - target = (insn_d_field (insnbuf[0]) << 16) | insn_d_field (insnbuf[1]); + target = (ppc_insn_d_field (insnbuf[0]) << 16) + | ppc_insn_d_field (insnbuf[1]); target = read_memory_unsigned_integer (target, 4, byte_order); } - if (insns_match_pattern (pc, powerpc32_plt_stub_so, insnbuf)) + if (ppc_insns_match_pattern (pc, powerpc32_plt_stub_so, insnbuf)) { /* Insn pattern is lwz r11, xxxx(r30) Branch target is in r11. */ target = get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 30) - + insn_d_field (insnbuf[0]); + + ppc_insn_d_field (insnbuf[0]); target = read_memory_unsigned_integer (target, 4, byte_order); } return target; } -/* Given that we've begun executing a call trampoline at PC, return - the entry point of the function the trampoline will go to. */ -static CORE_ADDR -ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) -{ - unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN]; - unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN]; - unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN]; - CORE_ADDR target; - - if (insns_match_pattern (pc, ppc64_standard_linkage1, - ppc64_standard_linkage1_insn)) - pc = ppc64_standard_linkage1_target (frame, pc, - ppc64_standard_linkage1_insn); - else if (insns_match_pattern (pc, ppc64_standard_linkage2, - ppc64_standard_linkage2_insn)) - pc = ppc64_standard_linkage2_target (frame, pc, - ppc64_standard_linkage2_insn); - else if (insns_match_pattern (pc, ppc64_standard_linkage3, - ppc64_standard_linkage3_insn)) - pc = ppc64_standard_linkage3_target (frame, pc, - ppc64_standard_linkage3_insn); - else - return 0; - - /* The PLT descriptor will either point to the already resolved target - address, or else to a glink stub. As the latter carry synthetic @plt - symbols, find_solib_trampoline_target should be able to resolve them. */ - target = find_solib_trampoline_target (frame, pc); - return target? target : pc; -} - - -/* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC64 - GNU/Linux. - - Usually a function pointer's representation is simply the address - of the function. On GNU/Linux on the PowerPC however, a function - pointer may be a pointer to a function descriptor. - - For PPC64, a function descriptor is a TOC entry, in a data section, - which contains three words: the first word is the address of the - function, the second word is the TOC pointer (r2), and the third word - is the static chain value. - - Throughout GDB it is currently assumed that a function pointer contains - the address of the function, which is not easy to fix. In addition, the - conversion of a function address to a function pointer would - require allocation of a TOC entry in the inferior's memory space, - with all its drawbacks. To be able to call C++ virtual methods in - the inferior (which are called via function pointers), - find_function_addr uses this function to get the function address - from a function pointer. - - If ADDR points at what is clearly a function descriptor, transform - it into the address of the corresponding function, if needed. Be - conservative, otherwise GDB will do the transformation on any - random addresses such as occur when there is no symbol table. */ - -static CORE_ADDR -ppc64_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch, - CORE_ADDR addr, - struct target_ops *targ) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct target_section *s = target_section_by_addr (targ, addr); - - /* Check if ADDR points to a function descriptor. */ - if (s && strcmp (s->the_bfd_section->name, ".opd") == 0) - { - /* There may be relocations that need to be applied to the .opd - section. Unfortunately, this function may be called at a time - where these relocations have not yet been performed -- this can - happen for example shortly after a library has been loaded with - dlopen, but ld.so has not yet applied the relocations. - - To cope with both the case where the relocation has been applied, - and the case where it has not yet been applied, we do *not* read - the (maybe) relocated value from target memory, but we instead - read the non-relocated value from the BFD, and apply the relocation - offset manually. - - This makes the assumption that all .opd entries are always relocated - by the same offset the section itself was relocated. This should - always be the case for GNU/Linux executables and shared libraries. - Note that other kind of object files (e.g. those added via - add-symbol-files) will currently never end up here anyway, as this - function accesses *target* sections only; only the main exec and - shared libraries are ever added to the target. */ - - gdb_byte buf[8]; - int res; - - res = bfd_get_section_contents (s->bfd, s->the_bfd_section, - &buf, addr - s->addr, 8); - if (res != 0) - return extract_unsigned_integer (buf, 8, byte_order) - - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr; - } - - return addr; -} - /* Wrappers to handle Linux-only registers. */ static void @@ -1742,7 +1333,7 @@ ppc_linux_init_abi (struct gdbarch_info info, /* Handle PPC GNU/Linux 64-bit function pointers (which are really function descriptors). */ set_gdbarch_convert_from_func_ptr_addr - (gdbarch, ppc64_linux_convert_from_func_ptr_addr); + (gdbarch, ppc64_convert_from_func_ptr_addr); /* Shared library handling. */ set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code); diff --git a/gdb/ppc-tdep.h b/gdb/ppc-tdep.h index 9be9666..b268e90 100644 --- a/gdb/ppc-tdep.h +++ b/gdb/ppc-tdep.h @@ -291,6 +291,23 @@ enum { PPC_NUM_REGS }; +/* An instruction to match. */ + +struct ppc_insn_pattern +{ + unsigned int mask; /* mask the insn with this... */ + unsigned int data; /* ...and see if it matches this. */ + int optional; /* If non-zero, this insn may be absent. */ +}; + +extern int +ppc_insns_match_pattern (CORE_ADDR pc, struct ppc_insn_pattern *pattern, + unsigned int *insn); +extern CORE_ADDR +ppc_insn_d_field (unsigned int insn); + +extern CORE_ADDR +ppc_insn_ds_field (unsigned int insn); /* Instruction size. */ #define PPC_INSN_SIZE 4 diff --git a/gdb/ppc64-tdep.c b/gdb/ppc64-tdep.c new file mode 100644 index 0000000..cdf8f4d --- /dev/null +++ b/gdb/ppc64-tdep.c @@ -0,0 +1,364 @@ +/* Common target-dependent code for ppc64 GDB, the GNU debugger. + + Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "frame.h" +#include "gdbcore.h" +#include "ppc-tdep.h" +#include "ppc64-tdep.h" + +/* Macros for matching instructions. Note that, since all the + operands are masked off before they're or-ed into the instruction, + you can use -1 to make masks. */ + +#define insn_d(opcd, rts, ra, d) \ + ((((opcd) & 0x3f) << 26) \ + | (((rts) & 0x1f) << 21) \ + | (((ra) & 0x1f) << 16) \ + | ((d) & 0xffff)) + +#define insn_ds(opcd, rts, ra, d, xo) \ + ((((opcd) & 0x3f) << 26) \ + | (((rts) & 0x1f) << 21) \ + | (((ra) & 0x1f) << 16) \ + | ((d) & 0xfffc) \ + | ((xo) & 0x3)) + +#define insn_xfx(opcd, rts, spr, xo) \ + ((((opcd) & 0x3f) << 26) \ + | (((rts) & 0x1f) << 21) \ + | (((spr) & 0x1f) << 16) \ + | (((spr) & 0x3e0) << 6) \ + | (((xo) & 0x3ff) << 1)) + +/* If DESC is the address of a 64-bit PowerPC FreeBSD function + descriptor, return the descriptor's entry point. */ + +static CORE_ADDR +ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + /* The first word of the descriptor is the entry point. */ + return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order); +} + +/* Pattern for the standard linkage function. These are built by + build_plt_stub in elf64-ppc.c, whose GLINK argument is always + zero. */ + +static struct ppc_insn_pattern ppc64_standard_linkage1[] = + { + /* addis r12, r2, <any> */ + { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, + + /* std r2, 40(r1) */ + { -1, insn_ds (62, 2, 1, 40, 0), 0 }, + + /* ld r11, <any>(r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, + + /* addis r12, r12, 1 <optional> */ + { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, + + /* ld r2, <any>(r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, + + /* addis r12, r12, 1 <optional> */ + { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, + + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + + /* ld r11, <any>(r12) <optional> */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, + + /* bctr */ + { -1, 0x4e800420, 0 }, + + { 0, 0, 0 } + }; + +#define PPC64_STANDARD_LINKAGE1_LEN ARRAY_SIZE (ppc64_standard_linkage1) + +static struct ppc_insn_pattern ppc64_standard_linkage2[] = + { + /* addis r12, r2, <any> */ + { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, + + /* std r2, 40(r1) */ + { -1, insn_ds (62, 2, 1, 40, 0), 0 }, + + /* ld r11, <any>(r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, + + /* addi r12, r12, <any> <optional> */ + { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 }, + + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + + /* ld r2, <any>(r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, + + /* ld r11, <any>(r12) <optional> */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, + + /* bctr */ + { -1, 0x4e800420, 0 }, + + { 0, 0, 0 } + }; + +#define PPC64_STANDARD_LINKAGE2_LEN ARRAY_SIZE (ppc64_standard_linkage2) + +static struct ppc_insn_pattern ppc64_standard_linkage3[] = + { + /* std r2, 40(r1) */ + { -1, insn_ds (62, 2, 1, 40, 0), 0 }, + + /* ld r11, <any>(r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 }, + + /* addi r2, r2, <any> <optional> */ + { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 }, + + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + + /* ld r11, <any>(r2) <optional> */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 }, + + /* ld r2, <any>(r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 }, + + /* bctr */ + { -1, 0x4e800420, 0 }, + + { 0, 0, 0 } + }; + +#define PPC64_STANDARD_LINKAGE3_LEN ARRAY_SIZE (ppc64_standard_linkage3) + +/* When the dynamic linker is doing lazy symbol resolution, the first + call to a function in another object will go like this: + + - The user's function calls the linkage function: + + 100007c4: 4b ff fc d5 bl 10000498 + 100007c8: e8 41 00 28 ld r2,40(r1) + + - The linkage function loads the entry point (and other stuff) from + the function descriptor in the PLT, and jumps to it: + + 10000498: 3d 82 00 00 addis r12,r2,0 + 1000049c: f8 41 00 28 std r2,40(r1) + 100004a0: e9 6c 80 98 ld r11,-32616(r12) + 100004a4: e8 4c 80 a0 ld r2,-32608(r12) + 100004a8: 7d 69 03 a6 mtctr r11 + 100004ac: e9 6c 80 a8 ld r11,-32600(r12) + 100004b0: 4e 80 04 20 bctr + + - But since this is the first time that PLT entry has been used, it + sends control to its glink entry. That loads the number of the + PLT entry and jumps to the common glink0 code: + + 10000c98: 38 00 00 00 li r0,0 + 10000c9c: 4b ff ff dc b 10000c78 + + - The common glink0 code then transfers control to the dynamic + linker's fixup code: + + 10000c78: e8 41 00 28 ld r2,40(r1) + 10000c7c: 3d 82 00 00 addis r12,r2,0 + 10000c80: e9 6c 80 80 ld r11,-32640(r12) + 10000c84: e8 4c 80 88 ld r2,-32632(r12) + 10000c88: 7d 69 03 a6 mtctr r11 + 10000c8c: e9 6c 80 90 ld r11,-32624(r12) + 10000c90: 4e 80 04 20 bctr + + Eventually, this code will figure out how to skip all of this, + including the dynamic linker. At the moment, we just get through + the linkage function. */ + +/* If the current thread is about to execute a series of instructions + at PC matching the ppc64_standard_linkage pattern, and INSN is the result + from that pattern match, return the code address to which the + standard linkage function will send them. (This doesn't deal with + dynamic linker lazy symbol resolution stubs.) */ + +static CORE_ADDR +ppc64_standard_linkage1_target (struct frame_info *frame, + CORE_ADDR pc, unsigned int *insn) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* The address of the function descriptor this linkage function + references. */ + CORE_ADDR desc + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + (ppc_insn_d_field (insn[0]) << 16) + + ppc_insn_ds_field (insn[2])); + + /* The first word of the descriptor is the entry point. Return that. */ + return ppc64_desc_entry_point (gdbarch, desc); +} + +static CORE_ADDR +ppc64_standard_linkage2_target (struct frame_info *frame, + CORE_ADDR pc, unsigned int *insn) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* The address of the function descriptor this linkage function + references. */ + CORE_ADDR desc + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + (ppc_insn_d_field (insn[0]) << 16) + + ppc_insn_ds_field (insn[2])); + + /* The first word of the descriptor is the entry point. Return that. */ + return ppc64_desc_entry_point (gdbarch, desc); +} + +static CORE_ADDR +ppc64_standard_linkage3_target (struct frame_info *frame, + CORE_ADDR pc, unsigned int *insn) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* The address of the function descriptor this linkage function + references. */ + CORE_ADDR desc + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + ppc_insn_ds_field (insn[1])); + + /* The first word of the descriptor is the entry point. Return that. */ + return ppc64_desc_entry_point (gdbarch, desc); +} + + +/* Given that we've begun executing a call trampoline at PC, return + the entry point of the function the trampoline will go to. */ + +CORE_ADDR +ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +{ + unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN]; + unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN]; + unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN]; + CORE_ADDR target; + + if (ppc_insns_match_pattern (pc, ppc64_standard_linkage1, + ppc64_standard_linkage1_insn)) + pc = ppc64_standard_linkage1_target (frame, pc, + ppc64_standard_linkage1_insn); + else if (ppc_insns_match_pattern (pc, ppc64_standard_linkage2, + ppc64_standard_linkage2_insn)) + pc = ppc64_standard_linkage2_target (frame, pc, + ppc64_standard_linkage2_insn); + else if (ppc_insns_match_pattern (pc, ppc64_standard_linkage3, + ppc64_standard_linkage3_insn)) + pc = ppc64_standard_linkage3_target (frame, pc, + ppc64_standard_linkage3_insn); + else + return 0; + + /* The PLT descriptor will either point to the already resolved target + address, or else to a glink stub. As the latter carry synthetic @plt + symbols, find_solib_trampoline_target should be able to resolve them. */ + target = find_solib_trampoline_target (frame, pc); + return target ? target : pc; +} + +/* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC64 + GNU/Linux. + + Usually a function pointer's representation is simply the address + of the function. On GNU/Linux on the PowerPC however, a function + pointer may be a pointer to a function descriptor. + + For PPC64, a function descriptor is a TOC entry, in a data section, + which contains three words: the first word is the address of the + function, the second word is the TOC pointer (r2), and the third word + is the static chain value. + + Throughout GDB it is currently assumed that a function pointer contains + the address of the function, which is not easy to fix. In addition, the + conversion of a function address to a function pointer would + require allocation of a TOC entry in the inferior's memory space, + with all its drawbacks. To be able to call C++ virtual methods in + the inferior (which are called via function pointers), + find_function_addr uses this function to get the function address + from a function pointer. + + If ADDR points at what is clearly a function descriptor, transform + it into the address of the corresponding function, if needed. Be + conservative, otherwise GDB will do the transformation on any + random addresses such as occur when there is no symbol table. */ + +CORE_ADDR +ppc64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, + CORE_ADDR addr, + struct target_ops *targ) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct target_section *s = target_section_by_addr (targ, addr); + + /* Check if ADDR points to a function descriptor. */ + if (s && strcmp (s->the_bfd_section->name, ".opd") == 0) + { + /* There may be relocations that need to be applied to the .opd + section. Unfortunately, this function may be called at a time + where these relocations have not yet been performed -- this can + happen for example shortly after a library has been loaded with + dlopen, but ld.so has not yet applied the relocations. + + To cope with both the case where the relocation has been applied, + and the case where it has not yet been applied, we do *not* read + the (maybe) relocated value from target memory, but we instead + read the non-relocated value from the BFD, and apply the relocation + offset manually. + + This makes the assumption that all .opd entries are always relocated + by the same offset the section itself was relocated. This should + always be the case for GNU/Linux executables and shared libraries. + Note that other kind of object files (e.g. those added via + add-symbol-files) will currently never end up here anyway, as this + function accesses *target* sections only; only the main exec and + shared libraries are ever added to the target. */ + + gdb_byte buf[8]; + int res; + + res = bfd_get_section_contents (s->bfd, s->the_bfd_section, + &buf, addr - s->addr, 8); + if (res != 0) + return extract_unsigned_integer (buf, 8, byte_order) + - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr; + } + + return addr; +} diff --git a/gdb/ppc64-tdep.h b/gdb/ppc64-tdep.h new file mode 100644 index 0000000..6fefdf3 --- /dev/null +++ b/gdb/ppc64-tdep.h @@ -0,0 +1,35 @@ +/* Common target-dependent code for ppc64. + + Copyright (C) 2013 + 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 <http://www.gnu.org/licenses/>. */ + +#ifndef PPC64_TDEP_H +#define PPC64_TDEP_H + +struct gdbarch; +struct frame_info; +struct target_ops; + +extern CORE_ADDR +ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc); + +extern CORE_ADDR +ppc64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, + CORE_ADDR addr, struct target_ops *targ); + +#endif /* PPC64_TDEP_H */ diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index a15f757..5bc1105 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -4238,6 +4238,68 @@ show_powerpc_exact_watchpoints (struct ui_file *file, int from_tty, fprintf_filtered (file, _("Use of exact watchpoints is %s.\n"), value); } +/* Read a PPC instruction from memory. PPC instructions are always + big-endian, no matter what endianness the program is running in, so + we can hardcode BFD_ENDIAN_BIG for read_memory_unsigned_integer. */ + +static unsigned int +read_insn (CORE_ADDR pc) +{ + return read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG); +} + +/* Return non-zero if the instructions at PC match the series + described in PATTERN, or zero otherwise. PATTERN is an array of + 'struct ppc_insn_pattern' objects, terminated by an entry whose + mask is zero. + + When the match is successful, fill INSN[i] with what PATTERN[i] + matched. If PATTERN[i] is optional, and the instruction wasn't + present, set INSN[i] to 0 (which is not a valid PPC instruction). + INSN should have as many elements as PATTERN. Note that, if + PATTERN contains optional instructions which aren't present in + memory, then INSN will have holes, so INSN[i] isn't necessarily the + i'th instruction in memory. */ + +int +ppc_insns_match_pattern (CORE_ADDR pc, struct ppc_insn_pattern *pattern, + unsigned int *insn) +{ + int i; + + for (i = 0; pattern[i].mask; i++) + { + insn[i] = read_insn (pc); + if ((insn[i] & pattern[i].mask) == pattern[i].data) + pc += 4; + else if (pattern[i].optional) + insn[i] = 0; + else + return 0; + } + + return 1; +} + +/* Return the 'd' field of the d-form instruction INSN, properly + sign-extended. */ + +CORE_ADDR +ppc_insn_d_field (unsigned int insn) +{ + return ((((CORE_ADDR) insn & 0xffff) ^ 0x8000) - 0x8000); +} + +/* Return the 'ds' field of the ds-form instruction INSN, with the two + zero bits concatenated at the right, and properly + sign-extended. */ + +CORE_ADDR +ppc_insn_ds_field (unsigned int insn) +{ + return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000); +} + /* Initialization code. */ /* -Wmissing-prototypes */ ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] patch to refactor ppc64 specific code from ppc-linux-tdep 2013-01-26 16:24 ` Andreas Tobler @ 2013-02-01 19:00 ` Pedro Alves 2013-02-01 20:55 ` Andreas Tobler 0 siblings, 1 reply; 6+ messages in thread From: Pedro Alves @ 2013-02-01 19:00 UTC (permalink / raw) To: Andreas Tobler; +Cc: gdb-patches On 01/26/2013 04:24 PM, Andreas Tobler wrote: > Hi Pedro, Hi Andreas. >> > Also, GDB's convention is that the function name goes on the first >> > column in function definitions only, not declarations, and that >> > declarations in .h files get an explicit "extern". > Done, not sure if I need the extern on ppc64-tdep.h too? Yes. > 2013-01-26 Andreas Tobler <andreast@fgznet.ch> > > * Makefile.in (ALL_TARGET_OBS): Add new file ppc64-tdep.o. > (HFILES_NO_SRCDIR): Likewise. > (ALLDEPFILES): Likewise. * Makefile.in (ALL_TARGET_OBS): Add ppc64-tdep.o. (HFILES_NO_SRCDIR): Add ppc64-tdep.h. (ALLDEPFILES): Add ppc64-tdep.c. > * configure.tgt: Add new file for powerpc-linux. * configure.tgt (powerpc-*-linux* | powerpc64-*-linux*): Add ppc64-tdep.o to gdb_target_obs. > * ppc64-tdep.h: New file. > * ppc64-tdep.c: New file. > (insn_d, insn_ds, insn_xfx, ppc64_desc_entry_point): Move from > ppc-linux-tdep.c to here. > (PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN) > (PPC64_STANDARD_LINKAGE2_LEN): Likewise and use ARRAY_SIZE macro. > (ppc64_standard_linkage1_target, ppc64_standard_linkage2_target) > (ppc64_standard_linkage3_target, ppc64_skip_trampoline_code): Move > from ppc-linux-tdep.c to here. > (ppc64_convert_from_func_ptr_addr): Rename it from > ppc64_linux_convert_from_func_ptr_addr to > ppc64_convert_from_func_ptr_addr and move it from ppc-linux-tdep.c to > here. Drop the "it"s. > * rs6000-tdep.c: > (read_insn): Move from ppc-linux-tdep.c to here. > (insns_match_pattern, insn_d_field, insn_ds_field): Move > from ppc-linux-tdep.c to here and rename them with the ppc_ prefix. > * ppc-linux-tdep.c: Include ppc64-tdep.h. > Removed above functions. > (ppc_linux_init_abi): Rename > ppc64_linux_convert_from_func_ptr_addr to > ppc64_convert_from_func_ptr_addr. (ppc_linux_init_abi): Adjust. > diff --git a/gdb/ppc-tdep.h b/gdb/ppc-tdep.h > index 9be9666..b268e90 100644 > --- a/gdb/ppc-tdep.h > +++ b/gdb/ppc-tdep.h > @@ -291,6 +291,23 @@ enum { > PPC_NUM_REGS > }; > > +/* An instruction to match. */ > + > +struct ppc_insn_pattern > +{ > + unsigned int mask; /* mask the insn with this... */ > + unsigned int data; /* ...and see if it matches this. */ > + int optional; /* If non-zero, this insn may be absent. */ > +}; > + > +extern int > +ppc_insns_match_pattern (CORE_ADDR pc, struct ppc_insn_pattern *pattern, > + unsigned int *insn); > +extern CORE_ADDR > +ppc_insn_d_field (unsigned int insn); > + > +extern CORE_ADDR > +ppc_insn_ds_field (unsigned int insn); Here, GDB's convention is that the function name goes on the first column in function definitions only, not declarations. So: extern int ppc_insns_match_pattern (CORE_ADDR pc, struct ppc_insn_pattern *pattern, unsigned int *insn); extern CORE_ADDR ppc_insn_d_field (unsigned int insn); extern CORE_ADDR ppc_insn_ds_field (unsigned int insn); This is so 'grep ^functionname" finds function definitions. > > /* Instruction size. */ > #define PPC_INSN_SIZE 4 > diff --git a/gdb/ppc64-tdep.c b/gdb/ppc64-tdep.c > new file mode 100644 > index 0000000..cdf8f4d > --- /dev/null > +++ b/gdb/ppc64-tdep.c > @@ -0,0 +1,364 @@ > +/* Common target-dependent code for ppc64 GDB, the GNU debugger. > + > + Copyright (C) 2013 Free Software > + Foundation, Inc. This is existing code, not new code. Please retain the copyright the copyright years of the file(s) the code has been copied from. This is okay with these issues fixed. Thanks again for doing this. -- Pedro Alves ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] patch to refactor ppc64 specific code from ppc-linux-tdep 2013-02-01 19:00 ` Pedro Alves @ 2013-02-01 20:55 ` Andreas Tobler 0 siblings, 0 replies; 6+ messages in thread From: Andreas Tobler @ 2013-02-01 20:55 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Hi Pedro, On 01.02.13 19:59, Pedro Alves wrote: > On 01/26/2013 04:24 PM, Andreas Tobler wrote: >>>> Also, GDB's convention is that the function name goes on the first >>>> column in function definitions only, not declarations, and that >>>> declarations in .h files get an explicit "extern". >> Done, not sure if I need the extern on ppc64-tdep.h too? > > Yes. > >> 2013-01-26 Andreas Tobler <andreast@fgznet.ch> >> >> * Makefile.in (ALL_TARGET_OBS): Add new file ppc64-tdep.o. >> (HFILES_NO_SRCDIR): Likewise. >> (ALLDEPFILES): Likewise. > > * Makefile.in (ALL_TARGET_OBS): Add ppc64-tdep.o. > (HFILES_NO_SRCDIR): Add ppc64-tdep.h. > (ALLDEPFILES): Add ppc64-tdep.c. > > >> * configure.tgt: Add new file for powerpc-linux. > > * configure.tgt (powerpc-*-linux* | powerpc64-*-linux*): Add ppc64-tdep.o > to gdb_target_obs. > >> * ppc64-tdep.h: New file. >> * ppc64-tdep.c: New file. >> (insn_d, insn_ds, insn_xfx, ppc64_desc_entry_point): Move from >> ppc-linux-tdep.c to here. >> (PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN) >> (PPC64_STANDARD_LINKAGE2_LEN): Likewise and use ARRAY_SIZE macro. >> (ppc64_standard_linkage1_target, ppc64_standard_linkage2_target) >> (ppc64_standard_linkage3_target, ppc64_skip_trampoline_code): Move >> from ppc-linux-tdep.c to here. >> (ppc64_convert_from_func_ptr_addr): Rename it from >> ppc64_linux_convert_from_func_ptr_addr to >> ppc64_convert_from_func_ptr_addr and move it from ppc-linux-tdep.c to >> here. > > Drop the "it"s. > >> * rs6000-tdep.c: >> (read_insn): Move from ppc-linux-tdep.c to here. >> (insns_match_pattern, insn_d_field, insn_ds_field): Move >> from ppc-linux-tdep.c to here and rename them with the ppc_ prefix. >> * ppc-linux-tdep.c: Include ppc64-tdep.h. >> Removed above functions. > > >> (ppc_linux_init_abi): Rename >> ppc64_linux_convert_from_func_ptr_addr to >> ppc64_convert_from_func_ptr_addr. > > (ppc_linux_init_abi): Adjust. > > >> diff --git a/gdb/ppc-tdep.h b/gdb/ppc-tdep.h >> index 9be9666..b268e90 100644 >> --- a/gdb/ppc-tdep.h >> +++ b/gdb/ppc-tdep.h >> @@ -291,6 +291,23 @@ enum { >> PPC_NUM_REGS >> }; >> >> +/* An instruction to match. */ >> + >> +struct ppc_insn_pattern >> +{ >> + unsigned int mask; /* mask the insn with this... */ >> + unsigned int data; /* ...and see if it matches this. */ >> + int optional; /* If non-zero, this insn may be absent. */ >> +}; >> + >> +extern int >> +ppc_insns_match_pattern (CORE_ADDR pc, struct ppc_insn_pattern *pattern, >> + unsigned int *insn); >> +extern CORE_ADDR >> +ppc_insn_d_field (unsigned int insn); >> + >> +extern CORE_ADDR >> +ppc_insn_ds_field (unsigned int insn); > > Here, GDB's convention is that the function name goes on the first > column in function definitions only, not declarations. So: > > extern int ppc_insns_match_pattern (CORE_ADDR pc, > struct ppc_insn_pattern *pattern, > unsigned int *insn); > > extern CORE_ADDR ppc_insn_d_field (unsigned int insn); > > extern CORE_ADDR ppc_insn_ds_field (unsigned int insn); > > > This is so 'grep ^functionname" finds function definitions. > >> >> /* Instruction size. */ >> #define PPC_INSN_SIZE 4 >> diff --git a/gdb/ppc64-tdep.c b/gdb/ppc64-tdep.c >> new file mode 100644 >> index 0000000..cdf8f4d >> --- /dev/null >> +++ b/gdb/ppc64-tdep.c >> @@ -0,0 +1,364 @@ >> +/* Common target-dependent code for ppc64 GDB, the GNU debugger. >> + >> + Copyright (C) 2013 Free Software >> + Foundation, Inc. > > This is existing code, not new code. Please retain the copyright > the copyright years of the file(s) the code has been copied from. > > This is okay with these issues fixed. > > Thanks again for doing this. Commit done, thank you for the patience! Andreas ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-02-01 20:55 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-12-27 21:36 [RFC] patch to refactor ppc64 specific code from ppc-linux-tdep Andreas Tobler 2013-01-19 13:46 ` Andreas Tobler 2013-01-21 15:50 ` Pedro Alves 2013-01-26 16:24 ` Andreas Tobler 2013-02-01 19:00 ` Pedro Alves 2013-02-01 20:55 ` Andreas Tobler
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox