Stackdb
Stackdb is a stackable, multi-target and -level source debugger and memory forensics library.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
strace.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, 2013, 2014 The University of Utah
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <argp.h>
25 #include <sys/user.h>
26 #include <sys/ptrace.h>
27 #include <inttypes.h>
28 #include <signal.h>
29 #include <time.h>
30 
31 #include "log.h"
32 #include "target_api.h"
33 #include "target.h"
34 #include "target_os.h"
35 
36 struct target *t = NULL;
37 GHashTable *probes = NULL;
38 
39 void cleanup_probes(void) {
40  GHashTableIter iter;
41  gpointer key;
42  struct probe *probe;
43 
44  if (probes) {
45  target_pause(t);
46  g_hash_table_iter_init(&iter,probes);
47  while (g_hash_table_iter_next(&iter,
48  (gpointer)&key,
49  (gpointer)&probe)) {
50  probe_unregister(probe,1);
51  probe_free(probe,1);
52  }
53  g_hash_table_destroy(probes);
54  probes = NULL;
55  }
56 }
57 
58 void sigh_cleanup_probes(int signo,siginfo_t *siginfo,void *x) {
60 }
61 
63  struct probe *trigger,struct probe *base) {
64  struct target_os_syscall_state *scs;
65  struct timeval tv = { 0,0 };
66  int i;
67  struct dump_info ud = { .stream = stdout,.prefix = "",.detail = 0,.meta = 0 };
68  struct value *v;
69  void *rv;
70 
72  if (!scs) {
73  verror("could not get syscall state!\n");
74  /* XXX: don't return _ERROR because that will disable the probe. */
75  return RESULT_SUCCESS;
76  }
77 
78  gettimeofday(&tv,NULL);
79 
80  printf("%11ld.%-6ld (%d) tid %6"PRIiTID" %s ",
81  tv.tv_sec,tv.tv_usec,scs->syscall->num,tid,
82  (scs->syscall->bsymbol) ? bsymbol_get_name(scs->syscall->bsymbol) : "");
83  if (scs->argvals) {
84  printf("(");
85  array_list_foreach(scs->argvals,i,v) {
86  if (!v) {
87  if (scs->regvals)
88  printf("0x%"PRIxREGVAL,
89  (REGVAL)array_list_item(scs->regvals,i));
90  }
91  else {
92  value_dump_simple(v,&ud);
93  }
95  printf(", ");
96  }
97  printf(")\n");
98  }
99  else if (scs->regvals) {
100  printf("(");
101  array_list_foreach(scs->regvals,i,rv) {
102  printf("0x%"PRIxREGVAL,(REGVAL)rv);
103  if (!array_list_foreach_is_last(scs->regvals,i))
104  printf(", ");
105  }
106  printf(")\n");
107  }
108  else {
109  printf("()\n");
110  }
111 
112  fflush(stdout);
113 
114  return RESULT_SUCCESS;
115 }
116 
118  struct probe *trigger,struct probe *base) {
119  struct target_os_syscall_state *scs;
120  struct timeval tv = { 0,0 };
121 
122  scs = target_os_syscall_probe_last(probe_target(probe),tid);
123  if (!scs) {
124  verror("could not get syscall state!\n");
125  /* XXX: don't return _ERROR because that will disable the probe. */
126  return RESULT_SUCCESS;
127  }
128 
129  gettimeofday(&tv,NULL);
130 
131  printf("%11ld.%-6ld (%d) tid %6"PRIiTID" %s = 0x%"PRIxREGVAL"\n",
132  tv.tv_sec,tv.tv_usec,scs->syscall->num,tid,
133  (scs->syscall->bsymbol) ? bsymbol_get_name(scs->syscall->bsymbol) : "",
134  scs->retval);
135  fflush(stdout);
136 
137  return RESULT_SUCCESS;
138 }
139 
141  int argc;
142  char **argv;
143 };
144 
146 
147 struct argp_option strace_argp_opts[] = {
148  { 0,0,0,0,0,0 },
149 };
150 
151 error_t strace_argp_parse_opt(int key,char *arg,struct argp_state *state) {
152  struct strace_argp_state *opts = \
154 
155  switch (key) {
156  case ARGP_KEY_ARG:
157  return ARGP_ERR_UNKNOWN;
158  case ARGP_KEY_ARGS:
159  /* Eat all the remaining args. */
160  if (state->quoted > 0)
161  opts->argc = state->quoted - state->next;
162  else
163  opts->argc = state->argc - state->next;
164  if (opts->argc > 0) {
165  opts->argv = calloc(opts->argc,sizeof(char *));
166  memcpy(opts->argv,&state->argv[state->next],opts->argc*sizeof(char *));
167  state->next += opts->argc;
168  }
169  return 0;
170  case ARGP_KEY_INIT:
172  return 0;
173  case ARGP_KEY_END:
174  case ARGP_KEY_NO_ARGS:
175  case ARGP_KEY_SUCCESS:
176  return 0;
177  case ARGP_KEY_ERROR:
178  case ARGP_KEY_FINI:
179  return 0;
180 
181  default:
182  return ARGP_ERR_UNKNOWN;
183  }
184 
185  return 0;
186 }
187 
188 struct argp strace_argp = {
189  strace_argp_opts,strace_argp_parse_opt,NULL,NULL,NULL,NULL,NULL,
190 };
191 
192 int main(int argc,char **argv) {
193  struct target_spec *tspec;
194  char *targetstr;
195  tid_t tid;
196  target_status_t tstat;
197  int i;
198  struct target_os_syscall *syscall;
199  struct probe *p;
200 
201  target_init();
202  atexit(target_fini);
203 
205 
206  tspec = target_argp_driver_parse_one(&strace_argp,&opts,argc,argv,
208 
209  if (!tspec) {
210  verror("could not parse target arguments!\n");
211  exit(-1);
212  }
213 
214  t = target_instantiate(tspec,NULL);
215  if (!t) {
216  verror("could not instantiate target!\n");
217  exit(-1);
218  }
219 
220  if (target_open(t)) {
221  fprintf(stderr,"could not open target!\n");
222  exit(-4);
223  }
224 
225  /*
226  * Make a permanent copy so we can print useful messages after
227  * target_finalize.
228  */
229  targetstr = target_name(t);
230  if (!targetstr)
231  targetstr = strdup("<UNNAMED_TARGET>");
232  else
233  targetstr = strdup(targetstr);
234 
236  goto exit;
237 
238  fflush(stderr);
239  fflush(stdout);
240 
241  probes = g_hash_table_new(g_direct_hash,g_direct_equal);
242 
243  /*
244  * If they gave us specific syscalls, look them up and probe them
245  * individually; else probe globally.
246  */
247  if (opts.argc) {
249  goto exit;
250  for (i = 0; i < opts.argc; ++i) {
251  syscall = target_os_syscall_lookup_name(t,opts.argv[i]);
252  if (!syscall) {
253  verror("could not lookup syscall %s!\n",opts.argv[i]);
254  goto exit;
255  }
257  syscall_post_handler,NULL);
258  if (!p) {
259  verror("could not probe syscall %s!\n",opts.argv[i]);
260  goto exit;
261  }
262  g_hash_table_insert(probes,p,p);
263  }
264  }
265  else {
268  NULL);
269  if (!p) {
270  verror("could not probe global syscall entry/exit path!\n");
271  goto exit;
272  }
273  g_hash_table_insert(probes,p,p);
274  }
275 
276  target_resume(t);
277 
278  while (1) {
279  tid = 0;
280 
281  tstat = target_monitor(t);
282 
283  if (tstat == TSTATUS_RUNNING)
284  continue;
285  else if (tstat == TSTATUS_PAUSED || tstat == TSTATUS_INTERRUPTED) {
286  tid = target_gettid(t);
287 
288  printf("%s thread %"PRIiTID" interrupted at 0x%"PRIxREGVAL"\n",
289  targetstr,tid,target_read_reg(t,tid,CREG_IP));
290 
291  if (target_resume(t)) {
292  fprintf(stderr,"could not resume target %s thread %"PRIiTID"\n",
293  targetstr,tid);
294 
295  cleanup_probes();
297  exit(-16);
298  }
299  }
300  else if (tstat == TSTATUS_EXITING) {
301  tid = target_gettid(t);
302  printf("%s exiting, removing probes safely...\n",targetstr);
303  cleanup_probes();
304  /* Let it resume to "finish" exiting! */
305  if (target_resume(t)) {
306  fprintf(stderr,"could not resume target %s thread %"PRIiTID"\n",
307  targetstr,tid);
308 
310  exit(-16);
311  }
312  }
313  else {
314  out:
315  fflush(stderr);
316  fflush(stdout);
317  cleanup_probes();
319 
320  if (tstat == TSTATUS_DONE) {
321  printf("%s finished.\n",targetstr);
322  free(targetstr);
323  exit(0);
324  }
325  else if (tstat == TSTATUS_ERROR) {
326  printf("%s monitoring failed!\n",targetstr);
327  free(targetstr);
328  exit(-9);
329  }
330  else {
331  printf("%s monitoring failed with %d!\n",targetstr,tstat);
332  free(targetstr);
333  exit(-10);
334  }
335  }
336  }
337 
338  exit:
339  target_resume(t);
340 
341  fflush(stderr);
342  fflush(stdout);
343  cleanup_probes();
345 
346  printf("%s finished.\n",targetstr);
347  exit(0);
348 }
struct target_os_syscall_state * target_os_syscall_probe_last(struct target *target, tid_t tid)
Definition: target_os.c:531
int probe_unregister(struct probe *probe, int force)
Definition: probe.c:1137
void sigh_cleanup_probes(int signo, siginfo_t *siginfo, void *x)
Definition: strace.c:58
int32_t tid_t
Definition: common.h:36
void * target_argp_driver_state(struct argp_state *state)
Definition: target.c:716
target_status_t
Definition: target_api.h:197
void value_dump_simple(struct value *value, struct dump_info *ud)
Definition: value.c:1289
struct target_spec * tspec
Definition: dumptarget.c:113
void * p
char ** argv
Definition: strace.c:142
static uint64_t unsigned int i
struct array_list * argvals
Definition: target_os.h:62
void target_init(void)
Definition: target.c:69
Definition: arch.h:74
int target_resume(struct target *target)
Definition: target_api.c:1012
int target_pause(struct target *target)
Definition: target_api.c:1027
tid_t target_gettid(struct target *target)
Definition: target_api.c:1918
struct argp_option strace_argp_opts[]
Definition: strace.c:147
char * bsymbol_get_name(struct bsymbol *bsymbol)
Definition: symbol.c:62
struct target_os_syscall * target_os_syscall_lookup_name(struct target *target, char *name)
Definition: target_os.c:437
struct list_head probe
Definition: probe.h:379
struct target * t
Definition: strace.c:36
#define verror(format,...)
Definition: log.h:30
int target_install_default_sighandlers(void(*sighandler)(int signo, siginfo_t *siginfo, void *x))
Definition: target.c:240
void cleanup_probes(void)
Definition: strace.c:39
struct argp strace_argp
Definition: strace.c:188
void target_fini(void)
Definition: target.c:91
void free(void *ptr)
Definition: debugserver.c:207
REGVAL target_read_reg(struct target *target, tid_t tid, REG reg)
Definition: target_api.c:1132
tid_t tid
Definition: probe.h:344
int main(int argc, char **argv)
Definition: strace.c:192
#define array_list_foreach(alist, lpc, placeholder)
Definition: alist.h:371
void target_default_cleanup()
Definition: target.c:128
int target_os_syscall_table_load(struct target *target)
Definition: target_os.c:415
struct probe * target_os_syscall_probe(struct target *target, tid_t tid, struct target_os_syscall *syscall, probe_handler_t pre_handler, probe_handler_t post_handler, void *handler_data)
Definition: target_os.c:465
int probe_free(struct probe *probe, int force)
Definition: probe.c:777
#define array_list_foreach_is_last(alist, lpc)
Definition: alist.h:386
char * target_name(struct target *target)
Definition: target_api.c:505
result_t syscall_post_handler(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
Definition: strace.c:117
struct target_os_syscall * syscall
Definition: target_os.h:58
Definition: probe.h:308
struct target * probe_target(struct probe *probe)
Definition: probe.c:1943
FILE * stream
Definition: output.h:26
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
struct strace_argp_state opts
Definition: strace.c:145
result_t
Definition: common.h:25
uint32_t REGVAL
Definition: common.h:66
struct probe * target_os_syscall_probe_all(struct target *target, tid_t tid, probe_handler_t pre_handler, probe_handler_t post_handler, void *handler_data)
Definition: target_os.c:474
#define PRIiTID
Definition: common.h:37
error_t strace_argp_parse_opt(int key, char *arg, struct argp_state *state)
Definition: strace.c:151
int target_open(struct target *target)
Definition: target_api.c:513
target_status_t target_monitor(struct target *target)
Definition: target_api.c:869
struct target_spec * target_argp_driver_parse_one(struct argp *driver_parser, void *driver_state, int argc, char **argv, target_type_t target_types, int filter_quoted)
Definition: target.c:802
struct target * target_instantiate(struct target_spec *spec, struct evloop *evloop)
Definition: target_api.c:55
struct array_list * regvals
Definition: target_os.h:60
struct bsymbol * bsymbol
Definition: target_os.h:42
GHashTable * probes
Definition: strace.c:37
result_t syscall_pre_handler(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
Definition: strace.c:62
#define TID_GLOBAL
Definition: target_api.h:145
void target_driver_argp_init_children(struct argp_state *state)
Definition: target.c:1057
#define PRIxREGVAL
Definition: common.h:72