blob: 27c49d53a9280baf90d4a5e88a4e76a0b898640c [file] [log] [blame]
Juan Cespedesf1bfe202002-03-27 00:22:23 +01001#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <sys/types.h>
6#include <sys/wait.h>
7#include <signal.h>
8#include <sys/ptrace.h>
9#include <asm/ptrace.h>
Ian Wienand9a2ad352006-02-20 22:44:45 +010010#include <elf.h>
Luis Machado55c5feb2008-03-12 15:56:01 +010011#include <errno.h>
Juan Cespedesf1bfe202002-03-27 00:22:23 +010012
13#include "ltrace.h"
14
15#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
16# define PTRACE_PEEKUSER PTRACE_PEEKUSR
17#endif
18
19#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
20# define PTRACE_POKEUSER PTRACE_POKEUSR
21#endif
22
Juan Cespedesf1350522008-12-16 18:19:58 +010023void
Juan Cespedesa8909f72009-04-28 20:02:41 +020024get_arch_dep(Process *proc) {
Ian Wienand9a2ad352006-02-20 22:44:45 +010025#ifdef __powerpc64__
Ian Wienand2d45b1a2006-02-20 22:48:07 +010026 if (proc->arch_ptr)
27 return;
28 proc->mask_32bit = (proc->e_machine == EM_PPC);
29 proc->arch_ptr = (void *)1;
Ian Wienand9a2ad352006-02-20 22:44:45 +010030#endif
Juan Cespedes5c3fe062004-06-14 18:08:37 +020031}
32
Luis Machado55c5feb2008-03-12 15:56:01 +010033/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */
Juan Cespedesf1bfe202002-03-27 00:22:23 +010034#define SYSCALL_INSN 0x44000002
Luis Machado55c5feb2008-03-12 15:56:01 +010035
36unsigned int greg = 3;
37unsigned int freg = 1;
38unsigned int vreg = 2;
39
Juan Cespedesf1350522008-12-16 18:19:58 +010040int
Juan Cespedesa8909f72009-04-28 20:02:41 +020041syscall_p(Process *proc, int status, int *sysnum) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010042 if (WIFSTOPPED(status)
43 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
Ian Wienand9a2ad352006-02-20 22:44:45 +010044 long pc = (long)get_instruction_pointer(proc);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010045 int insn =
46 (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long),
47 0);
Juan Cespedesf1bfe202002-03-27 00:22:23 +010048
49 if (insn == SYSCALL_INSN) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010050 *sysnum =
51 (int)ptrace(PTRACE_PEEKUSER, proc->pid,
52 sizeof(long) * PT_R0, 0);
53 if (proc->callstack_depth > 0
54 && proc->callstack[proc->callstack_depth -
55 1].is_syscall) {
Juan Cespedesf1bfe202002-03-27 00:22:23 +010056 return 2;
57 }
Juan Cespedes5bfb0612002-03-31 20:01:28 +020058 return 1;
Juan Cespedesf1bfe202002-03-27 00:22:23 +010059 }
60 }
61 return 0;
62}
63
Luis Machado55c5feb2008-03-12 15:56:01 +010064/* Grab functions arguments based on the PPC64 ABI. */
Juan Cespedesf1350522008-12-16 18:19:58 +010065long
Juan Cespedesa8909f72009-04-28 20:02:41 +020066gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
Luis Machado55c5feb2008-03-12 15:56:01 +010067 long data;
68
69 if (type == LT_TOF_FUNCTIONR) {
70 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE)
71 return ptrace (PTRACE_PEEKUSER, proc->pid,
72 sizeof (long) * (PT_FPR0 + 1), 0);
73 else
74 return ptrace (PTRACE_PEEKUSER, proc->pid,
75 sizeof (long) * PT_R3, 0);
Juan Cespedesf1bfe202002-03-27 00:22:23 +010076 }
Luis Machado55c5feb2008-03-12 15:56:01 +010077
78 /* Check if we're entering a new function call to list parameters. If
79 so, initialize the register control variables to keep track of where
80 the parameters were stored. */
81 if (type == LT_TOF_FUNCTION && arg_num == 0) {
82 /* Initialize the set of registrers for parameter passing. */
83 greg = 3;
84 freg = 1;
85 vreg = 2;
86 }
87
88 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) {
89 if (freg <= 13 || (proc->mask_32bit && freg <= 8)) {
90 data = ptrace (PTRACE_PEEKUSER, proc->pid,
91 sizeof (long) * (PT_FPR0 + freg), 0);
92
93 if (info->type == ARGTYPE_FLOAT) {
94 /* float values passed in FP registers are automatically
95 promoted to double. We need to convert it back to float
96 before printing. */
97 union { long val; float fval; double dval; } cvt;
98 cvt.val = data;
99 cvt.fval = (float) cvt.dval;
100 data = cvt.val;
101 }
102
103 freg++;
104 greg++;
105
106 return data;
107 }
108 }
109 else if (greg <= 10) {
110 data = ptrace (PTRACE_PEEKUSER, proc->pid,
111 sizeof (long) * greg, 0);
112 greg++;
113
114 return data;
115 }
116 else
117 return ptrace (PTRACE_PEEKDATA, proc->pid,
118 proc->stack_pointer + sizeof (long) *
119 (arg_num - 8), 0);
120
Juan Cespedesf1bfe202002-03-27 00:22:23 +0100121 return 0;
122}
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200123
Juan Cespedesf1350522008-12-16 18:19:58 +0100124void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200125save_register_args(enum tof type, Process *proc) {
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200126}
Luis Machado55c5feb2008-03-12 15:56:01 +0100127
128/* Read a single long from the process's memory address 'addr'. */
Juan Cespedesf1350522008-12-16 18:19:58 +0100129int
Juan Cespedesa8909f72009-04-28 20:02:41 +0200130arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
Luis Machado55c5feb2008-03-12 15:56:01 +0100131 long pointed_to;
132
133 errno = 0;
134
135 pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0);
136
137 if (pointed_to == -1 && errno)
138 return -errno;
139
140 /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we
141 need to shift the long values returned by ptrace to end up with
142 the correct value. */
143
144 if (info) {
145 if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER
146 || info->type == ARGTYPE_STRING))) {
147 pointed_to = pointed_to >> 32;
148
149 /* Make sure we have nothing in the upper word so we can
150 do a explicit cast from long to int later in the code. */
151 pointed_to &= 0x00000000ffffffff;
152 }
153 }
154
155 *result = pointed_to;
156 return 0;
157}