From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1457 invoked by alias); 17 Nov 2011 23:20:31 -0000 Received: (qmail 1427 invoked by uid 22791); 17 Nov 2011 23:20:25 -0000 X-SWARE-Spam-Status: No, hits=2.0 required=5.0 tests=BAYES_50,SARE_BAYES_6x6,SARE_BAYES_7x6,TW_EG,TW_GD X-Spam-Check-By: sourceware.org Received: from afflict.kos.to (HELO afflict.kos.to) (92.243.29.197) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 17 Nov 2011 23:20:04 +0000 Received: from enorme.TCLDOMAIN.OFFICE (unknown [62.254.222.225]) (using TLSv1 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by afflict.kos.to (Postfix) with ESMTPSA id 31D5B26670; Thu, 17 Nov 2011 23:20:01 +0000 (UTC) Date: Thu, 17 Nov 2011 23:20:00 -0000 From: Hector Oron To: gdb-patches@sourceware.org Cc: Nobuhiro Iwamatsu , yoshii.takashi@renesas.com Subject: [PATCH] Renesas SH (sh4) native support Message-ID: <20111117232006.GA22252@enorme.TCLDOMAIN.OFFICE> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="lrZ03NoBR/3+SXJZ" Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-11/txt/msg00490.txt.bz2 --lrZ03NoBR/3+SXJZ Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-length: 41875 Dear GDB developers, I am forwarding a patch that landed in Debian BTS a while ago for adding n= ative support for Renesas SH (sh4). You should be able to find original patch from Yoshii-san at Debian BTS: I have updated the patch to current CVS HEAD, but I have not been able to = test it as I lack SH hardware. At file gdb/sh-linux-tdep.c:596, there is a call to linux_init_abi (info, = gdbarch); which was not there when the original patch was written, the rest= of it, still applies to current HEAD, so if someone could test the patch a= nd, in the case it works, apply it to mainline GDB, that would be great. I would like to add support for an unofficial Debian SH port, so any comme= nts are welcome. Description: Add Renesas SH (sh4) support Add support for Renesas SH (sh4) architecture. . gdb (7.4-1~cvs20111117.2) experimental; urgency=3Dlow . * Add Renesas SH (sh4) support (Closes: #576242) - Thanks Nobuhiro Iwamatsu, Takashi Yoshii. Author: Hector Oron Bug-Debian: http://bugs.debian.org/576242 --- The information above should follow the Patch Tagging Guidelines, please checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here are templates for supplementary fields that you might want to add: Forwarded: Last-Update: <2011-11-17> --- gdb-7.4.orig/gdb/configure.host +++ gdb-7.4/gdb/configure.host @@ -139,6 +139,7 @@ powerpc64-*-linux*) gdb_host=3Dppc64-l =20 s390*-*-*) gdb_host=3Ds390 ;; =20 +sh*-*-linux*) gdb_host=3Dlinux ;; sh*-*-netbsdelf* | sh*-*-knetbsd*-gnu) gdb_host=3Dnbsd ;; sh*-*-openbsd*) gdb_host=3Dnbsd ;; --- gdb-7.4.orig/gdb/Makefile.in +++ gdb-7.4/gdb/Makefile.in @@ -1538,6 +1538,7 @@ ALLDEPFILES =3D \ score-tdep.c \ ser-go32.c ser-pipe.c ser-tcp.c ser-mingw.c \ sh-tdep.c sh64-tdep.c shnbsd-tdep.c shnbsd-nat.c \ + sh-linux-tdep.c sh-linux-nat.c \ sol2-tdep.c \ solib-irix.c solib-svr4.c solib-sunos.c \ sparc-linux-nat.c sparc-linux-tdep.c \ --- gdb-7.4.orig/gdb/sh-linux-tdep.c +++ gdb-7.4/gdb/sh-linux-tdep.c @@ -19,11 +19,34 @@ along with this program. If not, see . = */ =20 #include "defs.h" +#include "gdbcore.h" +#include "frame.h" +#include "frame-base.h" +#include "frame-unwind.h" +#include "dwarf2-frame.h" +#include "value.h" +#include "regcache.h" +#include "inferior.h" #include "osabi.h" =20 +#include "reggroups.h" +#include "arch-utils.h" +#include "floatformat.h" #include "solib-svr4.h" #include "symtab.h" +#include "gdb_string.h" +#include "command.h" +#include "gdb_assert.h" =20 +#include +#include +#include +#include +#include + +#include + +#include "regset.h" #include "glibc-tdep.h" #include "sh-tdep.h" #include "linux-tdep.h" @@ -71,9 +94,505 @@ static const struct sh_corefile_regmap f {-1 /* Terminator. */, 0} }; =20 +/* Recognizing signal handler frames. */ + +/* GNU/Linux has two flavors of signals. Normal signal handlers, and + "realtime" (RT) signals. The RT signals can provide additional + information to the signal handler if the SA_SIGINFO flag is set + when establishing a signal handler using `sigaction'. It is not + unlikely that future versions of GNU/Linux will support SA_SIGINFO + for normal signals too. */ + +/* When the SH Linux kernel calls a signal handler and the + SA_RESTORER flag isn't set, the return address points to a bit of + code on the stack. This function returns whether the PC appears to + be within this bit of code. + + The instruction sequence for normal signals is + mov.w 1f,r3 + trapa #16 + or r0, r0 + or r0, r0 + or r0, r0 + or r0, r0 + or r0, r0 + 1: .word __NR_sigreturn + or 0x9305 0xc310 0x200b 0x200b 0x200b 0x200b 0x200b 0x0077. + + Checking for the code sequence should be somewhat reliable, because + the effect is to call the system call sigreturn. This is unlikely + to occur anywhere other than a signal trampoline. + + It kind of sucks that we have to read memory from the process in + order to identify a signal trampoline, but there doesn't seem to be + any other way. The PC_IN_SIGTRAMP macro in tm-linux.h arranges to + only call us if no function name could be identified, which should + be the case since the code is on the stack. + + Detection of signal trampolines for handlers that set the + SA_RESTORER flag is in general not possible. Unfortunately this is + what the GNU C Library has been doing for quite some time now. + However, as of version 2.1.2, the GNU C Library uses signal + trampolines (named __restore and __restore_rt) that are identical + to the ones used by the kernel. Therefore, these trampolines are + supported too. */ + +#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ +#define TRAP16 0xc310 /* Syscall w/no args (NR in R3) */ +#define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ + +#define LINUX_SIGTRAMP_INSN0 MOVW(7) /* Move mem word at PC+7 to R3 */ +#define LINUX_SIGTRAMP_INSN1 TRAP16 /* Syscall w/no args (NR in R3) */ +#define LINUX_SIGTRAMP_INSN2 OR_R0_R0 /* or r0,r0 (insert to avoid hardwar= e bug) */ + +static const unsigned short linux_sigtramp_code[] =3D +{ + LINUX_SIGTRAMP_INSN0, + LINUX_SIGTRAMP_INSN1, + LINUX_SIGTRAMP_INSN2, + LINUX_SIGTRAMP_INSN2, + LINUX_SIGTRAMP_INSN2, + LINUX_SIGTRAMP_INSN2, + LINUX_SIGTRAMP_INSN2, + __NR_sigreturn +}; + +#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code) + +/* If PC is in a sigtramp routine, return the address of the start of + the routine. Otherwise, return 0. */ + +static CORE_ADDR +sh_linux_sigtramp_start (struct frame_info *next_frame) +{ + CORE_ADDR pc =3D get_frame_pc (next_frame); + gdb_byte buf[LINUX_SIGTRAMP_LEN]; + + /* We only recognize a signal trampoline if PC is at the start of + one of the three instructions. We optimize for finding the PC at + the start, as will be the case when the trampoline is not the + first frame on the stack. We assume that in the case where the + PC is not at the start of the instruction sequence, there will be + a few trailing readable bytes on the stack. */ + + if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_LEN)) + return 0; + + if (buf[0] !=3D LINUX_SIGTRAMP_INSN0) + { + if (buf[0] !=3D LINUX_SIGTRAMP_INSN1) + return 0; + + pc -=3D 2; + + if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_L= EN)) + return 0; + } + + if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) !=3D 0) + return 0; + + return pc; +} + +/* This function does the same for RT signals. Here the instruction + sequence is + mov.w 1f,r3 + trapa #16 + or r0, r0 + or r0, r0 + or r0, r0 + or r0, r0 + or r0, r0 + 1: .word __NR_rt_sigreturn + or 0x9305 0xc310 0x200b 0x200b 0x200b 0x200b 0x200b 0x00ad. + + The effect is to call the system call rt_sigreturn. */ + +#define LINUX_RT_SIGTRAMP_INSN0 MOVW(7) /* Move mem word at PC+7 to R3 */ +#define LINUX_RT_SIGTRAMP_INSN1 TRAP16 /* Syscall w/no args (NR in R3) */ +#define LINUX_RT_SIGTRAMP_INSN2 OR_R0_R0 /* or r0,r0 (insert to avoid har= dware bug) */ + +static const unsigned short linux_rt_sigtramp_code[] =3D +{ + LINUX_RT_SIGTRAMP_INSN0, + LINUX_RT_SIGTRAMP_INSN1, + LINUX_RT_SIGTRAMP_INSN2, + LINUX_RT_SIGTRAMP_INSN2, + LINUX_RT_SIGTRAMP_INSN2, + LINUX_RT_SIGTRAMP_INSN2, + LINUX_RT_SIGTRAMP_INSN2, + __NR_rt_sigreturn +}; + +#define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code) + +/* If PC is in a RT sigtramp routine, return the address of the start + of the routine. Otherwise, return 0. */ + +static CORE_ADDR +sh_linux_rt_sigtramp_start (struct frame_info *next_frame) +{ + CORE_ADDR pc =3D get_frame_pc (next_frame); + gdb_byte buf[LINUX_RT_SIGTRAMP_LEN]; + + /* We only recognize a signal trampoline if PC is at the start of + one of the two instructions. We optimize for finding the PC at + the start, as will be the case when the trampoline is not the + first frame on the stack. We assume that in the case where the + PC is not at the start of the instruction sequence, there will be + a few trailing readable bytes on the stack. */ + + if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_RT_SIGTRAMP_LE= N)) + return 0; + + if (buf[0] !=3D LINUX_RT_SIGTRAMP_INSN0) + { + if (buf[0] !=3D LINUX_RT_SIGTRAMP_INSN1) + return 0; + + pc -=3D 2; + + if (!safe_frame_unwind_memory (next_frame, pc, buf, + LINUX_RT_SIGTRAMP_LEN)) + return 0; + } + + if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) !=3D 0) + return 0; + + return pc; +} + +/* Return whether PC is in a GNU/Linux sigtramp routine. */ + +static int +sh_linux_sigtramp_p (struct frame_info *this_frame) +{ + CORE_ADDR pc =3D get_frame_pc (this_frame); + char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + + /* If we have NAME, we can optimize the search. The trampolines are + named __restore and __restore_rt. However, they aren't dynamically + exported from the shared C library, so the trampoline may appear to + be part of the preceding function. This should always be sigaction, + __sigaction, or __libc_sigaction (all aliases to the same function). = */ + if (name =3D=3D NULL || strstr (name, "sigaction") !=3D NULL) + return (sh_linux_sigtramp_start (this_frame) !=3D 0 + || sh_linux_rt_sigtramp_start (this_frame) !=3D 0); + + return (strcmp ("__restore", name) =3D=3D 0 + || strcmp ("__restore_rt", name) =3D=3D 0); +} + +/* Offset to struct sigcontext in ucontext, from . */ +#define SH_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 12 + + +/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp + routine, return the address of the associated sigcontext structure. */ + +static CORE_ADDR +sh_linux_sigcontext_addr (struct frame_info *this_frame) +{ + CORE_ADDR pc; + CORE_ADDR sp; + + sp =3D get_frame_register_unsigned (this_frame, SP_REGNUM); + + pc =3D sh_linux_sigtramp_start (this_frame); + if (pc) + { + return sp; + } + + pc =3D sh_linux_rt_sigtramp_start (this_frame); + if (pc) + { + CORE_ADDR ucontext_addr; + + /* The sigcontext structure is part of the user context. A + pointer to the user context is passed as the third argument + to the signal handler. */ + ucontext_addr =3D get_frame_register_unsigned (this_frame, ARG0_REGN= UM+2); + return ucontext_addr + SH_LINUX_UCONTEXT_SIGCONTEXT_OFFSET; + } + + error ("Couldn't recognize signal trampoline."); + return 0; +} + +/* Signal trampolines. */ +extern struct sh_frame_cache *sh_alloc_frame_cache (void); + +static struct sh_frame_cache * +sh_linux_sigtramp_frame_cache (struct frame_info *this_frame, void **this_= cache) +{ + struct sh_frame_cache *cache; + struct gdbarch_tdep *tdep =3D gdbarch_tdep (get_current_arch ()); + CORE_ADDR sigcontext_addr; + + if (*this_cache) + return *this_cache; + + cache =3D sh_alloc_frame_cache (); + + cache->base =3D get_frame_register_unsigned (this_frame, SP_REGNUM); + sigcontext_addr =3D tdep->sigcontext_addr (this_frame); + if (tdep->sc_reg_offset) + { + int i; + + gdb_assert (tdep->sc_num_regs <=3D SH_NUM_REGS); + + for (i =3D 0; i < tdep->sc_num_regs; i++) + if (tdep->sc_reg_offset[i] !=3D -1) + cache->saved_regs[i] =3D sigcontext_addr + tdep->sc_reg_offset[i]; + } + + *this_cache =3D cache; + return cache; +} + +static void +sh_linux_sigtramp_frame_this_id (struct frame_info *this_frame, void **thi= s_cache, + struct frame_id *this_id) +{ + struct sh_frame_cache *cache =3D + sh_linux_sigtramp_frame_cache (this_frame, this_cache); + + (*this_id) =3D frame_id_build (cache->base + 64, cache->pc); +} + +extern struct value * sh_frame_prev_register (); +static struct value * +sh_linux_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + sh_linux_sigtramp_frame_cache (this_frame, this_cache); + + return sh_frame_prev_register (this_frame, this_cache, regnum); +} + +static int +sh_linux_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + struct gdbarch_tdep *tdep =3D gdbarch_tdep (get_frame_arch (this_frame)); + + /* We shouldn't even bother if we don't have a sigcontext_addr + handler. */ + if (tdep->sigcontext_addr =3D=3D NULL) + return 0; + + if (tdep->sigtramp_p !=3D NULL) + { + if (tdep->sigtramp_p (this_frame)) + return 1; + } + + return 0; +} + +static const struct frame_unwind sh_linux_sigtramp_frame_unwind =3D +{ + SIGTRAMP_FRAME, + sh_linux_sigtramp_frame_this_id, + sh_linux_sigtramp_frame_prev_register, + NULL, + sh_linux_sigtramp_frame_sniffer +}; + +/* Supply register REGNUM from the buffer specified by GREGS and LEN + in the general-purpose register set REGSET to register cache + REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ + +void +sh_supply_gregset (const struct regset *regset, struct regcache *regcache, + int regnum, const void *gregs, size_t len) +{ + const struct gdbarch_tdep *tdep =3D gdbarch_tdep (regset->arch); + const char *regs =3D gregs; + int i; + + gdb_assert (len =3D=3D tdep->sizeof_gregset); + + for (i =3D 0; i < tdep->gregset_num_regs; i++) + { + if ((regnum =3D=3D i || regnum =3D=3D -1) + && tdep->gregset_reg_offset[i] !=3D -1) + regcache_raw_supply (regcache, i, regs + tdep->gregset_reg_offset[i]); + } +} + +/* Collect register REGNUM from the register cache REGCACHE and store + it in the buffer specified by GREGS and LEN as described by the + general-purpose register set REGSET. If REGNUM is -1, do this for + all registers in REGSET. */ + +void +sh_collect_gregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs, size_t len) +{ + const struct gdbarch_tdep *tdep =3D gdbarch_tdep (regset->arch); + char *regs =3D gregs; + int i; + + gdb_assert (len =3D=3D tdep->sizeof_gregset); + + for (i =3D 0; i < tdep->gregset_num_regs; i++) + { + if ((regnum =3D=3D i || regnum =3D=3D -1) + && tdep->gregset_reg_offset[i] !=3D -1) + regcache_raw_collect (regcache, i, regs + tdep->gregset_reg_offset[i]); + } +} + +/* Supply register REGNUM from the buffer specified by FPREGS and LEN + in the floating-point register set REGSET to register cache + REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ + +static void +sh_supply_fpregset (const struct regset *regset, struct regcache *regcache, + int regnum, const void *fpregs, size_t len) +{ + const struct gdbarch_tdep *tdep =3D gdbarch_tdep (regset->arch); + const char *regs =3D fpregs; + int i; + + gdb_assert (len =3D=3D tdep->sizeof_fpregset); + for (i =3D 0; i < 16; i++) + { + if (regnum =3D=3D i+25 || regnum =3D=3D -1) + regcache_raw_supply (regcache, i+25, regs + i*4); + } + if (regnum =3D=3D FPSCR_REGNUM || regnum =3D=3D -1) + regcache_raw_supply (regcache, FPSCR_REGNUM, regs + 32*4); + if (regnum =3D=3D FPUL_REGNUM || regnum =3D=3D -1) + regcache_raw_supply (regcache, FPUL_REGNUM, regs + 33*4); +} + +/* Collect register REGNUM from the register cache REGCACHE and store + it in the buffer specified by FPREGS and LEN as described by the + floating-point register set REGSET. If REGNUM is -1, do this for + all registers in REGSET. */ + +static void +sh_collect_fpregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *fpregs, size_t len) +{ + const struct gdbarch_tdep *tdep =3D gdbarch_tdep (regset->arch); + char *regs =3D fpregs; + int i; + + gdb_assert (len =3D=3D tdep->sizeof_fpregset); + for (i =3D 0; i < 16; i++) + { + if (regnum =3D=3D i+25 || regnum =3D=3D -1) + regcache_raw_collect (regcache, i+25, regs + i*4); + } + if (regnum =3D=3D FPSCR_REGNUM || regnum =3D=3D -1) + regcache_raw_collect (regcache, FPSCR_REGNUM, regs + 32*4); + if (regnum =3D=3D FPUL_REGNUM || regnum =3D=3D -1) + regcache_raw_collect (regcache, FPUL_REGNUM, regs + 33*4); +} + +/* Return the appropriate register set for the core section identified + by SECT_NAME and SECT_SIZE. */ + +const struct regset * +sh_linux_regset_from_core_section (struct gdbarch *gdbarch, + const char *sect_name, size_t sect_size) +{ + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + + if (strcmp (sect_name, ".reg") =3D=3D 0 && sect_size =3D=3D tdep->sizeof= _gregset) + { + if (tdep->gregset =3D=3D NULL) + tdep->gregset =3D regset_alloc (gdbarch, sh_supply_gregset, + sh_collect_gregset); + return tdep->gregset; + } + + if ((strcmp (sect_name, ".reg2") =3D=3D 0 && sect_size =3D=3D tdep->size= of_fpregset)) + { + if (tdep->fpregset =3D=3D NULL) + tdep->fpregset =3D regset_alloc (gdbarch, sh_supply_fpregset, + sh_collect_fpregset); + return tdep->fpregset; + } + + return NULL; +} + +/* The register sets used in GNU/Linux ELF core-dumps are identical to + the register sets in `struct user' that are used for a.out + core-dumps. These are also used by ptrace(2). The corresponding + types are `elf_gregset_t' for the general-purpose registers (with + `elf_greg_t' the type of a single GP register) and `elf_fpregset_t' + for the floating-point registers. + + Those types used to be available under the names `gregset_t' and + `fpregset_t' too, and GDB used those names in the past. But those + names are now used for the register sets used in the `mcontext_t' + type, which have a different size and layout. */ + +/* Mapping between the general-purpose registers in `struct user' + format and GDB's register cache layout. */ + +/* From . */ +static int sh_linux_gregset_reg_offset[] =3D +{ + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, + + REG_PC*4, REG_PR*4, REG_GBR*4, -1, + REG_MACH*4, REG_MACL*4, REG_SR*4, +}; + +/* Mapping between the general-purpose registers in `struct + sigcontext' format and GDB's register cache layout. */ + +/* From . */ +static int sh_linux_sc_reg_offset[] =3D +{ + 4, 8, 12, 16, 20, 24, 28, 32, + 36, 40, 44, 48, 52, 56, 60, 64, + 68, 72, 80, -1, + 84, 88, 76 +}; + static void sh_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + bfd abfd; + + tdep->gregset_reg_offset =3D sh_linux_gregset_reg_offset; + tdep->gregset_num_regs =3D ARRAY_SIZE (sh_linux_gregset_reg_offset); + tdep->sizeof_gregset =3D 23 * 4; + + tdep->jb_pc_offset =3D 32; /* From . */ + + tdep->sigtramp_p =3D sh_linux_sigtramp_p; + tdep->sigcontext_addr =3D sh_linux_sigcontext_addr; + tdep->sc_reg_offset =3D sh_linux_sc_reg_offset; + tdep->sc_num_regs =3D ARRAY_SIZE (sh_linux_sc_reg_offset); + + frame_unwind_append_unwinder(gdbarch, &sh_linux_sigtramp_frame_unwind); + + /* If we have a register mapping, enable the generic core file + support, unless it has already been enabled. */ + if (tdep->gregset_reg_offset + && !gdbarch_regset_from_core_section_p (gdbarch)) + set_gdbarch_regset_from_core_section (gdbarch, + sh_linux_regset_from_core_section= ); + linux_init_abi (info, gdbarch); =20 /* GNU/Linux uses SVR4-style shared libraries. */ --- gdb-7.4.orig/gdb/sh-tdep.h +++ gdb-7.4/gdb/sh-tdep.h @@ -22,6 +22,12 @@ =20 /* Contributed by Steve Chamberlain sac@cygnus.com. */ =20 +struct frame_info; +struct gdbarch; +struct reggroup; +struct regset; +struct regcache; + /* Registers for all SH variants. Used also by sh3-rom.c. */ enum { @@ -30,6 +36,7 @@ enum ARG0_REGNUM =3D 4, ARGLAST_REGNUM =3D 7, FP_REGNUM =3D 14, + SP_REGNUM =3D 15, PC_REGNUM =3D 16, PR_REGNUM =3D 17, GBR_REGNUM =3D 18, @@ -83,8 +90,26 @@ enum FV_LAST_REGNUM =3D 79 }; =20 +#define SH_NUM_REGS 67 + +struct sh_frame_cache +{ + /* Base address. */ + CORE_ADDR base; + LONGEST sp_offset; + CORE_ADDR pc; + + /* Flag showing that a frame has been created in the prologue code. */ + int uses_fp; + + /* Saved registers. */ + CORE_ADDR saved_regs[SH_NUM_REGS]; + CORE_ADDR saved_sp; +}; + extern gdbarch_init_ftype sh64_gdbarch_init; extern void sh64_show_regs (struct frame_info *); +extern struct sh_frame_cache *sh_frame_cache (struct frame_info *next_fram= e, void **this_cache); =20 /* This structure describes a register in a core-file. */ struct sh_corefile_regmap @@ -93,8 +118,32 @@ struct sh_corefile_regmap unsigned int offset; }; =20 +/* sh architecture specific information. */ struct gdbarch_tdep { + /* General-purpose registers. */ + struct regset *gregset; + int *gregset_reg_offset; + int gregset_num_regs; + size_t sizeof_gregset; + + /* Floating-point registers. */ + struct regset *fpregset; + size_t sizeof_fpregset; + + /* Offset of saved PC in jmp_buf. */ + int jb_pc_offset; + + /* Detect sigtramp. */ + int (*sigtramp_p) (struct frame_info *); + + /* Get address of sigcontext for sigtramp. */ + CORE_ADDR (*sigcontext_addr) (struct frame_info *); + + /* Offset of registers in `struct sigcontext'. */ + int *sc_reg_offset; + int sc_num_regs; + /* Non-NULL when debugging from a core file. Provides the offset where each general-purpose register is stored inside the associated core file section. */ --- /dev/null +++ gdb-7.4/gdb/sh-linux-nat.c @@ -0,0 +1,269 @@ +/* Low level SH interface to ptrace, for GDB when running native. + Copyright (C) 2002, 2004 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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.= */ + +#include "defs.h" +#include "inferior.h" +#include "gdbcore.h" +#include "regcache.h" +#include "linux-nat.h" +#include "target.h" +#include "arch-utils.h" + +#include "gdb_assert.h" +#include "gdb_string.h" +#include +#include +#include +#include + +/* Prototypes for supply_gregset etc. */ +#include "gregset.h" +#include "sh-tdep.h" + +/* Defines ps_err_e, struct ps_prochandle. */ +#include "gdb_proc_service.h" + +//#include + +#define SH_LINUX_NUM_REGS 40 +/* This table must line up with REGISTER_NAME in "sh-tdep.c". */ +static const int regmap[] =3D +{ + /* general registers 0-15 */ + REG_REG0 , REG_REG0+1 , REG_REG0+2 , REG_REG0+3, + REG_REG0+4 , REG_REG0+5 , REG_REG0+6 , REG_REG0+7, + REG_REG0+8 , REG_REG0+9 , REG_REG0+10, REG_REG0+11, + REG_REG0+12, REG_REG0+13, REG_REG0+14, REG_REG0+15, + /* 16 - 22 */ + REG_PC, REG_PR, REG_GBR, -1, REG_MACH, REG_MACL, REG_SR, + /* 23, 24 */ + REG_FPUL, REG_FPSCR, + /* floating point registers 25 - 40 */ + REG_FPREG0 , REG_FPREG0+1 , REG_FPREG0+2 , REG_FPREG0+3 , + REG_FPREG0+4 , REG_FPREG0+5 , REG_FPREG0+6 , REG_FPREG0+7 , + REG_FPREG0+8 , REG_FPREG0+9 , REG_FPREG0+10, REG_FPREG0+11, + REG_FPREG0+12, REG_FPREG0+13, REG_FPREG0+14, REG_FPREG0+15, +}; + +CORE_ADDR +register_u_addr (CORE_ADDR blockend, int regnum) +{ + if (regnum < 0 || regnum >=3D sizeof regmap/sizeof regmap[0]) + return (CORE_ADDR)-1; + return (blockend + 4 * regmap[regnum]); +} + +=0C +/* Return the address in the core dump or inferior of register REGNO. + BLOCKEND is the address of the end of the user structure. */ + +CORE_ADDR +register_addr (int regno, CORE_ADDR blockend) +{ + CORE_ADDR addr; + + if (regno < 0 || regno >=3D SH_LINUX_NUM_REGS) { + internal_error (__FILE__, __LINE__, + _("Got request for bad register number %d."), regno); + } + + REGISTER_U_ADDR (addr, blockend, regno); + + return addr; +} + +/* Fetch one register. */ + +static void +fetch_register (struct regcache *regcache, int tid, int regno) +{ + int val; + + if (cannot_fetch_register (regno)) + { + regcache_raw_supply (regcache, regno, NULL); + return; + } + + errno =3D 0; + val =3D ptrace (PTRACE_PEEKUSER, tid, register_addr (regno, 0), 0); + if (errno !=3D 0) + perror_with_name (_("Couldn't get registers")); + + regcache_raw_supply (regcache, regno, &val); +} + +/* Store one register. */ + +static void +store_register (struct regcache *regcache, int tid, int regno) +{ + int val; + + if (cannot_store_register (regno)) + return; + + errno =3D 0; + regcache_raw_collect (regcache, regno, &val); + ptrace (PTRACE_POKEUSER, tid, register_addr (regno, 0), val); + if (errno !=3D 0) + perror_with_name (_("Couldn't write registers")); +} + +/* Transfering the general-purpose registers between GDB, inferiors + and core files. */ + +/* Fill GDB's register array with the general-purpose register values + in *GREGSETP. */ + +void +supply_gregset (struct regcache *regcache, const elf_gregset_t *gregsetp) +{ + elf_greg_t *regp =3D (elf_greg_t *) gregsetp; + int i; + + for (i =3D 0; i < 23; i++) + if (regmap[i] =3D=3D -1) + regcache_raw_supply (regcache, i, NULL); + else + regcache_raw_supply (regcache, i, (char *) (regp + regmap[i])); +} + +/* Fill register REGNO (if it is a general-purpose register) in + *GREGSETPS with the value in GDB's register array. If REGNO is -1, + do this for all registers. */ + +void +fill_gregset (const struct regcache *regcache, elf_gregset_t *gregsetp, in= t regno) +{ + elf_greg_t *regp =3D (elf_greg_t *) gregsetp; + int i; + + for (i =3D 0; i < 23; i++) + if (regmap[i] !=3D -1 && (regno =3D=3D -1 || regno =3D=3D i)) + regcache_raw_collect (regcache, i, (char *) (regp + regmap[i])); +} + +/* Transfering floating-point registers between GDB, inferiors and cores. = */ + +/* Fill GDB's register array with the floating-point register values in + *FPREGSETP. */ + +void +supply_fpregset (struct regcache *regcache, const elf_fpregset_t *fpregset= p) +{ + int i; + long *regp =3D (long *)fpregsetp; + + for (i =3D 0; i < 16; i++) + regcache_raw_supply (regcache, 25 + i, (char *) (regp + i)); + regcache_raw_supply (regcache, FPUL_REGNUM, (char *) (regp + REG_FPUL - = REG_FPREG0)); + regcache_raw_supply (regcache, FPSCR_REGNUM, (char *) (regp + REG_FPSCR = - REG_FPREG0)); +} + +/* Fill register REGNO (if it is a floating-point register) in + *FPREGSETP with the value in GDB's register array. If REGNO is -1, + do this for all registers. */ + +void +fill_fpregset (const struct regcache *regcache, elf_fpregset_t *fpregsetp,= int regno) +{ + int i; + long *regp =3D (long *)fpregsetp; + + for (i =3D 0; i < 16; i++) + if ((regno =3D=3D -1) || (regno =3D=3D i)) + regcache_raw_collect (regcache, 25 + i, (char *) (regp + i)); + if ((regno =3D=3D -1) || regno =3D=3D FPSCR_REGNUM) + regcache_raw_collect (regcache, FPSCR_REGNUM, (char *) (regp + REG_FPS= CR - REG_FPREG0)); + if ((regno =3D=3D -1) || regno =3D=3D FPUL_REGNUM) + regcache_raw_collect (regcache, FPUL_REGNUM, (char *) (regp + REG_FPUL= - REG_FPREG0)); +} + +/* Transferring arbitrary registers between GDB and inferior. */ + +/* Check if register REGNO in the child process is accessible. + If we are accessing registers directly via the U area, only the + general-purpose registers are available. + All registers should be accessible if we have GETREGS support. */ +=20=20=20 +int +cannot_fetch_register (int regno) +{ + return (regno < 0 || regno >=3D sizeof regmap / sizeof regmap[0] || regm= ap[regno] =3D=3D -1); +} + +int +cannot_store_register (int regno) +{ + return (regno < 0 || regno >=3D sizeof regmap / sizeof regmap[0] || regm= ap[regno] =3D=3D -1); +} + +/* Fetch register values from the inferior. + If REGNO is negative, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +static void +sh_linux_fetch_inferior_registers (struct target_ops *ops, struct regcache= *regcache, int regno) +{ + int i; + int tid; + + /* GNU/Linux LWP ID's are process ID's. */ + if ((tid =3D TIDGET (inferior_ptid)) =3D=3D 0) + tid =3D PIDGET (inferior_ptid); /* Not a threaded program. */ + + for (i =3D 0; i < SH_LINUX_NUM_REGS; i++) + if (regno =3D=3D -1 || regno =3D=3D i) + fetch_register (regcache, tid, i); +} +/* Store our register values back into the inferior. + If REGNO is negative, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +static void +sh_linux_store_inferior_registers (struct target_ops *ops, struct regcache= *regcache, int regno) +{ + int i; + int tid; + + /* GNU/Linux LWP ID's are process ID's. */ + if ((tid =3D TIDGET (inferior_ptid)) =3D=3D 0) + tid =3D PIDGET (inferior_ptid); /* Not a threaded program. */ + + for (i =3D 0; i < SH_LINUX_NUM_REGS; i++) + if (regno =3D=3D -1 || regno =3D=3D i) + store_register (regcache, tid, i); +} + +void +_initialize_sh_linux_nat (void) +{ + struct target_ops *t; + + /* Fill in the generic GNU/Linux methods. */ + t =3D linux_target (); + + /* Add our register access methods. */ + t->to_fetch_registers =3D sh_linux_fetch_inferior_registers; + t->to_store_registers =3D sh_linux_store_inferior_registers; + + /* Register the target. */ + linux_nat_add_target (t); +} --- gdb-7.4.orig/gdb/sh-tdep.c +++ gdb-7.4/gdb/sh-tdep.c @@ -23,6 +23,9 @@ sac@cygnus.com. */ =20 #include "defs.h" +#include "arch-utils.h" +#include "command.h" +#include "dummy-frame.h" #include "frame.h" #include "frame-base.h" #include "frame-unwind.h" @@ -39,6 +42,7 @@ #include "arch-utils.h" #include "floatformat.h" #include "regcache.h" +#include "regset.h" #include "doublest.h" #include "osabi.h" #include "reggroups.h" @@ -71,23 +75,6 @@ static const char *sh_active_calling_con =20 static void (*sh_show_regs) (struct frame_info *); =20 -#define SH_NUM_REGS 67 - -struct sh_frame_cache -{ - /* Base address. */ - CORE_ADDR base; - LONGEST sp_offset; - CORE_ADDR pc; - - /* Flag showing that a frame has been created in the prologue code. */ - int uses_fp; - - /* Saved registers. */ - CORE_ADDR saved_regs[SH_NUM_REGS]; - CORE_ADDR saved_sp; -}; - static int sh_is_renesas_calling_convention (struct type *func_type) { @@ -1042,7 +1029,7 @@ sh_treat_as_flt_p (struct type *type) return 0; /* Otherwise if the type of that member is float, the whole type is treated as float. */ - if (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) =3D=3D TYPE_CODE_FLT) + if (TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, 0))) =3D=3D TYPE_CO= DE_FLT) return 1; /* Otherwise it's not treated as float. */ return 0; @@ -1092,7 +1079,7 @@ sh_push_dummy_call_fpu (struct gdbarch * in four registers available. Loop thru args from first to last. */ for (argnum =3D 0; argnum < nargs; argnum++) { - type =3D value_type (args[argnum]); + type =3D check_typedef (value_type (args[argnum])); len =3D TYPE_LENGTH (type); val =3D sh_justify_value_in_reg (gdbarch, args[argnum], len); =20 @@ -2510,7 +2497,7 @@ sh_dwarf2_frame_init_reg (struct gdbarch reg->how =3D DWARF2_FRAME_REG_UNDEFINED; } =20 -static struct sh_frame_cache * +struct sh_frame_cache * sh_alloc_frame_cache (void) { struct sh_frame_cache *cache; @@ -2537,7 +2524,7 @@ sh_alloc_frame_cache (void) return cache; } =20 -static struct sh_frame_cache * +struct sh_frame_cache * sh_frame_cache (struct frame_info *this_frame, void **this_cache) { struct gdbarch *gdbarch =3D get_frame_arch (this_frame); @@ -2595,9 +2582,9 @@ sh_frame_cache (struct frame_info *this_ return cache; } =20 -static struct value * -sh_frame_prev_register (struct frame_info *this_frame, - void **this_cache, int regnum) +struct value * +sh_frame_prev_register (struct frame_info *this_frame, void **this_cache, + int regnum) { struct gdbarch *gdbarch =3D get_frame_arch (this_frame); struct sh_frame_cache *cache =3D sh_frame_cache (this_frame, this_cache); @@ -2611,7 +2598,7 @@ sh_frame_prev_register (struct frame_inf the current frame. Frob regnum so that we pull the value from the correct place. */ if (regnum =3D=3D gdbarch_pc_regnum (gdbarch)) - regnum =3D PR_REGNUM; + regnum =3D PR_REGNUM; /* XXX: really? */ =20 if (regnum < SH_NUM_REGS && cache->saved_regs[regnum] !=3D -1) return frame_unwind_got_memory (this_frame, regnum, @@ -2855,8 +2842,8 @@ sh_regset_from_core_section (struct gdba static struct gdbarch * sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { - struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; + struct gdbarch *gdbarch; =20 sh_show_regs =3D sh_generic_show_regs; switch (info.bfd_arch_info->mach) @@ -2919,6 +2906,18 @@ sh_gdbarch_init (struct gdbarch_info inf tdep =3D XZALLOC (struct gdbarch_tdep); gdbarch =3D gdbarch_alloc (&info, tdep); =20 + /* General-purpose registers. */ + tdep->gregset =3D NULL; + tdep->gregset_reg_offset =3D NULL; + tdep->gregset_num_regs =3D 23; + tdep->sizeof_gregset =3D 0; + + /* Floating-point registers. */ + tdep->fpregset =3D NULL; + tdep->sizeof_fpregset =3D 34*4; + + tdep->jb_pc_offset =3D -1; + set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT); set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT); set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT); @@ -3064,10 +3063,11 @@ sh_gdbarch_init (struct gdbarch_info inf break; } =20 + dwarf2_append_unwinders (gdbarch); + /* Hook in ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); =20 - dwarf2_append_unwinders (gdbarch); frame_unwind_append_unwinder (gdbarch, &sh_frame_unwind); =20 return gdbarch; --- /dev/null +++ gdb-7.4/gdb/testsuite/gdb.asm/sh-linux.inc @@ -0,0 +1,78 @@ +# You'll find a bunch of nop opcodes in the below macros. They are +# there to keep the code correctly aligned. Be careful to maintain +# them when changing the code. + + comment "subroutine declare" + .purgem gdbasm_declare + .macro gdbasm_declare name + .align 1 + .global \name +\name: + .endm + + comment "subroutine prologue" + .macro gdbasm_enter + mov.l r14,@-r15 + sts.l pr,@-r15 + mov r15,r14 + nop + .endm + + comment "subroutine epilogue" + .macro gdbasm_leave + mov r14,r15 + lds.l @r15+,pr + mov.l @r15+,r14 + rts + nop + nop + .endm + + comment "subroutine end" + .purgem gdbasm_end + .macro gdbasm_end name + .size \name, .-_foo1 + .align 1 + .endm + + comment "subroutine call" + .macro gdbasm_call subr + mov.l .Lconst\@,r1 + bra .Lafterconst\@ + nop + .align 2 +.Lconst\@: + .long \subr +.Lafterconst\@: + jsr @r1 + nop + .endm + + .macro gdbasm_several_nops + nop + nop + nop + nop + .endm + + comment "exit (0)" + .macro gdbasm_exit0 + sleep + nop + .endm + + comment "crt0 startup" + .macro gdbasm_startup + mov #0,r14 + .endm + + comment "Declare a data variable" + .purgem gdbasm_datavar + .macro gdbasm_datavar name value + .data + .align 2 + .type \name, @object + .size \name, 4 +\name: + .long \value + .endm --- gdb-7.4.orig/gdb/testsuite/gdb.asm/sh.inc +++ gdb-7.4/gdb/testsuite/gdb.asm/sh.inc @@ -40,9 +40,8 @@ mov.l .Lconst\@,r1 bra .Lafterconst\@ nop - nop -.Lconst\@: .align 2 +.Lconst\@: .long \subr .align 1 .Lafterconst\@: --- gdb-7.4.orig/gdb/testsuite/gdb.asm/asm-source.exp +++ gdb-7.4/gdb/testsuite/gdb.asm/asm-source.exp @@ -111,6 +111,11 @@ switch -glob -- [istarget] { append link-flags " -m elf32ppc" } } + "sh*-linux*" { + set asm-arch sh-linux + set asm-flags "-I${srcdir}/${subdir} -I${objdir}/${subdir}" + set debug-flags "-gdwarf-2" + } "sh*-*-*" { set asm-arch sh set debug-flags "-gdwarf-2" --- gdb-7.4.orig/gdb/testsuite/gdb.base/sigall.c +++ gdb-7.4/gdb/testsuite/gdb.base/sigall.c @@ -1,9 +1,9 @@ #include #include =20 -#ifdef __sh__ -#define signal(a,b) /* Signals not supported on this target - make them go= away */ -#endif + + + =20 /* Signal handlers, we set breakpoints in them to make sure that the signals really get delivered. */ --- gdb-7.4.orig/gdb/testsuite/gdb.base/signals.c +++ gdb-7.4/gdb/testsuite/gdb.base/signals.c @@ -3,10 +3,10 @@ #include #include =20 -#ifdef __sh__ -#define signal(a,b) /* Signals not supported on this target - make them go= away */ -#define alarm(a) /* Ditto for alarm() */ -#endif + + + + =20 static int count =3D 0; =20 --- gdb-7.4.orig/gdb/testsuite/gdb.base/annota1.c +++ gdb-7.4/gdb/testsuite/gdb.base/annota1.c @@ -1,9 +1,9 @@ #include #include =20 -#ifdef __sh__ -#define signal(a,b) /* Signals not supported on this target - make them go= away */ -#endif + + + =20 =20 #ifdef PROTOTYPES --- gdb-7.4.orig/gdb/testsuite/gdb.base/annota3.c +++ gdb-7.4/gdb/testsuite/gdb.base/annota3.c @@ -1,9 +1,9 @@ #include #include =20 -#ifdef __sh__ -#define signal(a,b) /* Signals not supported on this target - make them go= away */ -#endif + + + =20 =20 #ifdef PROTOTYPES --- /dev/null +++ gdb-7.4/gdb/config/sh/xm-linux.h @@ -0,0 +1,32 @@ +/* Native support for GNU/Linux, for GDB, the GNU debugger. + Copyright (C) 2000 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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.= */ + +#ifndef XM_LINUX_H +#define XM_LINUX_H + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +#define HAVE_TERMIOS + +#define NEED_POSIX_SETPGID + +/* Need R_OK etc, but USG isn't defined. */ +#include + +#endif /* #ifndef XM_LINUX_H */ --- /dev/null +++ gdb-7.4/gdb/config/sh/nm-linux.h @@ -0,0 +1,54 @@ +/* Native-dependent definitions for SuperH running Linux, for GDB. + Copyright 2004 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef NM_LINUX_H +#define NM_LINUX_H + +/* Get generic Linux native definitions. */ +#include "config/nm-linux.h" +/* Support for the user area. */ + +/* Return the size of the user struct. */ +extern int kernel_u_size (void); +#define KERNEL_U_SIZE kernel_u_size() + +/* This is the amount to substract from u.u_ar0 to get the offset in + the core file of the register values. */ +#define KERNEL_U_ADDR 0 + +#define U_REGS_OFFSET 0 + +extern CORE_ADDR register_u_addr (CORE_ADDR blockend, int regnum); +#define REGISTER_U_ADDR(addr, blockend, regnum) \ + (addr) =3D register_u_addr (blockend, regnum) + +/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. = */ +#define FETCH_INFERIOR_REGISTERS + +/* Nevertheless, define CANNOT_{FETCH,STORE}_REGISTER, because we + might fall back on the code `infptrace.c' (well a copy of that code + in `sh-linux-nat.c' for now) and we can access only the + general-purpose registers in that way. */ +extern int cannot_fetch_register (int regno); +extern int cannot_store_register (int regno); +#define CANNOT_FETCH_REGISTER(regno) cannot_fetch_register (regno) +#define CANNOT_STORE_REGISTER(regno) cannot_store_register (regno) + +#endif /* NM_LINUX_H */ --- /dev/null +++ gdb-7.4/gdb/config/sh/linux.mh @@ -0,0 +1,8 @@ +# Host: Renesas Super-H running GNU/Linux +NAT_FILE=3D nm-linux.h +NATDEPFILES=3D inf-ptrace.o fork-child.o corelow.o \ + sh-linux-nat.o \ + proc-service.o linux-thread-db.o gcore.o \ + linux-nat.o linux-fork.o + +LOADLIBES=3D -ldl -rdynamic Best regards, --=20 H=E9ctor Or=F3n --lrZ03NoBR/3+SXJZ Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-length: 836 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAEBCAAGBQJOxZamAAoJEK8ig6p24qx7Uw0QAJu7SyWXgZ2PmNH9U4hNzP1D cvHmn0ZQ731NaZGPGU5+7uEnFbAPKMYA4fvHziAhgW3hwEzVbNheSZ7a8psxoqYA a/n+CmvDJ93coYqcBGjpixL32iSl4LHfeUJ/I6y49F12yvzPjvdiTAL//uJKaCnB 47lWniSNrhb+452zY5lC1KxH7WXh8yOsxTbSwsJjZIqUwG5fIy1eEvkkv/PkR/93 DKTQEf075EhCCVl53yHJuBlj6h4mtbQyKDgMrcpol0agA7CdeZRswpQyHpPLLpV+ neZE1rnLWobATWJkPqmHQQnJhLhDxK0RkML/sCgZ0o/i/qFXnfweb6yfqQST67xB 3AeiulaWyrjHAWl1B4JuRivSGQWIppIyNPWGdOhFV5odYeaeTcpHUJGrXpuY4kil Jn7Lu5QCXteikuCrVw3o9YuP66t4XZkebHfIxaTlAd0m+lQBD9qAxcoFCeir3aSK V9/JSjiTWQHfMgsefpHm81MYX7HriBo6gEViumgRao+HoXojIVJnD26AxfY5XNFT AAdhAwI1vUah/zjcsK8hp8dh5qWRKes4oGaeqGDxqicTLTM5b/ly8RV9vfj/4FgJ 9sq10zUk0R9km+BTGh+DaXaiL0ZP6J0HDMKsvl8T+GJAiCHbb2T71b07150XKY9f 9K9JgTEGHjseeJb1Nmu4 =chZ7 -----END PGP SIGNATURE----- --lrZ03NoBR/3+SXJZ--