Statistics
| Branch: | Revision:

root / linux-user / strace.c @ f3e3285d

History | View | Annotate | Download (7.5 kB)

1
#include <stdio.h>
2
#include <errno.h>
3
#include <sys/ipc.h>
4
#include <sys/msg.h>
5
#include <sys/sem.h>
6
#include <sys/shm.h>
7
#include <sys/select.h>
8
#include <sys/types.h>
9
#include <unistd.h>
10
#include "qemu.h"
11

    
12
int do_strace=0;
13

    
14
struct syscallname {
15
    int nr;
16
    char *name;
17
    char *format;
18
    void (*call)(struct syscallname *,
19
                 target_long, target_long, target_long,
20
                 target_long, target_long, target_long);
21
    void (*result)(struct syscallname *, target_long);
22
};
23

    
24
/*
25
 * Utility functions
26
 */
27
static void
28
print_ipc_cmd(int cmd)
29
{
30
#define output_cmd(val) \
31
if( cmd == val ) { \
32
    gemu_log(#val); \
33
    return; \
34
}
35

    
36
    cmd &= 0xff;
37

    
38
    /* General IPC commands */
39
    output_cmd( IPC_RMID );
40
    output_cmd( IPC_SET );
41
    output_cmd( IPC_STAT );
42
    output_cmd( IPC_INFO );
43
    /* msgctl() commands */
44
    #ifdef __USER_MISC
45
    output_cmd( MSG_STAT );
46
    output_cmd( MSG_INFO );
47
    #endif
48
    /* shmctl() commands */
49
    output_cmd( SHM_LOCK );
50
    output_cmd( SHM_UNLOCK );
51
    output_cmd( SHM_STAT );
52
    output_cmd( SHM_INFO );
53
    /* semctl() commands */
54
    output_cmd( GETPID );
55
    output_cmd( GETVAL );
56
    output_cmd( GETALL );
57
    output_cmd( GETNCNT );
58
    output_cmd( GETZCNT );
59
    output_cmd( SETVAL );
60
    output_cmd( SETALL );
61
    output_cmd( SEM_STAT );
62
    output_cmd( SEM_INFO );
63
    output_cmd( IPC_RMID );
64
    output_cmd( IPC_RMID );
65
    output_cmd( IPC_RMID );
66
    output_cmd( IPC_RMID );
67
    output_cmd( IPC_RMID );
68
    output_cmd( IPC_RMID );
69
    output_cmd( IPC_RMID );
70
    output_cmd( IPC_RMID );
71
    output_cmd( IPC_RMID );
72

    
73
    /* Some value we don't recognize */
74
    gemu_log("%d",cmd);
75
}
76

    
77
static void
78
print_fdset(int n, target_ulong target_fds_addr)
79
{
80
    int i;
81

    
82
    gemu_log("[");
83
    if( target_fds_addr ) {
84
        target_long *target_fds;
85

    
86
        if (!access_ok(VERIFY_READ, target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1)))
87
            return;
88

    
89
        target_fds = lock_user(target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1), 1);
90
        for (i=n; i>=0; i--) {
91
            if ((tswapl(target_fds[i / TARGET_LONG_BITS]) >> (i & (TARGET_LONG_BITS - 1))) & 1)
92
                gemu_log("%d,", i );
93
            }
94
        unlock_user(target_fds, target_fds_addr, 0);
95
    }
96
    gemu_log("]");
97
}
98

    
99
static void
100
print_timeval(target_ulong tv_addr)
101
{
102
    if( tv_addr ) {
103
        struct target_timeval *tv;
104

    
105
        if (!access_ok(VERIFY_READ, tv_addr, sizeof(*tv)))
106
            return;
107

    
108
        tv = lock_user(tv_addr, sizeof(*tv), 1);
109
        gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}",
110
                 tv->tv_sec, tv->tv_usec);
111
        unlock_user(tv, tv_addr, 0);
112
    } else
113
        gemu_log("NULL");
114
}
115

    
116
/*
117
 * Sysycall specific output functions
118
 */
119

    
120
/* select */
121
static long newselect_arg1 = 0;
122
static long newselect_arg2 = 0;
123
static long newselect_arg3 = 0;
124
static long newselect_arg4 = 0;
125
static long newselect_arg5 = 0;
126

    
127
static void
128
print_newselect(struct syscallname *name,
129
                target_long arg1, target_long arg2, target_long arg3,
130
                target_long arg4, target_long arg5, target_long arg6)
131
{
132
    gemu_log("%s(" TARGET_FMT_ld ",", name->name, arg1);
133
    print_fdset(arg1, arg2);
134
    gemu_log(",");
135
    print_fdset(arg1, arg3);
136
    gemu_log(",");
137
    print_fdset(arg1, arg4);
138
    gemu_log(",");
139
    print_timeval(arg5);
140
    gemu_log(")");
141

    
142
    /* save for use in the return output function below */
143
    newselect_arg1=arg1;
144
    newselect_arg2=arg2;
145
    newselect_arg3=arg3;
146
    newselect_arg4=arg4;
147
    newselect_arg5=arg5;
148
}
149

    
150
static void
151
print_semctl(struct syscallname *name,
152
             target_long arg1, target_long arg2, target_long arg3,
153
             target_long arg4, target_long arg5, target_long arg6)
