Imported Upstream version 0.5.3
[platform/upstream/ltrace.git] / sysdeps / linux-gnu / mipsel / trace.c
1 #include "config.h"
2
3 #include <sys/types.h>
4 #include <sys/wait.h>
5 #include <signal.h>
6 #include <sys/ptrace.h>
7 #include <asm/ptrace.h>
8 #include "debug.h"
9 #include "common.h"
10 #include "mipsel.h"
11 #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
12 # define PTRACE_PEEKUSER PTRACE_PEEKUSR
13 #endif
14
15 #if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
16 # define PTRACE_POKEUSER PTRACE_POKEUSR
17 #endif
18
19
20 /**
21    \addtogroup mipsel Mipsel specific functions.
22
23    These are the functions that it looks like I need to implement in
24    order to get ltrace to work on our target.
25
26    @{
27  */
28
29 /**
30    \param proc The process that had an event.
31
32    Called by \c next_event() right after the return from wait.
33
34    Most targets just return here. A couple use proc->arch_ptr for a
35    private data area.
36  */
37 void
38 get_arch_dep(Process *proc) {
39 }
40
41 /**
42    \param proc Process that had event.
43    \param status From \c wait()
44    \param sysnum 0-based syscall number.
45    \return 1 if syscall, 2 if sysret, 0 otherwise.
46
47    Called by \c next_event() after the call to get_arch_dep()
48
49    It seems that the ptrace call trips twice on a system call, once
50    just before the system call and once when it returns. Both times,
51    the pc points at the instruction just after the mipsel "syscall"
52    instruction.
53
54    There are several possiblities for system call sets, each is offset
55    by a base from the others. On our system, it looks like the base
56    for the system calls is 4000.
57  */
58 int
59 syscall_p(Process *proc, int status, int *sysnum) {
60         if (WIFSTOPPED(status)
61                         && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
62                 /* get the user's pc (plus 8) */
63                 long pc = (long)get_instruction_pointer(proc);
64                 /* fetch the SWI instruction */
65                 int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0);
66                 int num = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 8, 0);
67
68                 /*
69                    On a mipsel,  syscall looks like:
70                    24040fa1    li v0, 0x0fa1   # 4001 --> _exit syscall
71                    0000000c    syscall
72                  */
73                 if(insn!=0x0000000c){
74                         return 0;
75                 }
76
77                 *sysnum = (num & 0xFFFF) - 4000;
78                 /* if it is a syscall, return 1 or 2 */
79                 if (proc->callstack_depth > 0 &&
80                                 proc->callstack[proc->callstack_depth - 1].is_syscall &&
81                                 proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) {
82                         return 2;
83                 }
84
85                 if (*sysnum >= 0) {
86                         return 1;
87                 }
88         }
89         return 0;
90 }
91 /**
92    \param type Function/syscall call or return.
93    \param proc The process that had an event.
94    \param arg_num -1 for return value,
95    \return The argument to fetch.
96
97    A couple of assumptions.
98
99 -  Type is LT_TOF_FUNCTIONR or LT_TOF_SYSCALLR if arg_num==-1. These
100    types are only used in calls for output_right(), which only uses -1
101    for arg_num.
102 -  Type is LT_TOF_FUNCTION or LT_TOF_SYSCALL for args 0...4.
103 -   I'm only displaying the first 4 args (Registers a0..a3). Good
104    enough for now.
105
106   Mipsel conventions seem to be:
107 - syscall parameters: r4...r9
108 - syscall return: if(!a3){ return v0;} else{ errno=v0;return -1;}
109 - function call: r4..r7. Not sure how to get arg number 5.
110 - function return: v0
111
112 The argument registers are wiped by a call, so it is a mistake to ask
113 for arguments on a return. If ltrace does this, we will need to cache
114 arguments somewhere on the call.
115
116 I'm not doing any floating point support here.
117
118 */
119 long
120 gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
121         long ret;
122         debug(2,"type %d arg %d",type,arg_num);
123         if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL){
124                 if(arg_num <4){
125                         ret=ptrace(PTRACE_PEEKUSER,proc->pid,off_a0+arg_num,0);
126                         debug(2,"ret = %#lx",ret);
127                         return ret;
128                 } else {
129                         // If we need this, I think we can look at [sp+16] for arg_num==4.
130                         CP;
131                         return 0;
132                 }
133         }
134         if(arg_num>=0){
135                 fprintf(stderr,"args on return?");
136         }
137         if(type == LT_TOF_FUNCTIONR) {
138                 return  ptrace(PTRACE_PEEKUSER,proc->pid,off_v0,0);
139         }
140         if (type == LT_TOF_SYSCALLR) {
141                 unsigned a3=ptrace(PTRACE_PEEKUSER, proc->pid,off_a3,0);
142                 unsigned v0=ptrace(PTRACE_PEEKUSER, proc->pid,off_v0,0);
143                 if(!a3){
144                         return v0;
145                 }
146                 return -1;
147         }
148         fprintf(stderr, "gimme_arg called with wrong arguments\n");
149         return 0;
150 }
151
152 /**
153    \param type Type of call/return
154    \param proc Process to work with.
155
156    Called by \c output_left(), which is called on a syscall or
157    function.
158
159    The other architectures stub this out, but seems to be the place to
160    stash off the arguments on a call so we have them on the return.
161
162 */
163 void
164 save_register_args(enum tof type, Process *proc) {
165 }
166
167 /**@}*/