|
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 const char *name; |
|
17 const char *format; |
|
18 void (*call)(const struct syscallname *, |
|
19 abi_long, abi_long, abi_long, |
|
20 abi_long, abi_long, abi_long); |
|
21 void (*result)(const struct syscallname *, abi_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 #ifdef TARGET_NR__newselect |
|
78 static void |
|
79 print_fdset(int n, abi_ulong target_fds_addr) |
|
80 { |
|
81 int i; |
|
82 |
|
83 gemu_log("["); |
|
84 if( target_fds_addr ) { |
|
85 abi_long *target_fds; |
|
86 |
|
87 target_fds = lock_user(VERIFY_READ, |
|
88 target_fds_addr, |
|
89 sizeof(*target_fds)*(n / TARGET_ABI_BITS + 1), |
|
90 1); |
|
91 |
|
92 if (!target_fds) |
|
93 return; |
|
94 |
|
95 for (i=n; i>=0; i--) { |
|
96 if ((tswapl(target_fds[i / TARGET_ABI_BITS]) >> (i & (TARGET_ABI_BITS - 1))) & 1) |
|
97 gemu_log("%d,", i ); |
|
98 } |
|
99 unlock_user(target_fds, target_fds_addr, 0); |
|
100 } |
|
101 gemu_log("]"); |
|
102 } |
|
103 |
|
104 static void |
|
105 print_timeval(abi_ulong tv_addr) |
|
106 { |
|
107 if( tv_addr ) { |
|
108 struct target_timeval *tv; |
|
109 |
|
110 tv = lock_user(VERIFY_READ, tv_addr, sizeof(*tv), 1); |
|
111 if (!tv) |
|
112 return; |
|
113 gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}", |
|
114 tv->tv_sec, tv->tv_usec); |
|
115 unlock_user(tv, tv_addr, 0); |
|
116 } else |
|
117 gemu_log("NULL"); |
|
118 } |
|
119 #endif |
|
120 |
|
121 /* |
|
122 * Sysycall specific output functions |
|
123 */ |
|
124 |
|
125 /* select */ |
|
126 #ifdef TARGET_NR__newselect |
|
127 static long newselect_arg1 = 0; |
|
128 static long newselect_arg2 = 0; |
|
129 static long newselect_arg3 = 0; |
|
130 static long newselect_arg4 = 0; |
|
131 static long newselect_arg5 = 0; |
|
132 |
|
133 static void |
|
134 print_newselect(const struct syscallname *name, |
|
135 abi_long arg1, abi_long arg2, abi_long arg3, |
|
136 abi_long arg4, abi_long arg5, abi_long arg6) |
|
137 { |
|
138 gemu_log("%s(" TARGET_ABI_FMT_ld ",", name->name, arg1); |
|
139 print_fdset(arg1, arg2); |
|
140 gemu_log(","); |
|
141 print_fdset(arg1, arg3); |
|
142 gemu_log(","); |
|
143 print_fdset(arg1, arg4); |
|
144 gemu_log(","); |
|
145 print_timeval(arg5); |
|
146 gemu_log(")"); |
|
147 |
|
148 /* save for use in the return output function below */ |
|
149 newselect_arg1=arg1; |
|
150 newselect_arg2=arg2; |
|
151 newselect_arg3=arg3; |
|
152 newselect_arg4=arg4; |
|
153 newselect_arg5=arg5; |
|
154 } |
|
155 #endif |
|
156 |
|
157 #ifdef TARGET_NR_semctl |
|
158 static void |
|
159 print_semctl(const struct syscallname *name, |
|
160 abi_long arg1, abi_long arg2, abi_long arg3, |
|
161 abi_long arg4, abi_long arg5, abi_long arg6) |
|
162 { |
|
163 gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", name->name, arg1, arg2); |
|
164 print_ipc_cmd(arg3); |
|
165 gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4); |
|
166 } |
|
167 #endif |
|
168 |
|
169 static void |
|
170 print_execve(const struct syscallname *name, |
|
171 abi_long arg1, abi_long arg2, abi_long arg3, |
|
172 abi_long arg4, abi_long arg5, abi_long arg6) |
|
173 { |
|
174 abi_ulong arg_ptr_addr; |
|
175 char *s; |
|
176 |
|
177 if (!(s = lock_user_string(arg1))) |
|
178 return; |
|
179 gemu_log("%s(\"%s\",{", name->name, s); |
|
180 unlock_user(s, arg1, 0); |
|
181 |
|
182 for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) { |
|
183 abi_ulong *arg_ptr, arg_addr; |
|
184 |
|
185 arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); |
|
186 if (!arg_ptr) |
|
187 return; |
|
188 arg_addr = tswapl(*arg_ptr); |
|
189 unlock_user(arg_ptr, arg_ptr_addr, 0); |
|
190 if (!arg_addr) |
|
191 break; |
|
192 if ((s = lock_user_string(arg_addr))) { |
|
193 gemu_log("\"%s\",", s); |
|
194 unlock_user(s, arg_addr, 0); |
|
195 } |
|
196 } |
|
197 |
|
198 gemu_log("NULL})"); |
|
199 } |
|
200 |
|
201 #ifdef TARGET_NR_ipc |
|
202 static void |
|
203 print_ipc(const struct syscallname *name, |
|
204 abi_long arg1, abi_long arg2, abi_long arg3, |
|
205 abi_long arg4, abi_long arg5, abi_long arg6) |
|
206 { |
|
207 switch(arg1) { |
|
208 case IPCOP_semctl: |
|
209 gemu_log("semctl(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", arg1, arg2); |
|
210 print_ipc_cmd(arg3); |
|
211 gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4); |
|
212 break; |
|
213 default: |
|
214 gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")", |
|
215 name->name, arg1, arg2, arg3, arg4); |
|
216 } |
|
217 } |
|
218 #endif |
|
219 |
|
220 /* |
|
221 * Variants for the return value output function |
|
222 */ |
|
223 |
|
224 static void |
|
225 print_syscall_ret_addr(const struct syscallname *name, abi_long ret) |
|
226 { |
|
227 if( ret == -1 ) { |
|
228 gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno)); |
|
229 } else { |
|
230 gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); |
|
231 } |
|
232 } |
|
233 |
|
234 #if 0 /* currently unused */ |
|
235 static void |
|
236 print_syscall_ret_raw(struct syscallname *name, abi_long ret) |
|
237 { |
|
238 gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); |
|
239 } |
|
240 #endif |
|
241 |
|
242 #ifdef TARGET_NR__newselect |
|
243 static void |
|
244 print_syscall_ret_newselect(const struct syscallname *name, abi_long ret) |
|
245 { |
|
246 gemu_log(" = 0x" TARGET_ABI_FMT_lx " (", ret); |
|
247 print_fdset(newselect_arg1,newselect_arg2); |
|
248 gemu_log(","); |
|
249 print_fdset(newselect_arg1,newselect_arg3); |
|
250 gemu_log(","); |
|
251 print_fdset(newselect_arg1,newselect_arg4); |
|
252 gemu_log(","); |
|
253 print_timeval(newselect_arg5); |
|
254 gemu_log(")\n"); |
|
255 } |
|
256 #endif |
|
257 |
|
258 /* |
|
259 * An array of all of the syscalls we know about |
|
260 */ |
|
261 |
|
262 static const struct syscallname scnames[] = { |
|
263 #include "strace.list" |
|
264 }; |
|
265 |
|
266 static int nsyscalls = ARRAY_SIZE(scnames); |
|
267 |
|
268 /* |
|
269 * The public interface to this module. |
|
270 */ |
|
271 void |
|
272 print_syscall(int num, |
|
273 abi_long arg1, abi_long arg2, abi_long arg3, |
|
274 abi_long arg4, abi_long arg5, abi_long arg6) |
|
275 { |
|
276 int i; |
|
277 const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")"; |
|
278 |
|
279 gemu_log("%d ", getpid() ); |
|
280 |
|
281 for(i=0;i<nsyscalls;i++) |
|
282 if( scnames[i].nr == num ) { |
|
283 if( scnames[i].call != NULL ) { |
|
284 scnames[i].call(&scnames[i],arg1,arg2,arg3,arg4,arg5,arg6); |
|
285 } else { |
|
286 /* XXX: this format system is broken because it uses |
|
287 host types and host pointers for strings */ |
|
288 if( scnames[i].format != NULL ) |
|
289 format = scnames[i].format; |
|
290 gemu_log(format,scnames[i].name, arg1,arg2,arg3,arg4,arg5,arg6); |
|
291 } |
|
292 return; |
|
293 } |
|
294 gemu_log("Unknown syscall %d\n", num); |
|
295 } |
|
296 |
|
297 |
|
298 void |
|
299 print_syscall_ret(int num, abi_long ret) |
|
300 { |
|
301 int i; |
|
302 |
|
303 for(i=0;i<nsyscalls;i++) |
|
304 if( scnames[i].nr == num ) { |
|
305 if( scnames[i].result != NULL ) { |
|
306 scnames[i].result(&scnames[i],ret); |
|
307 } else { |
|
308 if( ret < 0 ) { |
|
309 gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, target_strerror(-ret)); |
|
310 } else { |
|
311 gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret); |
|
312 } |
|
313 } |
|
314 break; |
|
315 } |
|
316 } |