Statistics
| Branch: | Revision:

root / linux-user / strace.c @ 33189d31

History | View | Annotate | Download (7.3 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("{%d,%d}", tv->tv_sec, tv->tv_usec);
110
        unlock_user(tv, tv_addr, 0);
111
    } else
112
        gemu_log("NULL");
113
}
114

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
223
static void
224
print_syscall_ret_raw(struct syscallname *name, target_long ret)
225
{
226
        gemu_log(" = " TARGET_FMT_lx "\n", ret);
227
}
228

    
229
static void
230
print_syscall_ret_newselect(struct syscallname *name, target_long ret)
231
{
232
    gemu_log(" = " TARGET_FMT_lx " (", ret);
233
    print_fdset(newselect_arg1,newselect_arg2);
234
    gemu_log(",");
235
    print_fdset(newselect_arg1,newselect_arg3);
236
    gemu_log(",");
237
    print_fdset(newselect_arg1,newselect_arg4);
238
    gemu_log(",");
239
    print_timeval(newselect_arg5);
240
    gemu_log(")\n");
241
}
242

    
243
/*
244
 * An array of all of the syscalls we know about
245
 */
246

    
247
static struct syscallname scnames[] = {
248
#include "strace.list"
249
};
250

    
251
static int nsyscalls = sizeof(scnames)/sizeof(struct syscallname);
252

    
253
/*
254
 * The public interface to this module.
255
 */
256
void
257
print_syscall(int num,
258
              target_long arg1, target_long arg2, target_long arg3,
259
              target_long arg4, target_long arg5, target_long arg6)
260
{
261
    int i;
262
    char *format="%s(%ld,%ld,%ld,%ld,%ld,%ld)";
263

    
264
    gemu_log("%d ", getpid() );
265

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

    
279

    
280
void
281
print_syscall_ret(int num, target_long ret)
282
{
283
    int i;
284

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