Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:11.1:kernel-2.6.32
ltrace
ltrace.powerpc-ABI-support.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File ltrace.powerpc-ABI-support.patch of Package ltrace
Bug 364988 - LTC41151 - ltrace64 testcase (parameters.exp) fails in SLES10 2008-02-27 Luis Machado <luisgpm@br.ibm.com> * sysdeps/linux-gnu/ppc/trace.c (arch_umovelong): New function. * sysdeps/linux-gnu/ppc/regs.c (get_instruction): New function. (get_count_register): New function. * sysdeps/linux-gnu/ppc/arch.h (ARCH_HAVE_UMOVELONG): New define. * sysdeps/linux-gnu/trace.c (umovelong): Create arch-specific variant. * ltrace.h (umovelong): Change prototype. * process_event.c (process_breakpoint): Handle specifics of ppc32 PLT. * display_args.c: Call umovelong with info parameter. --- display_args.c | 6 +- ltrace.h | 2 process_event.c | 28 +++++++---- sysdeps/linux-gnu/ppc/arch.h | 3 + sysdeps/linux-gnu/ppc/regs.c | 7 ++ sysdeps/linux-gnu/ppc/trace.c | 103 +++++++++++++++++++++++++++++++++++++----- sysdeps/linux-gnu/trace.c | 37 +++++++++------ 7 files changed, 148 insertions(+), 38 deletions(-) --- a/display_args.c +++ b/display_args.c @@ -32,7 +32,8 @@ static long get_length(enum tof type, st if (len_spec > 0) return len_spec; if (type == LT_TOF_STRUCT) { - umovelong(proc, st + st_info->u.struct_info.offset[-len_spec-1], &len); + umovelong (proc, st + st_info->u.struct_info.offset[-len_spec-1], + &len, st_info->u.struct_info.fields[-len_spec-1]); return len; } @@ -135,7 +136,8 @@ static int display_pointer(enum tof type } else { if (value == 0) return fprintf(output, "NULL"); - else if (umovelong(proc, (void *) value, &pointed_to) < 0) + else if (umovelong (proc, (void *) value, &pointed_to, + info->u.ptr_info.info) < 0) return fprintf(output, "?"); else return display_value(type, proc, pointed_to, inner, --- a/ltrace.h +++ b/ltrace.h @@ -250,7 +250,7 @@ extern void continue_enabling_breakpoint extern long gimme_arg(enum tof type, struct process *proc, int arg_num, arg_type_info *info); extern void save_register_args(enum tof type, struct process *proc); extern int umovestr(struct process *proc, void *addr, int len, void *laddr); -extern int umovelong(struct process *proc, void *addr, long *result); +extern int umovelong (struct process *proc, void *addr, long *result, arg_type_info *info); extern int ffcheck(void *maddr); extern void *sym2addr(struct process *, struct library_symbol *); --- a/process_event.c +++ b/process_event.c @@ -248,21 +248,29 @@ static void process_breakpoint(struct ev struct breakpoint *sbp; debug(2, "event: breakpoint (%p)", event->e_un.brk_addr); - if ((sbp = event->proc->breakpoint_being_enabled) != 0) { + #ifdef __powerpc__ - struct breakpoint *nxtbp; - char nop_inst[] = PPC_NOP; - if (memcmp(sbp->orig_value, nop_inst, PPC_NOP_LENGTH) == 0) { - nxtbp = address2bpstruct(event->proc, - event->e_un.brk_addr + - PPC_NOP_LENGTH); - if (nxtbp != 0) { - enable_breakpoint(event->proc->pid, sbp); - continue_after_breakpoint(event->proc, nxtbp); + /* Need to skip following NOP's to prevent a fake function from being stacked. */ + long stub_addr = (long) get_count_register(event->proc); + struct breakpoint *stub_bp = NULL; + char nop_instruction[] = PPC_NOP; + + stub_bp = address2bpstruct (event->proc, event->e_un.brk_addr); + + if (stub_bp) { + unsigned char *bp_instruction = stub_bp->orig_value; + + if (memcmp(bp_instruction, nop_instruction, + PPC_NOP_LENGTH) == 0) { + if (stub_addr != (long) event->e_un.brk_addr) { + set_instruction_pointer (event->proc, event->e_un.brk_addr + 4); + continue_process(event->proc->pid); return; } } + } #endif + if ((sbp = event->proc->breakpoint_being_enabled) != 0) { /* Reinsert breakpoint */ continue_enabling_breakpoint(event->proc->pid, event->proc-> --- a/sysdeps/linux-gnu/ppc/arch.h +++ b/sysdeps/linux-gnu/ppc/arch.h @@ -13,6 +13,9 @@ #define PLT_REINITALISATION_BP "_start" +/* Start of arch-specific functions. */ +#define ARCH_HAVE_UMOVELONG + #define PPC_NOP { 0x60, 0x00, 0x00, 0x00 } #define PPC_NOP_LENGTH 4 --- a/sysdeps/linux-gnu/ppc/regs.c +++ b/sysdeps/linux-gnu/ppc/regs.c @@ -38,3 +38,10 @@ void *get_return_addr(struct process *pr return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long) * PT_LNK, 0); } + +/* Grab the value of CTR registers. */ +void *get_count_register (struct process *proc) +{ + return (void *) ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * PT_CTR, 0); +} --- a/sysdeps/linux-gnu/ppc/trace.c +++ b/sysdeps/linux-gnu/ppc/trace.c @@ -8,6 +8,7 @@ #include <sys/ptrace.h> #include <asm/ptrace.h> #include <elf.h> +#include <errno.h> #include "ltrace.h" @@ -29,9 +30,13 @@ void get_arch_dep(struct process *proc) #endif } -/* Returns 1 if syscall, 2 if sysret, 0 otherwise. - */ +/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */ #define SYSCALL_INSN 0x44000002 + +unsigned int greg = 3; +unsigned int freg = 1; +unsigned int vreg = 2; + int syscall_p(struct process *proc, int status, int *sysnum) { if (WIFSTOPPED(status) @@ -56,21 +61,97 @@ int syscall_p(struct process *proc, int return 0; } +/* Grab functions arguments based on the PPC64 ABI. */ long gimme_arg(enum tof type, struct process *proc, int arg_num, arg_type_info *info) { - if (arg_num == -1) { /* return value */ - return ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long) * PT_R3, - 0); - } else if (arg_num < 8) { - return ptrace(PTRACE_PEEKUSER, proc->pid, - sizeof(long) * (arg_num + PT_R3), 0); - } else { - return ptrace(PTRACE_PEEKDATA, proc->pid, - proc->stack_pointer + 8 * (arg_num - 8), 0); + long data; + + if (type == LT_TOF_FUNCTIONR) { + if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) + return ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * (PT_FPR0 + 1), 0); + else + return ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * PT_R3, 0); + } + + /* Check if we're entering a new function call to list parameters. If + so, initialize the register control variables to keep track of where + the parameters were stored. */ + if (type == LT_TOF_FUNCTION && arg_num == 0) { + /* Initialize the set of registrers for parameter passing. */ + greg = 3; + freg = 1; + vreg = 2; + } + + if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) { + if (freg <= 13 || (proc->mask_32bit && freg <= 8)) { + data = ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * (PT_FPR0 + freg), 0); + + if (info->type == ARGTYPE_FLOAT) { + /* float values passed in FP registers are automatically + promoted to double. We need to convert it back to float + before printing. */ + union { long val; float fval; double dval; } cvt; + cvt.val = data; + cvt.fval = (float) cvt.dval; + data = cvt.val; + } + + freg++; + greg++; + + return data; + } } + else if (greg <= 10) { + data = ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * greg, 0); + greg++; + + return data; + } + else + return ptrace (PTRACE_PEEKDATA, proc->pid, + proc->stack_pointer + sizeof (long) * + (arg_num - 8), 0); + return 0; } void save_register_args(enum tof type, struct process *proc) { } + +/* Read a single long from the process's memory address 'addr'. */ +int arch_umovelong (struct process *proc, void *addr, long *result, arg_type_info *info) +{ + long pointed_to; + + errno = 0; + + pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); + + if (pointed_to == -1 && errno) + return -errno; + + /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we + need to shift the long values returned by ptrace to end up with + the correct value. */ + + if (info) { + if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER + || info->type == ARGTYPE_STRING))) { + pointed_to = pointed_to >> 32; + + /* Make sure we have nothing in the upper word so we can + do a explicit cast from long to int later in the code. */ + pointed_to &= 0x00000000ffffffff; + } + } + + *result = pointed_to; + return 0; +} --- a/sysdeps/linux-gnu/trace.c +++ b/sysdeps/linux-gnu/trace.c @@ -73,6 +73,29 @@ static int fork_exec_syscalls[][5] = { #endif }; +#ifdef ARCH_HAVE_UMOVELONG +extern int arch_umovelong (struct process *, void *, long *, arg_type_info *); +int umovelong (struct process *proc, void *addr, long *result, arg_type_info *info) +{ + return arch_umovelong (proc, addr, result, info); +} +#else +/* Read a single long from the process's memory address 'addr' */ +int umovelong (struct process *proc, void *addr, long *result, arg_type_info *info) +{ + long pointed_to; + + errno = 0; + pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); + if (pointed_to == -1 && errno) + return -errno; + + *result = pointed_to; + return 0; +} +#endif + + /* Returns 1 if the sysnum may make a new child to be created * (ie, with fork() or clone()) * Returns 0 otherwise. @@ -207,20 +230,6 @@ void continue_after_breakpoint(struct pr } } -/* Read a single long from the process's memory address 'addr' */ -int umovelong(struct process *proc, void *addr, long *result) -{ - long pointed_to; - - errno = 0; - pointed_to = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); - if (pointed_to == -1 && errno) - return -errno; - - *result = pointed_to; - return 0; -} - /* Read a series of bytes starting at the process's memory address 'addr' and continuing until a NUL ('\0') is seen or 'len' bytes have been read.
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor