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
cfi_util.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 <errno.h>
21 
22 #include "log.h"
23 #include "cfi.h"
24 #include "probe_api.h"
25 #include "probe.h"
26 #include "target.h"
27 #include "target_api.h"
28 #include "disasm.h"
29 
30 static int cfi_instrument_func(struct cfi_data *cfi,struct bsymbol *bsymbol,
31  int isroot);
32 static int cfi_instrument_block(struct cfi_data *cfi,ADDR target,int isroot);
33 
34 static int __cfit_stack_makenull(struct cfi_thread_status *cfit) {
35  void *addr;
36  void *symbol;
37 
38  if (array_list_len(cfit->shadow_stack) > 0) {
39  addr = array_list_item(cfit->shadow_stack,
40  array_list_len(cfit->shadow_stack) - 1);
41  symbol = array_list_item(cfit->shadow_stack_symbols,
42  array_list_len(cfit->shadow_stack_symbols) - 1);
43 
44  if (addr == 0 && symbol == NULL) {
45  /*
46  * Do nothing; already were in an untracked bunch of code;
47  * do not push more NULLs.
48  */
49  return 1;
50  }
51  else {
52  array_list_append(cfit->shadow_stack,NULL);
53  array_list_append(cfit->shadow_stack_symbols,NULL);
54 
55  return 0;
56  }
57  }
58  else {
59  array_list_append(cfit->shadow_stack,NULL);
60  array_list_append(cfit->shadow_stack_symbols,NULL);
61 
62  return 0;
63  }
64 }
65 
66 static int __cfit_stack_makelastnull(struct cfi_thread_status *cfit) {
67  ADDR oldretaddr;
68  struct bsymbol *symbol;
69  int len;
70 
71  len = array_list_len(cfit->shadow_stack);
72  if (len > 0) {
73  oldretaddr = (ADDR)(uintptr_t)array_list_item(cfit->shadow_stack,len - 1);
74  symbol = (struct bsymbol *) \
75  array_list_item(cfit->shadow_stack_symbols,len - 1);
76 
77  if (oldretaddr == 0 && symbol == NULL) {
78  if (len > 1) {
79  array_list_remove(cfit->shadow_stack);
80  array_list_remove(cfit->shadow_stack_symbols);
81 
82  --len;
83 
84  oldretaddr = (ADDR)(uintptr_t) \
85  array_list_item(cfit->shadow_stack,len - 1);
86  symbol = (struct bsymbol *) \
87  array_list_item(cfit->shadow_stack_symbols,len - 1);
88 
90  "popping retaddr = 0x%"PRIxADDR" (%d) (0x%s);"
91  " replacing with NULL (also skipped a NULL)\n",
92  oldretaddr,array_list_len(cfit->shadow_stack),
93  bsymbol_get_name(symbol));
94 
95  array_list_remove(cfit->shadow_stack);
96  array_list_remove(cfit->shadow_stack_symbols);
97 
98  bsymbol_release(symbol);
99 
100  /* Replace it with a NULL, or don't if NULL was there. */
101  return __cfit_stack_makenull(cfit);
102  }
103  else {
104  /* End of stack is already NULL; leave it alone! */
105  return 1;
106  }
107  }
108  else {
109  vdebug(8,LA_LIB,LF_CFI,
110  "popping retaddr = 0x%"PRIxADDR" (%d) (0x%s);"
111  " replacing with NULL\n",
112  oldretaddr,array_list_len(cfit->shadow_stack),
113  bsymbol_get_name(symbol));
114 
115  array_list_remove(cfit->shadow_stack);
116  array_list_remove(cfit->shadow_stack_symbols);
117 
118  bsymbol_release(symbol);
119 
120  /* Replace it with a NULL, or don't if NULL was there. */
121  return __cfit_stack_makenull(cfit);
122  }
123  }
124  else {
125  /* Add a single NULL. */
126  return __cfit_stack_makenull(cfit);
127  }
128 }
129 
131  struct probe *trigger,struct probe *base) {
132  struct cfi_data *cfi = (struct cfi_data *)data;
133  struct cfi_thread_status *cfit;
134  REGVAL sp, ip;
135  ADDR retaddr;
136  struct bsymbol *bsymbol;
137 
138  if (cfi->tid != TID_GLOBAL && tid != cfi->tid) {
139  vdebug(8,LA_LIB,LF_CFI,
140  "skipping cfi probe in tid %d that is not our tid (%d)\n",
141  tid,cfi->tid);
142  return 0;
143  }
144 
145  cfit = (struct cfi_thread_status *) \
146  g_hash_table_lookup(cfi->thread_status,(gpointer)(uintptr_t)tid);
147  if (!cfit) {
148  cfit = calloc(1,sizeof(*cfit));
149  cfit->shadow_stack = array_list_create(16);
150  cfit->shadow_stack_symbols = array_list_create(16);
151  g_hash_table_insert(cfi->thread_status,(gpointer)(uintptr_t)tid,cfit);
152  }
153 
154  errno = 0;
155  sp = target_read_creg(cfi->target,cfi->tid,CREG_SP);
156  if (errno) {
157  verror("could not read SP!\n");
158  return RESULT_ERROR;
159  }
160 
161  /* Grab the return address on the top of the stack */
162  retaddr = 0;
163  if (!target_read_addr(cfi->target,(ADDR)sp,sizeof(ADDR),
164  (unsigned char *)&retaddr)) {
165  verror("could not read top of stack!\n");
166  return 0;
167  }
168 
169  /* Grab the current IP -- the post-call IP */
170  ip = target_read_creg(cfi->target,cfi->tid,CREG_IP);
171  if (errno) {
172  verror("could not read IP!\n");
173  return 0;
174  }
175 
176  bsymbol = target_lookup_sym_addr(cfi->target,ip);
177  if (bsymbol) {
178  if (cfi_instrument_func(cfi,bsymbol,0)) {
179  vwarn("tid %d retaddr = 0x%"PRIxADDR" (%d) branch 0x%"PRIxADDR" ->"
180  " 0x%"PRIxADDR" (%s) probe(%s) (trying code block)!\n",
181  tid,retaddr,array_list_len(cfit->shadow_stack),
182  probe_addr(base),ip,bsymbol_get_name(bsymbol),
183  probe_name(base));
184 
185  bsymbol_release(bsymbol);
186  bsymbol = NULL;
187  //__cfit_stack_makenull(cfit);
188  }
189  else {
190  vdebug(5,LA_LIB,LF_CFI,
191  "tid %d retaddr = 0x%"PRIxADDR" (%d) branch 0x%"PRIxADDR" ->"
192  " 0x%"PRIxADDR" (%s) probe(%s) (tracking)\n",
193  tid,retaddr,array_list_len(cfit->shadow_stack),
194  probe_addr(base),ip,bsymbol_get_name(bsymbol),
195  probe_name(base));
196 
197  /* Since we know that the call is a known function that
198  * we can disasm and instrument return points for, push
199  * it onto the shadow stack!
200  */
201  array_list_append(cfit->shadow_stack,(void *)(uintptr_t)retaddr);
202  array_list_append(cfit->shadow_stack_symbols,bsymbol);
203  }
204  }
205 
206  if (!bsymbol) {
207  vdebug(8,LA_LIB,LF_CFI,
208  "tid %d retaddr = 0x%"PRIxADDR" (%d) branch 0x%"PRIxADDR" ->"
209  " 0x%"PRIxADDR" probe(%s) (trying code block)\n",
210  tid,retaddr,array_list_len(cfit->shadow_stack),
211  probe_addr(base),ip,probe_name(base));
212 
213  if (cfi_instrument_block(cfi,ip,0)) {
214  vwarn("tid %d could not instrument code block for ip 0x%"PRIxADDR";"
215  " not tracking!\n",tid,ip);
216 
217  __cfit_stack_makenull(cfit);
218  }
219  else {
220  /*
221  * Since we know that the call is a known code range (even
222  * though we can't find a symbol for it) that we can disasm
223  * and instrument return points for, push it onto the shadow
224  * stack!
225  */
226  array_list_append(cfit->shadow_stack,(void *)(uintptr_t)retaddr);
227  array_list_append(cfit->shadow_stack_symbols,NULL);
228 
229  return 0;
230  }
231  }
232 
233  if (bsymbol)
234  bsymbol_release(bsymbol);
235 
236  return 0;
237 }
238 
240  struct probe *trigger,struct probe *base) {
241  struct cfi_data *cfi = (struct cfi_data *)data;
242  struct cfi_thread_status *cfit;
243  REGVAL ip;
244  struct bsymbol *bsymbol;
245 
246  if (cfi->tid != TID_GLOBAL && tid != cfi->tid) {
247  vdebug(8,LA_LIB,LF_CFI,
248  "skipping cfi probe in tid %d that is not our tid (%d)\n",
249  tid,cfi->tid);
250  return 0;
251  }
252 
253  cfit = (struct cfi_thread_status *) \
254  g_hash_table_lookup(cfi->thread_status,(gpointer)(uintptr_t)tid);
255  if (!cfit) {
256  cfit = calloc(1,sizeof(*cfit));
257  cfit->shadow_stack = array_list_create(16);
258  cfit->shadow_stack_symbols = array_list_create(16);
259  g_hash_table_insert(cfi->thread_status,(gpointer)(uintptr_t)tid,cfit);
260  }
261 
262  /* Grab the current IP -- the post-jmp IP */
263  ip = target_read_creg(cfi->target,cfi->tid,CREG_IP);
264  if (errno) {
265  verror("could not read IP!\n");
266  return 0;
267  }
268 
269  bsymbol = target_lookup_sym_addr(cfi->target,ip);
270 
271  if (bsymbol) {
272  if (cfi_instrument_func(cfi,bsymbol,0)) {
273  vwarn("tid %d could not instrument branch 0x%"PRIxADDR" -> (0x%"PRIxADDR
274  " (%s); not tracking (removing last call)!\n",
275  tid,probe_addr(base),ip,bsymbol_get_name(bsymbol));
276 
277  bsymbol_release(bsymbol);
278  bsymbol = NULL;
279 
280  /*
281  * XXX XXX XXX
282  *
283  * In this case, we need to do the third-stack trick of
284  * knowing whether the last non-null was a call, or a jump.
285  * If it was a call, we have to roll it back and put a NULL
286  * in the other stacks. If it was a jump, we have to trace
287  * back until we hit a function, then remove that one and
288  * put a NULL in its place.
289  */
290 
291  //__cfit_stack_makelastnull(cfit);
292  }
293  }
294 
295  if (!bsymbol) {
296  if (cfi_instrument_block(cfi,ip,0)) {
297  vwarn("tid %d could not instrument code block for branch target"
298  " 0x%"PRIxADDR" -> 0x%"PRIxADDR";"
299  " not tracking (removing last call)!\n",
300  tid,probe_addr(base),ip);
301 
302  __cfit_stack_makelastnull(cfit);
303  }
304  }
305 
306  if (bsymbol)
307  bsymbol_release(bsymbol);
308 
309  return RESULT_SUCCESS;
310 }
311 
313  struct probe *trigger,struct probe *base) {
314  struct cfi_data *cfi = (struct cfi_data *)data;
315  struct cfi_thread_status *cfit;
316  REGVAL sp;
317  ADDR newretaddr;
318  ADDR oldretaddr;
319  struct bsymbol *symbol;
320  struct bsymbol *bsymbol;
321  ADDR oldretaddr2;
322 
323  if (cfi->tid != TID_GLOBAL && tid != cfi->tid) {
324  vdebug(8,LA_LIB,LF_CFI,
325  "skipping cfi probe in tid %d that is not our tid (%d)\n",
326  tid,cfi->tid);
327  return 0;
328  }
329 
330  cfit = (struct cfi_thread_status *) \
331  g_hash_table_lookup(cfi->thread_status,(gpointer)(uintptr_t)tid);
332  if (!cfit) {
333  cfit = calloc(1,sizeof(*cfit));
334  cfit->shadow_stack = array_list_create(16);
335  cfit->shadow_stack_symbols = array_list_create(16);
336  g_hash_table_insert(cfi->thread_status,(gpointer)(uintptr_t)tid,cfit);
337  }
338 
339  /* These are probably from functions we instrumented, but
340  * that were not called from our function root set.
341  */
342  if (array_list_len(cfit->shadow_stack) == 0) {
343  ++cfi->status.nonrootsethits;
344  ++cfit->status.nonrootsethits;
345  return RESULT_SUCCESS;
346  }
347 
348  errno = 0;
349  sp = target_read_creg(cfi->target,cfi->tid,CREG_SP);
350  if (errno) {
351  verror("could not read SP!\n");
352  return RESULT_ERROR;
353  }
354 
355  oldretaddr = (ADDR)(uintptr_t) \
356  array_list_item(cfit->shadow_stack,
357  array_list_len(cfit->shadow_stack) - 1);
358  symbol = (struct bsymbol *) \
359  array_list_item(cfit->shadow_stack_symbols,
360  array_list_len(cfit->shadow_stack_symbols) - 1);
361 
362  if (!target_read_addr(cfi->target,(ADDR)sp,sizeof(ADDR),
363  (unsigned char *)&newretaddr)) {
364  verror("tid %d could not read retaddr from top of stack!\n",tid);
365  array_list_remove(cfit->shadow_stack);
366  array_list_remove(cfit->shadow_stack_symbols);
367  return RESULT_ERROR;
368  }
369 
370  if (oldretaddr == 0 && symbol == NULL) {
371  /*
372  * This is an "unknown code" that was jumped into and we halted
373  * tracking; so allow this return!
374  */
375 
376  oldretaddr2 = (ADDR)(uintptr_t) \
377  array_list_item(cfit->shadow_stack,
378  array_list_len(cfit->shadow_stack) - 2);
379 
380  /*
381  * If we were off in the unknown code region, and are finally
382  * getting back to known code, allow it! We basically push a
383  * single NULL -- not multiple NULLs -- so we use it as a
384  * placeholder wildcard, almost :).
385  */
386  if (oldretaddr2 == newretaddr) {
387  array_list_remove(cfit->shadow_stack);
388  array_list_remove(cfit->shadow_stack_symbols);
389 
390  oldretaddr = (ADDR)(uintptr_t) \
391  array_list_item(cfit->shadow_stack,
392  array_list_len(cfit->shadow_stack) - 1);
393  symbol = (struct bsymbol *) \
394  array_list_item(cfit->shadow_stack_symbols,
395  array_list_len(cfit->shadow_stack_symbols) - 1);
396 
397  vdebug(8,LA_LIB,LF_CFI,
398  "tid %d leaving untracked sequence; newretaddr = 0x%"PRIxADDR";"
399  " oldretaddr = 0x%"PRIxADDR" (probe %s)!\n",
400  tid,newretaddr,oldretaddr2,probe_name(base));
401 
402  goto cficlean;
403  }
404  else {
405  vdebug(8,LA_LIB,LF_CFI,
406  "tid %d not leaving untracked sequence; newretaddr = 0x%"PRIxADDR";"
407  " oldretaddr = 0x%"PRIxADDR" (probe %s)!\n",
408  tid,newretaddr,oldretaddr2,probe_name(base));
409  return 0;
410  }
411  }
412  else if (newretaddr != oldretaddr) {
413  /*
414  * Check for RET-immediates; if the RET cleans up its stack
415  * *after* reading the retaddr, it is probably really just
416  * jumping elsewhere and cleaning up its current frame and
417  * replacing it with the "jumped"-to addr. If this is the case,
418  * handle it like we do dynamic jumps, by instrumenting the
419  * jumped-to code.
420  */
421  if (g_hash_table_lookup(cfi->ret_immediate_addrs,
422  (gpointer)(uintptr_t)probe_addr(base))) {
423  bsymbol = target_lookup_sym_addr(cfi->target,newretaddr);
424 
425  vdebug(5,LA_LIB,LF_CFI,
426  "tid %d retaddr = 0x%"PRIxADDR" (%d) (ret-immediate; oldretaddr ="
427  " 0x%"PRIxADDR") probe %s (0x%"PRIxADDR")\n",
428  tid,newretaddr,array_list_len(cfit->shadow_stack),oldretaddr,
429  probe_name(probe),probe_addr(base));
430 
431  if (bsymbol) {
432  if (cfi_instrument_func(cfi,bsymbol,0)) {
433  vwarn("tid %d could not instrument function %s (0x%"PRIxADDR");"
434  " trying code block!\n",
435  tid,bsymbol_get_name(bsymbol),newretaddr);
436  bsymbol_release(bsymbol);
437  bsymbol = NULL;
438  }
439  }
440 
441  if (!bsymbol) {
442  if (cfi_instrument_block(cfi,newretaddr,0)) {
443  vwarn("tid %d could not instrument code block for RETI"
444  " newretaddr 0x%"PRIxADDR"; not tracking!\n",
445  tid,newretaddr);
446  }
447  }
448 
449  if (bsymbol) {
450  bsymbol_release(bsymbol);
451  bsymbol = NULL;
452  }
453 
454  return 0;
455  }
456  else {
457  cfi->status.isviolation = 1;
458  cfit->status.isviolation = 1;
459  cfi->status.oldretaddr = oldretaddr;
460  cfit->status.oldretaddr = oldretaddr;
461  cfi->status.newretaddr = newretaddr;
462  cfit->status.newretaddr = newretaddr;
463 
464  cfi->cfi_probe->post_handler(cfi->cfi_probe,tid,
465  cfi->cfi_probe->handler_data,
466  probe,base);
467 
468  cfi->status.isviolation = 0;
469  cfit->status.isviolation = 0;
470  cfi->status.oldretaddr = 0;
471  cfit->status.oldretaddr = 0;
472  cfi->status.newretaddr = 0;
473  cfit->status.newretaddr = 0;
474 
475  ++cfi->status.violations;
476  ++cfit->status.violations;
477 
478  vdebug(5,LA_LIB,LF_CFI,
479  "tid %d retaddr = 0x%"PRIxADDR" (%d) (violation! oldretaddr ="
480  " 0x%"PRIxADDR") probe %s (0x%"PRIxADDR")\n",
481  tid,newretaddr,array_list_len(cfit->shadow_stack),oldretaddr,
482  probe_name(probe),probe_addr(base));
483 
484  /*
485  * Maybe try to fix the stack; probably won't work that well :)
486  */
487  if (cfi->flags & CFI_FIXUP) {
488  if (!target_write_addr(cfi->target,(ADDR)sp,sizeof(ADDR),
489  (unsigned char *)&oldretaddr)) {
490  verror("could not fixup top of stack in retaddr_check!\n");
491  }
492  else
493  vdebug(5,LA_LIB,LF_CFI,"reset stack after corruption!\n");
494  }
495  }
496  }
497  else {
498  cficlean:
499  cfi->status.isviolation = 0;
500  cfit->status.isviolation = 0;
501  cfi->status.oldretaddr = oldretaddr;
502  cfit->status.oldretaddr = oldretaddr;
503  cfi->status.newretaddr = newretaddr;
504  cfit->status.newretaddr = newretaddr;
505 
506  cfi->cfi_probe->pre_handler(cfi->cfi_probe,tid,
507  cfi->cfi_probe->handler_data,
508  probe,base);
509 
510  cfi->status.isviolation = 0;
511  cfit->status.isviolation = 0;
512  cfi->status.oldretaddr = 0;
513  cfit->status.oldretaddr = 0;
514  cfi->status.newretaddr = 0;
515  cfit->status.newretaddr = 0;
516 
517  vdebug(5,LA_LIB,LF_CFI,
518  "tid %d retaddr = 0x%"PRIxADDR" (%d) (clean) probe(%s) (0x%"PRIxADDR")\n",
519  tid,newretaddr,array_list_len(cfit->shadow_stack),
520  probe_name(probe),probe_addr(base));
521  }
522 
523  /*
524  * Wait to free the retaddr and release the symbol until we have
525  * called the handlers.
526  */
527  array_list_remove(cfit->shadow_stack);
528  if (symbol)
529  bsymbol_release(symbol);
530  array_list_remove(cfit->shadow_stack_symbols);
531 
532  return 0;
533 }
534 
536  struct cfi_data *cfi;
538 };
539 
540 static int cfi_probe_disasm_handler(struct cf_inst_data *id,ADDR iaddr,
541  void *handler_data,
542  struct probe **probe_alt) {
543  struct cfi_probe_disasm_state *s = \
544  (struct cfi_probe_disasm_state *)handler_data;
545 
546  /*
547  * If this is a jump instr, and it has an absolute target address,
548  * add that address to our list -- AND DO NOT probe on it! Also
549  * don't probe on any jump target that is in the disasm segment;
550  * those don't "go" anywhere :).
551  */
552  if (id->type == INST_JMP || id->type == INST_JCC) {
553  if (id->cf.target_in_segment)
554  return 0;
555  else if (id->cf.target_is_valid) {
556  array_list_append(s->absolute_branch_targets,
557  (void *)(uintptr_t)id->cf.target);
558  return 0;
559  }
560  }
561  /*
562  * If this is a RET that reads its retaddr off stack top, THEN
563  * adjusts the stack to clear the current frame -- assume it is
564  * "returning" into or to another function; so we need a different
565  * probe handler than the normal ret handler. Basically, our
566  * handler needs to grab the retaddr; if it agrees, assume a normal
567  * return; if it does not agree, then assume a *valid* control
568  * transfer to another function, and add that function to our
569  * tracked set.
570  */
571  else if (id->type == INST_RET && id->size == 3) {
572  if (!(s->cfi->flags & CFI_NOAUTOFOLLOW)) {
573  g_hash_table_insert(s->cfi->ret_immediate_addrs,
574  (gpointer)(uintptr_t)iaddr,(gpointer)1);
575  return 1;
576  }
577  }
578 
579  return 1;
580 }
581 
582 static int cfi_instrument_func(struct cfi_data *cfi,struct bsymbol *bsymbol,
583  int isroot) {
584  ADDR funcstart = 0;
585  int bufsiz;
586  char *buf;
587  struct probe *cprobe = NULL;
588  struct probe *rprobe = NULL;
589  struct probe *jprobe = NULL;
590  char *name;
591  struct cfi_probe_disasm_state pds;
592  struct bsymbol *absolute_branch_symbol;
593  ADDR absolute_branch_addr;
594  int i;
595  void *item;
596  struct target_location_ctxt *tlctxt;
597 
599  bsymbol);
600  if (target_bsymbol_resolve_base(cfi->target,tlctxt,bsymbol,&funcstart,NULL)) {
601  verror("could not resolve base addr for function %s!\n",
602  bsymbol_get_name(bsymbol));
604  return -1;
605  }
607 
608  if (g_hash_table_lookup(cfi->disfuncs_noflow,(gpointer)funcstart))
609  return -1;
610 
611  /* Disassemble the called function if we haven't already! */
612  if (!g_hash_table_lookup(cfi->disfuncs,(gpointer)funcstart)) {
613  /* Dissasemble the function and grab a list of
614  * RET instrs, and insert more child
615  * breakpoints.
616  */
617  name = bsymbol_get_name(bsymbol);
618  if (name) {
619  bufsiz = sizeof("call_in_") + strlen(name) + 1;
620  buf = malloc(bufsiz);
621  snprintf(buf,bufsiz,"call_in_%s",name);
622  }
623  else {
624  bufsiz = sizeof("call_in_") + sizeof(ADDR) * 2 + 1;
625  buf = malloc(bufsiz);
626  snprintf(buf,bufsiz,"call_in_%"PRIxADDR,funcstart);
627  }
628 
629  cprobe = probe_create(cfi->target,cfi->tid,NULL,buf,NULL,
630  cfi_dynamic_retaddr_save,cfi,0,0);
631  free(buf);
632 
633  if (!isroot) {
634  if (name) {
635  bufsiz = sizeof("ret_in_") + strlen(name) + 1;
636  buf = malloc(bufsiz);
637  snprintf(buf,bufsiz,"ret_in_%s",name);
638  }
639  else {
640  bufsiz = sizeof("ret_in_") + sizeof(ADDR) * 2 + 1;
641  buf = malloc(bufsiz);
642  snprintf(buf,bufsiz,"ret_in_%"PRIxADDR,funcstart);
643  }
644 
645  rprobe = probe_create(cfi->target,cfi->tid,NULL,buf,
646  cfi_dynamic_retaddr_check,NULL,cfi,0,0);
647  free(buf);
648  }
649 
650  if (name) {
651  bufsiz = sizeof("jmp_in_") + strlen(name) + 1;
652  buf = malloc(bufsiz);
653  snprintf(buf,bufsiz,"jmp_in_%s",name);
654  }
655  else {
656  bufsiz = sizeof("jmp_in_") + sizeof(ADDR) * 2 + 1;
657  buf = malloc(bufsiz);
658  snprintf(buf,bufsiz,"jmp_in_%"PRIxADDR,funcstart);
659  }
660 
661  jprobe = probe_create(cfi->target,cfi->tid,NULL,buf,NULL,
663  free(buf);
664 
665  pds.absolute_branch_targets = array_list_create(0);
666  pds.cfi = cfi;
667 
668  /*
669  * XXX: can we do this optimization; suppose one of our root
670  * functions is not really a root, but is called by another
671  * function it itself calls. So we have to catch these RETs
672  * too.
673  *
674  * ???
675  */
676 
677  if (isroot) {
678  if (!probe_register_function_instrs(bsymbol,PROBEPOINT_SW,1,
679  cfi_probe_disasm_handler,&pds,
680  INST_CALL,cprobe,
681  INST_JMP,jprobe,
682  INST_NONE)) {
683  probe_free(cprobe,1);
684  return -2;
685  }
686  }
687  else {
688  if (!probe_register_function_instrs(bsymbol,PROBEPOINT_SW,1,
689  cfi_probe_disasm_handler,&pds,
690  INST_RET,rprobe,
691  INST_CALL,cprobe,
692  INST_JMP,jprobe,
693  INST_NONE)) {
694  probe_free(cprobe,1);
695  probe_free(rprobe,1);
696  return -2;
697  }
698  }
699 
700  if (probe_num_sources(cprobe) == 0) {
701  vdebug(5,LA_LIB,LF_CFI,
702  "no call sites in %s; removing\n",probe_name(cprobe));
703  probe_free(cprobe,1);
704  cprobe = NULL;
705  }
706  else {
707  g_hash_table_insert(cfi->probes,(gpointer)cprobe,(gpointer)cprobe);
708  vdebug(5,LA_LIB,LF_CFI,
709  "registered %d call probes on %s\n",
710  probe_num_sources(cprobe),probe_name(cprobe));
711  }
712 
713  if (!isroot) {
714  /*
715  * If the function does not have any exit points, don't
716  * bother tracking calls to it!
717  */
718  if (probe_num_sources(rprobe) == 0) {
719  vdebug(5,LA_LIB,LF_CFI,
720  "no return sites in %s; removing\n",probe_name(rprobe));
721  probe_free(rprobe,1);
722  rprobe = NULL;
723  }
724  else {
725  g_hash_table_insert(cfi->probes,(gpointer)rprobe,(gpointer)rprobe);
726  vdebug(5,LA_LIB,LF_CFI,
727  "registered %d return probes on %s\n",
728  probe_num_sources(rprobe),probe_name(rprobe));
729  }
730  }
731 
732  if (probe_num_sources(jprobe) == 0) {
733  vdebug(5,LA_LIB,LF_CFI,
734  "no indirect jmp sites in %s; removing\n",probe_name(jprobe));
735  probe_free(jprobe,1);
736  jprobe = NULL;
737  }
738  else {
739  g_hash_table_insert(cfi->probes,(gpointer)jprobe,(gpointer)jprobe);
740  vdebug(5,LA_LIB,LF_CFI,
741  "registered %d jmp probes on %s\n",
742  probe_num_sources(jprobe),probe_name(jprobe));
743  }
744 
745  /*
746  * If no control flow was found, we have to return to the caller
747  * with an error; we cannot track this function in dynamic CFI.
748  */
749  if (!cprobe && !rprobe && !jprobe) {
750  array_list_free(pds.absolute_branch_targets);
751 
752  g_hash_table_insert(cfi->disfuncs_noflow,
753  (gpointer)funcstart,(gpointer)1);
754 
755  return -3;
756  }
757  else
758  g_hash_table_insert(cfi->disfuncs,(gpointer)funcstart,(gpointer)1);
759 
760  /*
761  * If the function had absolute jump targets outside of it, we
762  * have to instrument the blocks containing those things too!
763  *
764  * NB: this MUST come last (esp after the cfi->disfuncs
765  * insertion above)! Otherwise, there is a risk of infinite
766  * recursion.
767  */
768  if (array_list_len(pds.absolute_branch_targets) > 0) {
769  array_list_foreach(pds.absolute_branch_targets,i,item) {
770  absolute_branch_addr = (ADDR)item;
771  absolute_branch_symbol =
772  target_lookup_sym_addr(cfi->target,absolute_branch_addr);
773 
774  if (absolute_branch_symbol) {
775  if (cfi_instrument_func(cfi,absolute_branch_symbol,0)) {
776  vdebug(8,LA_LIB,LF_CFI,
777  "could not find symbol for ip 0x%"PRIxADDR" (%s);"
778  " trying code block!\n",
779  absolute_branch_addr,
780  bsymbol_get_name(absolute_branch_symbol));
781  bsymbol_release(absolute_branch_symbol);
782  absolute_branch_symbol = NULL;
783  }
784  }
785 
786  if (!absolute_branch_symbol) {
787  if (cfi_instrument_block(cfi,absolute_branch_addr,0)) {
788  vwarn("could not instrument block for addr 0x%"PRIxADDR";"
789  " CFI might be BUGGY!\n",
790  absolute_branch_addr);
791  }
792  }
793 
794  if (absolute_branch_symbol)
795  bsymbol_release(absolute_branch_symbol);
796  }
797  }
798  array_list_free(pds.absolute_branch_targets);
799  }
800 
801  return 0;
802 }
803 
804 static int cfi_instrument_block(struct cfi_data *cfi,ADDR ip,int isroot) {
805  ADDR start = 0,end = 0;
806  int bufsiz;
807  char *buf;
808  struct probe *cprobe = NULL;
809  struct probe *rprobe = NULL;
810  struct probe *jprobe = NULL;
811  struct cfi_probe_disasm_state pds;
812  struct bsymbol *absolute_branch_symbol;
813  ADDR absolute_branch_addr;
814  int i;
815  void *item;
816 
817  if (target_lookup_safe_disasm_range(cfi->target,ip,&start,&end,NULL)) {
818  verror("no safe disasm range contains target ip 0x%"PRIxADDR"!\n",ip);
819  return -1;
820  }
821 
822  if (g_hash_table_lookup(cfi->disfuncs_noflow,(gpointer)start))
823  return -1;
824 
825  /* Probe the called-into block if we haven't already! */
826  if (!g_hash_table_lookup(cfi->disfuncs,(gpointer)start)) {
827  bufsiz = sizeof("call_in_") + sizeof(ADDR) * 2 + 1;
828  buf = malloc(bufsiz);
829  snprintf(buf,bufsiz,"call_in_%"PRIxADDR,start);
830 
831  cprobe = probe_create(cfi->target,cfi->tid,NULL,buf,NULL,
832  cfi_dynamic_retaddr_save,cfi,0,0);
833  free(buf);
834 
835  if (!isroot) {
836  bufsiz = sizeof("ret_in_") + sizeof(ADDR) * 2 + 1;
837  buf = malloc(bufsiz);
838  snprintf(buf,bufsiz,"ret_in_%"PRIxADDR,start);
839 
840  rprobe = probe_create(cfi->target,cfi->tid,NULL,buf,
841  cfi_dynamic_retaddr_check,NULL,cfi,0,0);
842  free(buf);
843  }
844 
845  bufsiz = sizeof("jmp_in_") + sizeof(ADDR) * 2 + 1;
846  buf = malloc(bufsiz);
847  snprintf(buf,bufsiz,"jmp_in_%"PRIxADDR,start);
848 
849  jprobe = probe_create(cfi->target,cfi->tid,NULL,buf,NULL,
851  free(buf);
852 
853  pds.absolute_branch_targets = array_list_create(0);
854  pds.cfi = cfi;
855 
856  /*
857  * XXX: can we do this optimization; suppose one of our root
858  * functions is not really a root, but is called by another
859  * function it itself calls. So we have to catch these RETs
860  * too.
861  *
862  * ???
863  */
864 
865  if (isroot) {
866  if (!probe_register_block_instrs(cfi->target,start,end,
867  PROBEPOINT_SW,1,
868  cfi_probe_disasm_handler,&pds,
869  INST_CALL,cprobe,
870  INST_JMP,jprobe,
871  INST_NONE)) {
872  probe_free(cprobe,1);
873  return -2;
874  }
875  }
876  else {
877  if (!probe_register_block_instrs(cfi->target,start,end,
878  PROBEPOINT_SW,1,
879  cfi_probe_disasm_handler,&pds,
880  INST_RET,rprobe,
881  INST_CALL,cprobe,
882  INST_JMP,jprobe,
883  INST_NONE)) {
884  probe_free(cprobe,1);
885  probe_free(rprobe,1);
886  return -2;
887  }
888  }
889 
890  if (probe_num_sources(cprobe) == 0) {
891  vdebug(5,LA_LIB,LF_CFI,
892  "no call sites in %s; removing\n",probe_name(cprobe));
893  probe_free(cprobe,1);
894  cprobe = NULL;
895  }
896  else {
897  g_hash_table_insert(cfi->probes,(gpointer)cprobe,(gpointer)cprobe);
898  vdebug(5,LA_LIB,LF_CFI,
899  "registered %d call probes on %s\n",
900  probe_num_sources(cprobe),probe_name(cprobe));
901  }
902 
903  if (!isroot) {
904  /*
905  * If the function does not have any exit points, don't
906  * bother tracking calls to it!
907  */
908  if (probe_num_sources(rprobe) == 0) {
909  vdebug(5,LA_LIB,LF_CFI,
910  "no return sites in %s; removing\n",probe_name(rprobe));
911  probe_free(rprobe,1);
912  rprobe = NULL;
913  }
914  else {
915  g_hash_table_insert(cfi->probes,(gpointer)rprobe,(gpointer)rprobe);
916  vdebug(5,LA_LIB,LF_CFI,
917  "registered %d return probes on %s\n",
918  probe_num_sources(rprobe),probe_name(rprobe));
919  }
920  }
921 
922  if (probe_num_sources(jprobe) == 0) {
923  vdebug(5,LA_LIB,LF_CFI,
924  "no indirect jmp sites in %s; removing\n",probe_name(jprobe));
925  probe_free(jprobe,1);
926  jprobe = NULL;
927  }
928  else {
929  g_hash_table_insert(cfi->probes,(gpointer)jprobe,(gpointer)jprobe);
930  vdebug(5,LA_LIB,LF_CFI,
931  "registered %d jmp probes on %s\n",
932  probe_num_sources(jprobe),probe_name(jprobe));
933  }
934 
935  /*
936  * If no control flow was found, we have to return to the caller
937  * with an error; we cannot track this function in dynamic CFI.
938  */
939  if (!cprobe && !rprobe && !jprobe) {
940  array_list_free(pds.absolute_branch_targets);
941 
942  g_hash_table_insert(cfi->disfuncs_noflow,
943  (gpointer)start,(gpointer)1);
944 
945  return -3;
946  }
947  else
948  g_hash_table_insert(cfi->disfuncs,(gpointer)start,(gpointer)1);
949 
950  /*
951  * If the function had absolute jump targets outside of it, we
952  * have to instrument the blocks containing those things too!
953  *
954  * NB: this MUST come last (esp after the cfi->disfuncs
955  * insertion above)! Otherwise, there is a risk of infinite
956  * recursion.
957  */
958  if (array_list_len(pds.absolute_branch_targets) > 0) {
959  array_list_foreach(pds.absolute_branch_targets,i,item) {
960  absolute_branch_addr = (ADDR)item;
961  absolute_branch_symbol =
962  target_lookup_sym_addr(cfi->target,absolute_branch_addr);
963 
964  if (absolute_branch_symbol) {
965  if (cfi_instrument_func(cfi,absolute_branch_symbol,0)) {
966  vdebug(8,LA_LIB,LF_CFI,
967  "could not find symbol for ip 0x%"PRIxADDR" (%s);"
968  " trying code block!\n",
969  absolute_branch_addr,
970  bsymbol_get_name(absolute_branch_symbol));
971  bsymbol_release(absolute_branch_symbol);
972  absolute_branch_symbol = NULL;
973  }
974  }
975 
976  if (!absolute_branch_symbol) {
977  if (cfi_instrument_block(cfi,absolute_branch_addr,0)) {
978  vwarn("could not instrument block for addr 0x%"PRIxADDR";"
979  " CFI might be BUGGY!\n",
980  absolute_branch_addr);
981  }
982  }
983 
984  if (absolute_branch_symbol)
985  bsymbol_release(absolute_branch_symbol);
986  }
987  }
988  array_list_free(pds.absolute_branch_targets);
989  }
990 
991  return 0;
992 }
993 
994 const char *probe_gettype_cfi(struct probe *probe) {
995  return "cfi";
996 }
997 
999  return &((struct cfi_data *)(probe->priv))->status;
1000 }
1001 
1003  struct cfi_data *cfi = (struct cfi_data *)probe->priv;
1004  struct cfi_thread_status *ts;
1005 
1006  if (!cfi)
1007  return NULL;
1008 
1009  ts = (struct cfi_thread_status *) \
1010  g_hash_table_lookup(cfi->thread_status,(gpointer)(uintptr_t)tid);
1011 
1012  return ts;
1013 }
1014 
1016  struct cfi_data *cfi = (struct cfi_data *)probe->priv;
1017  GHashTableIter iter;
1018  struct probe *tprobe;
1019  struct cfi_thread_status *tdata;
1020  struct bsymbol *symbol;
1021  int i;
1022 
1023  g_hash_table_destroy(cfi->disfuncs);
1024  g_hash_table_destroy(cfi->ret_immediate_addrs);
1025 
1026  g_hash_table_iter_init(&iter,cfi->probes);
1027  while (g_hash_table_iter_next(&iter,NULL,(gpointer *)&tprobe)) {
1028  probe_free(tprobe,0);
1029  }
1030  g_hash_table_destroy(cfi->probes);
1031 
1032  g_hash_table_iter_init(&iter,cfi->thread_status);
1033  while (g_hash_table_iter_next(&iter,NULL,(gpointer *)&tdata)) {
1034  array_list_free(tdata->shadow_stack);
1035  array_list_foreach(tdata->shadow_stack_symbols,i,symbol) {
1036  if (symbol)
1037  bsymbol_release(symbol);
1038  }
1039  array_list_free(tdata->shadow_stack_symbols);
1040  free(tdata);
1041  }
1042  g_hash_table_destroy(cfi->thread_status);
1043 
1044  free(cfi);
1045 
1046  return 0;
1047 }
1048 
1049 static struct probe_ops probe_ops_cfi = {
1051  .summarize = probe_summarize_cfi,
1052  .summarize_tid = probe_summarize_tid_cfi,
1053  .fini = probe_fini_cfi,
1054 };
1055 
1056 char *cfi_thread_backtrace(struct cfi_data *cfi,struct cfi_thread_status *cts,
1057  char *sep) {
1058  char *buf;
1059  int buflen;
1060  int rc = 0, rcr;
1061  ADDR base;
1062  struct bsymbol *function;
1063  char *name;
1064  void *retaddr;
1065  int i;
1066  int alen;
1067  struct target_location_ctxt *tlctxt;
1068 
1069  if (!sep)
1070  sep = " | ";
1071 
1072  buflen = 0;
1073  // 0xRETADDR <name> 0xBASEADDR |
1074  buflen += array_list_len(cts->shadow_stack) * (sizeof(ADDR) * 4 + 8 + 3);
1075  array_list_foreach(cts->shadow_stack_symbols,i,function) {
1076  if (!function)
1077  buflen += 4; // NULL
1078  else if (bsymbol_get_name(function))
1079  buflen += strlen(bsymbol_get_name(function));
1080  else
1081  buflen += 4; // NULL
1082  }
1083  buflen += 1; // '\0'
1084 
1085  buf = malloc(buflen);
1086  alen = array_list_len(cts->shadow_stack);
1087  array_list_foreach(cts->shadow_stack,i,retaddr) {
1088  function = (struct bsymbol *)array_list_item(cts->shadow_stack_symbols,i);
1089  name = NULL;
1090  base = 0;
1091  if (function) {
1092  name = bsymbol_get_name(function);
1094  function);
1095  target_bsymbol_resolve_base(cfi->target,tlctxt,function,&base,NULL);
1096  target_location_ctxt_free(tlctxt);
1097  }
1098  if (!name)
1099  name = "<UNKNOWN>";
1100 
1101  rcr = snprintf(buf + rc,buflen - rc,
1102  "0x%"PRIxADDR" %s 0x%"PRIxADDR,
1103  (ADDR)(uintptr_t)retaddr,name,base);
1104  rc += rcr;
1105  if ((i + 1) < alen) {
1106  rcr = snprintf(buf + rc,buflen - rc,"%s",sep);
1107  rc += rcr;
1108  }
1109  }
1110  if (rc > buflen)
1111  buf[buflen - 1] = '\0';
1112  else
1113  buf[rc] = '\0';
1114 
1115  return buf;
1116 }
1117 
1119  cfi_mode_t mode,cfi_flags_t flags,
1120  struct array_list *root_functions,
1121  struct array_list *root_addrs,
1123  void *handler_data) {
1124  struct cfi_data *cfi;
1125  struct probe *cfi_probe;
1126  char namebuf[64];
1127  int i;
1128  struct bsymbol *function;
1129  ADDR addr;
1130 
1131  /*
1132  * Only dynamic for now; see cfi.h .
1133  */
1134  if (mode != CFI_DYNAMIC) {
1135  verror("unsupported CFI mode %d!\n",mode);
1136  return NULL;
1137  }
1138 
1139  if (flags & CFI_SINGLESTEP_UNKNOWN) {
1140  vwarn("unsupported SINGLESTEP_UNKNOWN option!\n");
1141  }
1142 
1143  if (tid != TID_GLOBAL) {
1144  vwarn("CFI with specific thread %d might be buggy!\n",tid);
1145  }
1146 
1147  cfi = (struct cfi_data *)calloc(1,sizeof(*cfi));
1148  snprintf(namebuf,64,"cfi(target %d tid %d)",target->id,tid);
1149 
1150  cfi_probe =
1151  probe_create(target,tid,&probe_ops_cfi,namebuf,
1152  pre_handler ? pre_handler : probe_do_sink_pre_handlers,
1153  post_handler ? post_handler : probe_do_sink_post_handlers,
1154  handler_data,0,1);
1155  cfi_probe->priv = cfi;
1156  cfi->cfi_probe = cfi_probe;
1157  cfi->mode = mode;
1158  cfi->flags = flags;
1159  cfi->target = target;
1160  cfi->tid = tid;
1161 
1162  cfi->disfuncs = g_hash_table_new(g_direct_hash,g_direct_equal);
1163  cfi->disfuncs_noflow = g_hash_table_new(g_direct_hash,g_direct_equal);
1164  cfi->probes = g_hash_table_new(g_direct_hash,g_direct_equal);
1165  cfi->thread_status = g_hash_table_new(g_direct_hash,g_direct_equal);
1166  cfi->ret_immediate_addrs = g_hash_table_new(g_direct_hash,g_direct_equal);
1167 
1168  /*
1169  * Just instrument all the functions and addrs! If we fail, then free the
1170  * whole probe and return.
1171  */
1172  if (root_functions) {
1173  array_list_foreach(root_functions,i,function) {
1174  if (cfi_instrument_func(cfi,function,1)) {
1175  probe_free(cfi_probe,1);
1176  return NULL;
1177  }
1178  }
1179  }
1180  if (root_addrs) {
1181  array_list_foreach_fakeptr_t(root_addrs,i,addr,uintptr_t) {
1182  if (cfi_instrument_block(cfi,addr,1)) {
1183  probe_free(cfi_probe,1);
1184  return NULL;
1185  }
1186  }
1187  }
1188 
1189  return cfi_probe;
1190 }
1191 
1192 
struct target * target
Definition: cfi.h:150
result_t pre_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: spf.c:903
struct array_list * shadow_stack_symbols
Definition: cfi.h:142
struct cfi_status status
Definition: cfi.h:201
uint8_t size
Definition: disasm.h:101
int nonrootsethits
Definition: cfi.h:137
probe_handler_t pre_handler
Definition: probe.h:350
int32_t tid_t
Definition: common.h:36
GHashTable * thread_status
Definition: cfi.h:184
cfi_mode_t mode
Definition: cfi.h:147
void * probe_summarize_cfi(struct probe *probe)
Definition: cfi_util.c:998
result_t cfi_dynamic_jmp_target_instr(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: cfi_util.c:239
char * name
Definition: probe.h:314
static uint64_t unsigned int i
Definition: arch.h:74
inst_type_t type
Definition: disasm.h:99
int target_bsymbol_resolve_base(struct target *target, struct target_location_ctxt *tlctxt, struct bsymbol *bsymbol, ADDR *o_addr, struct memrange **o_range)
Definition: target.c:2618
struct target_location_ctxt * target_location_ctxt_create_from_bsymbol(struct target *target, tid_t tid, struct bsymbol *bsymbol)
Definition: target.c:5325
struct cfi_data * cfi
Definition: cfi_util.c:536
int target_in_segment
Definition: disasm.h:104
cfi_flags_t flags
Definition: cfi.h:148
result_t probe_do_sink_post_handlers(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
Definition: probe.c:109
char * bsymbol_get_name(struct bsymbol *bsymbol)
Definition: symbol.c:62
int probe_fini_cfi(struct probe *probe)
Definition: cfi_util.c:1015
#define verror(format,...)
Definition: log.h:30
result_t probe_do_sink_pre_handlers(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
Definition: probe.c:48
unsigned char * target_read_addr(struct target *target, ADDR addr, unsigned long length, unsigned char *buf)
Definition: target_api.c:1053
const char *(* gettype)(struct probe *probe)
Definition: probe_api.h:96
ADDR oldretaddr
Definition: cfi.h:133
result_t(* probe_handler_t)(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
Definition: probe_api.h:70
#define vwarn(format,...)
Definition: log.h:33
struct array_list * shadow_stack
Definition: cfi.h:141
void free(void *ptr)
Definition: debugserver.c:207
struct array_list * absolute_branch_targets
Definition: cfi_util.c:537
ADDR probe_addr(struct probe *probe)
Definition: probe.c:1959
struct cfi_status status
Definition: cfi.h:143
result_t cfi_dynamic_retaddr_check(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: cfi_util.c:312
GHashTable * probes
Definition: cfi.h:178
tid_t tid
Definition: probe.h:344
#define array_list_foreach(alist, lpc, placeholder)
Definition: alist.h:371
REFCNT bsymbol_release(struct bsymbol *bsymbol)
Definition: symbol.c:90
Definition: log.h:68
int tid
Definition: cfi.h:155
int probe_free(struct probe *probe, int force)
Definition: probe.c:777
int target_is_valid
Definition: disasm.h:104
struct bsymbol * target_lookup_sym_addr(struct target *target, ADDR addr)
Definition: target.c:2093
int len
Definition: dumptarget.c:52
cfi_flags_t
Definition: cfi.h:78
int probe_num_sources(struct probe *probe)
Definition: probe.c:1923
char * cfi_thread_backtrace(struct cfi_data *cfi, struct cfi_thread_status *cts, char *sep)
Definition: cfi_util.c:1056
Definition: probe.h:308
struct probe * probe_create(struct target *target, tid_t tid, struct probe_ops *pops, const char *name, probe_handler_t pre_handler, probe_handler_t post_handler, void *handler_data, int autofree, int tracked)
Definition: probe.c:729
REGVAL target_read_creg(struct target *target, tid_t tid, common_reg_t reg)
Definition: target_api.c:1178
#define vdebug(devel, areas, flags, format,...)
Definition: log.h:302
struct cf_inst_data::@12 cf
GHashTable * ret_immediate_addrs
Definition: cfi.h:195
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
result_t post_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: spf.c:908
ADDR target
Definition: disasm.h:132
result_t
Definition: common.h:25
void * probe_summarize_tid_cfi(struct probe *probe, tid_t tid)
Definition: cfi_util.c:1002
uint32_t REGVAL
Definition: common.h:66
cfi_mode_t
Definition: cfi.h:44
struct probe * cfi_probe
Definition: cfi_check.c:46
GHashTable * disfuncs
Definition: cfi.h:162
uint32_t ADDR
Definition: common.h:64
Definition: log.h:104
uint16_t violations
Definition: cfi.h:136
Definition: cfi.h:146
result_t cfi_dynamic_retaddr_save(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: cfi_util.c:130
#define PRIxADDR
Definition: common.h:67
void target_location_ctxt_free(struct target_location_ctxt *tlctxt)
Definition: target.c:5348
uint8_t isviolation
Definition: cfi.h:131
int id
Definition: target_api.h:2514
void * malloc(size_t size)
Definition: debugserver.c:214
struct probe * probe_cfi(struct target *target, tid_t tid, cfi_mode_t mode, cfi_flags_t flags, struct array_list *root_functions, struct array_list *root_addrs, probe_handler_t pre_handler, probe_handler_t post_handler, void *handler_data)
Definition: cfi_util.c:1118
ADDR newretaddr
Definition: cfi.h:134
unsigned long target_write_addr(struct target *target, ADDR addr, unsigned long length, unsigned char *buf)
Definition: target_api.c:1060
void * handler_data
Definition: probe.h:359
int target_lookup_safe_disasm_range(struct target *target, ADDR addr, ADDR *start, ADDR *end, void **data)
Definition: target.c:3825
#define array_list_foreach_fakeptr_t(alist, lpc, placeholder, intertype)
Definition: alist.h:381
char * probe_name(struct probe *probe)
Definition: probe.c:1935
void * priv
Definition: probe.h:318
const char * probe_gettype_cfi(struct probe *probe)
Definition: cfi_util.c:994
probe_handler_t post_handler
Definition: probe.h:354
#define TID_GLOBAL
Definition: target_api.h:145
GHashTable * disfuncs_noflow
Definition: cfi.h:173
Definition: arch.h:76
struct probe * cfi_probe
Definition: cfi.h:198
Definition: cfi.h:103