root / linux-user / strace.c @ 33189d31
History | View | Annotate | Download (7.3 kB)
1 | 33189d31 | ths | #include <stdio.h> |
---|---|---|---|
2 | 33189d31 | ths | #include <errno.h> |
3 | 33189d31 | ths | #include <sys/ipc.h> |
4 | 33189d31 | ths | #include <sys/msg.h> |
5 | 33189d31 | ths | #include <sys/sem.h> |
6 | 33189d31 | ths | #include <sys/shm.h> |
7 | 33189d31 | ths | #include <sys/select.h> |
8 | 33189d31 | ths | #include <sys/types.h> |
9 | 33189d31 | ths | #include <unistd.h> |
10 | 33189d31 | ths | #include "qemu.h" |
11 | 33189d31 | ths | |
12 | 33189d31 | ths | int do_strace=0; |
13 | 33189d31 | ths | |
14 | 33189d31 | ths | struct syscallname {
|
15 | 33189d31 | ths | int nr;
|
16 | 33189d31 | ths | char *name;
|
17 | 33189d31 | ths | char *format;
|
18 | 33189d31 | ths | void (*call)(struct syscallname *, |
19 | 33189d31 | ths | target_long, target_long, target_long, |
20 | 33189d31 | ths | target_long, target_long, target_long); |
21 | 33189d31 | ths | void (*result)(struct syscallname *, target_long); |
22 | 33189d31 | ths | }; |
23 | 33189d31 | ths | |
24 | 33189d31 | ths | /*
|
25 | 33189d31 | ths | * Utility functions
|
26 | 33189d31 | ths | */
|
27 | 33189d31 | ths | static void |
28 | 33189d31 | ths | print_ipc_cmd(int cmd)
|
29 | 33189d31 | ths | { |
30 | 33189d31 | ths | #define output_cmd(val) \
|
31 | 33189d31 | ths | if( cmd == val ) { \
|
32 | 33189d31 | ths | gemu_log(#val); \
|
33 | 33189d31 | ths | return; \
|
34 | 33189d31 | ths | } |
35 | 33189d31 | ths | |
36 | 33189d31 | ths | cmd &= 0xff;
|
37 | 33189d31 | ths | |
38 | 33189d31 | ths | /* General IPC commands */
|
39 | 33189d31 | ths | output_cmd( IPC_RMID ); |
40 | 33189d31 | ths | output_cmd( IPC_SET ); |
41 | 33189d31 | ths | output_cmd( IPC_STAT ); |
42 | 33189d31 | ths | output_cmd( IPC_INFO ); |
43 | 33189d31 | ths | /* msgctl() commands */
|
44 | 33189d31 | ths | #ifdef __USER_MISC
|
45 | 33189d31 | ths | output_cmd( MSG_STAT ); |
46 | 33189d31 | ths | output_cmd( MSG_INFO ); |
47 | 33189d31 | ths | #endif
|
48 | 33189d31 | ths | /* shmctl() commands */
|
49 | 33189d31 | ths | output_cmd( SHM_LOCK ); |
50 | 33189d31 | ths | output_cmd( SHM_UNLOCK ); |
51 | 33189d31 | ths | output_cmd( SHM_STAT ); |
52 | 33189d31 | ths | output_cmd( SHM_INFO ); |
53 | 33189d31 | ths | /* semctl() commands */
|
54 | 33189d31 | ths | output_cmd( GETPID ); |
55 | 33189d31 | ths | output_cmd( GETVAL ); |
56 | 33189d31 | ths | output_cmd( GETALL ); |
57 | 33189d31 | ths | output_cmd( GETNCNT ); |
58 | 33189d31 | ths | output_cmd( GETZCNT ); |
59 | 33189d31 | ths | output_cmd( SETVAL ); |
60 | 33189d31 | ths | output_cmd( SETALL ); |
61 | 33189d31 | ths | output_cmd( SEM_STAT ); |
62 | 33189d31 | ths | output_cmd( SEM_INFO ); |
63 | 33189d31 | ths | output_cmd( IPC_RMID ); |
64 | 33189d31 | ths | output_cmd( IPC_RMID ); |
65 | 33189d31 | ths | output_cmd( IPC_RMID ); |
66 | 33189d31 | ths | output_cmd( IPC_RMID ); |
67 | 33189d31 | ths | output_cmd( IPC_RMID ); |
68 | 33189d31 | ths | output_cmd( IPC_RMID ); |
69 | 33189d31 | ths | output_cmd( IPC_RMID ); |
70 | 33189d31 | ths | output_cmd( IPC_RMID ); |
71 | 33189d31 | ths | output_cmd( IPC_RMID ); |
72 | 33189d31 | ths | |
73 | 33189d31 | ths | /* Some value we don't recognize */
|
74 | 33189d31 | ths | gemu_log("%d",cmd);
|
75 | 33189d31 | ths | } |
76 | 33189d31 | ths | |
77 | 33189d31 | ths | static void |
78 | 33189d31 | ths | print_fdset(int n, target_ulong target_fds_addr)
|
79 | 33189d31 | ths | { |
80 | 33189d31 | ths | int i;
|
81 | 33189d31 | ths | |
82 | 33189d31 | ths | gemu_log("[");
|
83 | 33189d31 | ths | if( target_fds_addr ) {
|
84 | 33189d31 | ths | target_long *target_fds; |
85 | 33189d31 | ths | |
86 | 33189d31 | ths | if (!access_ok(VERIFY_READ, target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1))) |
87 | 33189d31 | ths | return;
|
88 | 33189d31 | ths | |
89 | 33189d31 | ths | target_fds = lock_user(target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1), 1); |
90 | 33189d31 | ths | for (i=n; i>=0; i--) { |
91 | 33189d31 | ths | if ((tswapl(target_fds[i / TARGET_LONG_BITS]) >> (i & (TARGET_LONG_BITS - 1))) & 1) |
92 | 33189d31 | ths | gemu_log("%d,", i );
|
93 | 33189d31 | ths | } |
94 | 33189d31 | ths | unlock_user(target_fds, target_fds_addr, 0);
|
95 | 33189d31 | ths | } |
96 | 33189d31 | ths | gemu_log("]");
|
97 | 33189d31 | ths | } |
98 | 33189d31 | ths | |
99 | 33189d31 | ths | static void |
100 | 33189d31 | ths | print_timeval(target_ulong tv_addr) |
101 | 33189d31 | ths | { |
102 | 33189d31 | ths | if( tv_addr ) {
|
103 | 33189d31 | ths | struct target_timeval *tv;
|
104 | 33189d31 | ths | |
105 | 33189d31 | ths | if (!access_ok(VERIFY_READ, tv_addr, sizeof(*tv))) |
106 | 33189d31 | ths | return;
|
107 | 33189d31 | ths | |
108 | 33189d31 | ths | tv = lock_user(tv_addr, sizeof(*tv), 1); |
109 | 33189d31 | ths | gemu_log("{%d,%d}", tv->tv_sec, tv->tv_usec);
|
110 | 33189d31 | ths | unlock_user(tv, tv_addr, 0);
|
111 | 33189d31 | ths | } else
|
112 | 33189d31 | ths | gemu_log("NULL");
|
113 | 33189d31 | ths | } |
114 | 33189d31 | ths | |
115 | 33189d31 | ths | /*
|
116 | 33189d31 | ths | * Sysycall specific output functions
|
117 | 33189d31 | ths | */
|
118 | 33189d31 | ths | |
119 | 33189d31 | ths | /* select */
|
120 | 33189d31 | ths | static long newselect_arg1 = 0; |
121 | 33189d31 | ths | static long newselect_arg2 = 0; |
122 | 33189d31 | ths | static long newselect_arg3 = 0; |
123 | 33189d31 | ths | static long newselect_arg4 = 0; |
124 | 33189d31 | ths | static long newselect_arg5 = 0; |
125 | 33189d31 | ths | |
126 | 33189d31 | ths | static void |
127 | 33189d31 | ths | print_newselect(struct syscallname *name,
|
128 | 33189d31 | ths | target_long arg1, target_long arg2, target_long arg3, |
129 | 33189d31 | ths | target_long arg4, target_long arg5, target_long arg6) |
130 | 33189d31 | ths | { |
131 | 33189d31 | ths | gemu_log("%s(" TARGET_FMT_ld ",", name->name, arg1); |
132 | 33189d31 | ths | print_fdset(arg1, arg2); |
133 | 33189d31 | ths | gemu_log(",");
|
134 | 33189d31 | ths | print_fdset(arg1, arg3); |
135 | 33189d31 | ths | gemu_log(",");
|
136 | 33189d31 | ths | print_fdset(arg1, arg4); |
137 | 33189d31 | ths | gemu_log(",");
|
138 | 33189d31 | ths | print_timeval(arg5); |
139 | 33189d31 | ths | gemu_log(")");
|
140 | 33189d31 | ths | |
141 | 33189d31 | ths | /* save for use in the return output function below */
|
142 | 33189d31 | ths | newselect_arg1=arg1; |
143 | 33189d31 | ths | newselect_arg2=arg2; |
144 | 33189d31 | ths | newselect_arg3=arg3; |
145 | 33189d31 | ths | newselect_arg4=arg4; |
146 | 33189d31 | ths | newselect_arg5=arg5; |
147 | 33189d31 | ths | } |
148 | 33189d31 | ths | |
149 | 33189d31 | ths | static void |
150 | 33189d31 | ths | print_semctl(struct syscallname *name,
|
151 | 33189d31 | ths | target_long arg1, target_long arg2, target_long arg3, |
152 | 33189d31 | ths | target_long arg4, target_long arg5, target_long arg6) |
153 | 33189d31 | ths | { |
154 | 33189d31 | ths | gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld ",", name->name, arg1, arg2); |
155 | 33189d31 | ths | print_ipc_cmd(arg3); |
156 | 33189d31 | ths | gemu_log(",0x" TARGET_FMT_lx ")", arg4); |
157 | 33189d31 | ths | } |
158 | 33189d31 | ths | |
159 | 33189d31 | ths | static void |
160 | 33189d31 | ths | print_execve(struct syscallname *name,
|
161 | 33189d31 | ths | target_long arg1, target_long arg2, target_long arg3, |
162 | 33189d31 | ths | target_long arg4, target_long arg5, target_long arg6) |
163 | 33189d31 | ths | { |
164 | 33189d31 | ths | target_ulong arg_ptr_addr; |
165 | 33189d31 | ths | char *s;
|
166 | 33189d31 | ths | |
167 | 33189d31 | ths | if (!access_ok(VERIFY_READ, arg1, 1)) |
168 | 33189d31 | ths | return;
|
169 | 33189d31 | ths | |
170 | 33189d31 | ths | s = lock_user_string(arg1); |
171 | 33189d31 | ths | gemu_log("%s(\"%s\",{", name->name, s);
|
172 | 33189d31 | ths | unlock_user(s, arg1, 0);
|
173 | 33189d31 | ths | |
174 | 33189d31 | ths | for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(target_ulong)) { |
175 | 33189d31 | ths | target_ulong *arg_ptr, arg_addr, s_addr; |
176 | 33189d31 | ths | |
177 | 33189d31 | ths | if (!access_ok(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong))) |
178 | 33189d31 | ths | return;
|
179 | 33189d31 | ths | |
180 | 33189d31 | ths | arg_ptr = lock_user(arg_ptr_addr, sizeof(target_ulong), 1); |
181 | 33189d31 | ths | arg_addr = tswapl(*arg_ptr); |
182 | 33189d31 | ths | unlock_user(arg_ptr, arg_ptr_addr, 0);
|
183 | 33189d31 | ths | if (!arg_addr)
|
184 | 33189d31 | ths | break;
|
185 | 33189d31 | ths | s = lock_user_string(arg_addr); |
186 | 33189d31 | ths | gemu_log("\"%s\",", s);
|
187 | 33189d31 | ths | unlock_user(s, s_addr, 0);
|
188 | 33189d31 | ths | } |
189 | 33189d31 | ths | |
190 | 33189d31 | ths | gemu_log("NULL})");
|
191 | 33189d31 | ths | } |
192 | 33189d31 | ths | |
193 | 33189d31 | ths | static void |
194 | 33189d31 | ths | print_ipc(struct syscallname *name,
|
195 | 33189d31 | ths | target_long arg1, target_long arg2, target_long arg3, |
196 | 33189d31 | ths | target_long arg4, target_long arg5, target_long arg6) |
197 | 33189d31 | ths | { |
198 | 33189d31 | ths | switch(arg1) {
|
199 | 33189d31 | ths | case IPCOP_semctl:
|
200 | 33189d31 | ths | name->name = "semctl";
|
201 | 33189d31 | ths | print_semctl(name,arg2,arg3,arg4,arg5,arg6,0);
|
202 | 33189d31 | ths | break;
|
203 | 33189d31 | ths | default:
|
204 | 33189d31 | ths | gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld ")", |
205 | 33189d31 | ths | name->name, arg1, arg2, arg3, arg4); |
206 | 33189d31 | ths | } |
207 | 33189d31 | ths | } |
208 | 33189d31 | ths | |
209 | 33189d31 | ths | /*
|
210 | 33189d31 | ths | * Variants for the return value output function
|
211 | 33189d31 | ths | */
|
212 | 33189d31 | ths | |
213 | 33189d31 | ths | static void |
214 | 33189d31 | ths | print_syscall_ret_addr(struct syscallname *name, target_long ret)
|
215 | 33189d31 | ths | { |
216 | 33189d31 | ths | if( ret == -1 ) { |
217 | 33189d31 | ths | gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno));
|
218 | 33189d31 | ths | } else {
|
219 | 33189d31 | ths | gemu_log(" = " TARGET_FMT_lx "\n", ret); |
220 | 33189d31 | ths | } |
221 | 33189d31 | ths | } |
222 | 33189d31 | ths | |
223 | 33189d31 | ths | static void |
224 | 33189d31 | ths | print_syscall_ret_raw(struct syscallname *name, target_long ret)
|
225 | 33189d31 | ths | { |
226 | 33189d31 | ths | gemu_log(" = " TARGET_FMT_lx "\n", ret); |
227 | 33189d31 | ths | } |
228 | 33189d31 | ths | |
229 | 33189d31 | ths | static void |
230 | 33189d31 | ths | print_syscall_ret_newselect(struct syscallname *name, target_long ret)
|
231 | 33189d31 | ths | { |
232 | 33189d31 | ths | gemu_log(" = " TARGET_FMT_lx " (", ret); |
233 | 33189d31 | ths | print_fdset(newselect_arg1,newselect_arg2); |
234 | 33189d31 | ths | gemu_log(",");
|
235 | 33189d31 | ths | print_fdset(newselect_arg1,newselect_arg3); |
236 | 33189d31 | ths | gemu_log(",");
|
237 | 33189d31 | ths | print_fdset(newselect_arg1,newselect_arg4); |
238 | 33189d31 | ths | gemu_log(",");
|
239 | 33189d31 | ths | print_timeval(newselect_arg5); |
240 | 33189d31 | ths | gemu_log(")\n");
|
241 | 33189d31 | ths | } |
242 | 33189d31 | ths | |
243 | 33189d31 | ths | /*
|
244 | 33189d31 | ths | * An array of all of the syscalls we know about
|
245 | 33189d31 | ths | */
|
246 | 33189d31 | ths | |
247 | 33189d31 | ths | static struct syscallname scnames[] = { |
248 | 33189d31 | ths | #include "strace.list" |
249 | 33189d31 | ths | }; |
250 | 33189d31 | ths | |
251 | 33189d31 | ths | static int nsyscalls = sizeof(scnames)/sizeof(struct syscallname); |
252 | 33189d31 | ths | |
253 | 33189d31 | ths | /*
|
254 | 33189d31 | ths | * The public interface to this module.
|
255 | 33189d31 | ths | */
|
256 | 33189d31 | ths | void
|
257 | 33189d31 | ths | print_syscall(int num,
|
258 | 33189d31 | ths | target_long arg1, target_long arg2, target_long arg3, |
259 | 33189d31 | ths | target_long arg4, target_long arg5, target_long arg6) |
260 | 33189d31 | ths | { |
261 | 33189d31 | ths | int i;
|
262 | 33189d31 | ths | char *format="%s(%ld,%ld,%ld,%ld,%ld,%ld)"; |
263 | 33189d31 | ths | |
264 | 33189d31 | ths | gemu_log("%d ", getpid() );
|
265 | 33189d31 | ths | |
266 | 33189d31 | ths | for(i=0;i<nsyscalls;i++) |
267 | 33189d31 | ths | if( scnames[i].nr == num ) {
|
268 | 33189d31 | ths | if( scnames[i].call != NULL ) { |
269 | 33189d31 | ths | scnames[i].call(&scnames[i],arg1,arg2,arg3,arg4,arg5,arg6); |
270 | 33189d31 | ths | } else {
|
271 | 33189d31 | ths | if( scnames[i].format != NULL ) |
272 | 33189d31 | ths | format = scnames[i].format; |
273 | 33189d31 | ths | gemu_log(format,scnames[i].name, arg1,arg2,arg3,arg4,arg5,arg6); |
274 | 33189d31 | ths | } |
275 | 33189d31 | ths | break;
|
276 | 33189d31 | ths | } |
277 | 33189d31 | ths | } |
278 | 33189d31 | ths | |
279 | 33189d31 | ths | |
280 | 33189d31 | ths | void
|
281 | 33189d31 | ths | print_syscall_ret(int num, target_long ret)
|
282 | 33189d31 | ths | { |
283 | 33189d31 | ths | int i;
|
284 | 33189d31 | ths | |
285 | 33189d31 | ths | for(i=0;i<nsyscalls;i++) |
286 | 33189d31 | ths | if( scnames[i].nr == num ) {
|
287 | 33189d31 | ths | if( scnames[i].result != NULL ) { |
288 | 33189d31 | ths | scnames[i].result(&scnames[i],ret); |
289 | 33189d31 | ths | } else {
|
290 | 33189d31 | ths | if( ret < 0 ) { |
291 | 33189d31 | ths | gemu_log(" = -1 errno=%d (%s)\n", -ret, target_strerror(-ret));
|
292 | 33189d31 | ths | } else {
|
293 | 33189d31 | ths | gemu_log(" = %d\n", ret);
|
294 | 33189d31 | ths | } |
295 | 33189d31 | ths | } |
296 | 33189d31 | ths | break;
|
297 | 33189d31 | ths | } |
298 | 33189d31 | ths | } |