154
{
155
    gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld ",", name->name, arg1, arg2);
156
    print_ipc_cmd(arg3);
157
    gemu_log(",0x" TARGET_FMT_lx ")", arg4);
158
}
159

    
160
static void
161
print_execve(struct syscallname *name,
162
             target_long arg1, target_long arg2, target_long arg3,
163
             target_long arg4, target_long arg5, target_long arg6)
164
{
165
    target_ulong arg_ptr_addr;
166
    char *s;
167

    
168
    if (!access_ok(VERIFY_READ, arg1, 1))
169
        return;
170

    
171
    s = lock_user_string(arg1);
172
    gemu_log("%s(\"%s\",{", name->name, s);
173
    unlock_user(s, arg1, 0);
174

    
175
    for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(target_ulong)) {
176
        target_ulong *arg_ptr, arg_addr, s_addr;
177

    
178
        if (!access_ok(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong)))
179
            return;
180

    
181
        arg_ptr = lock_user(arg_ptr_addr, sizeof(target_ulong), 1);
182
        arg_addr = tswapl(*arg_ptr);
183
        unlock_user(arg_ptr, arg_ptr_addr, 0);
184
        if (!arg_addr)
185
            break;
186
        s = lock_user_string(arg_addr);
187
        gemu_log("\"%s\",", s);
188
        unlock_user(s, s_addr, 0);
189
    }
190

    
191
    gemu_log("NULL})");
192
}
193

    
194
static void
195
print_ipc(struct syscallname *name,
196
          target_long arg1, target_long arg2, target_long arg3,
197
          target_long arg4, target_long arg5, target_long arg6)
198
{
199
    switch(arg1) {
200
    case IPCOP_semctl:
201
        name->name = "semctl";
202
        print_semctl(name,arg2,arg3,arg4,arg5,arg6,0);
203
        break;
204
    default:
205
        gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld ")",
206
                 name->name, arg1, arg2, arg3, arg4);
207
    }
208
}
209

    
210
/*
211
 * Variants for the return value output function
212
 */
213

    
214
static void
215
print_syscall_ret_addr(struct syscallname *name, target_long ret)
216
{
217
if( ret == -1 ) {
218
        gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno));
219
    } else {
220
        gemu_log(" = " TARGET_FMT_lx "\n", ret);
221
    }
222
}
223

    
224
#if 0 /* currently unused */
225
static void
226
print_syscall_ret_raw(struct syscallname *name, target_long ret)
227
{
228
        gemu_log(" = " TARGET_FMT_lx "\n", ret);
229
}
230
#endif
231

    
232
#ifdef TARGET_NR__newselect
233
static void
234
print_syscall_ret_newselect(struct syscallname *name, target_long ret)
235
{
236
    gemu_log(" = " TARGET_FMT_lx " (", ret);
237
    print_fdset(newselect_arg1,newselect_arg2);
238
    gemu_log(",");
239
    print_fdset(newselect_arg1,newselect_arg3);
240
    gemu_log(",");
241
    print_fdset(newselect_arg1,newselect_arg4);
242
    gemu_log(",");
243
    print_timeval(newselect_arg5);
244
    gemu_log(")\n");
245
}
246
#endif
247

    
248
/*
249
 * An array of all of the syscalls we know about
250
 */
251

    
252
static struct syscallname scnames[] = {
253
#include "strace.list"
254
};
255

    
256
static int nsyscalls = sizeof(scnames)/sizeof(struct syscallname);
257

    
258
/*
259
 * The public interface to this module.
260
 */
261
void
262
print_syscall(int num,
263
              target_long arg1, target_long arg2, target_long arg3,
264
              target_long arg4, target_long arg5, target_long arg6)
265
{
266
    int i;
267
    char *format="%s(%ld,%ld,%ld,%ld,%ld,%ld)";
268

    
269
    gemu_log("%d ", getpid() );
270

    
271
    for(i=0;i<nsyscalls;i++)
272
        if( scnames[i].nr == num ) {
273
            if( scnames[i].call != NULL ) {
274
                scnames[i].call(&scnames[i],arg1,arg2,arg3,arg4,arg5,arg6);
275
            } else {
276
                if( scnames[i].format != NULL )
277
                    format = scnames[i].format;
278
                gemu_log(format,scnames[i].name, arg1,arg2,arg3,arg4,arg5,arg6);
279
            }
280
            break;
281
        }
282
}
283

    
284

    
285
void
286
print_syscall_ret(int num, target_long ret)
287
{
288
    int i;
289

    
290
    for(i=0;i<nsyscalls;i++)
291
        if( scnames[i].nr == num ) {
292
            if( scnames[i].result != NULL ) {
293
                scnames[i].result(&scnames[i],ret);
294
            } else {
295
                if( ret < 0 ) {
296
                    gemu_log(" = -1 errno=%d (%s)\n", -ret, target_strerror(-ret));
297
                } else {
298
                    gemu_log(" = %d\n", ret);
299
                }
300
            }
301
            break;
302
        }
303
}
304