Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dwarf-aux.c
Go to the documentation of this file.
1 /*
2  * dwarf-aux.c : libdw auxiliary interfaces
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (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, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  */
19 
20 #include <stdbool.h>
21 #include "util.h"
22 #include "debug.h"
23 #include "dwarf-aux.h"
24 
32 const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
33 {
34  Dwarf_Files *files;
35  size_t nfiles, i;
36  const char *src = NULL;
37  int ret;
38 
39  if (!fname)
40  return NULL;
41 
42  ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
43  if (ret != 0)
44  return NULL;
45 
46  for (i = 0; i < nfiles; i++) {
47  src = dwarf_filesrc(files, i, NULL, NULL);
48  if (strtailcmp(src, fname) == 0)
49  break;
50  }
51  if (i == nfiles)
52  return NULL;
53  return src;
54 }
55 
64 const char *cu_get_comp_dir(Dwarf_Die *cu_die)
65 {
66  Dwarf_Attribute attr;
67  if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
68  return NULL;
69  return dwarf_formstring(&attr);
70 }
71 
81 int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
82  const char **fname, int *lineno)
83 {
84  Dwarf_Line *line;
85  Dwarf_Addr laddr;
86 
87  line = dwarf_getsrc_die(cu_die, (Dwarf_Addr)addr);
88  if (line && dwarf_lineaddr(line, &laddr) == 0 &&
89  addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) {
90  *fname = dwarf_linesrc(line, NULL, NULL);
91  if (!*fname)
92  /* line number is useless without filename */
93  *lineno = 0;
94  }
95 
96  return *lineno ?: -ENOENT;
97 }
98 
99 static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data);
100 
111 int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
112  int (*callback)(Dwarf_Die *, void *), void *data)
113 {
114  Dwarf_Die die_mem;
115  Dwarf_Die *sc_die;
116  int ret = -ENOENT;
117 
118  /* Inlined function could be recursive. Trace it until fail */
119  for (sc_die = die_find_realfunc(cu_die, addr, &die_mem);
120  sc_die != NULL;
121  sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr,
122  &die_mem)) {
123  ret = callback(sc_die, data);
124  if (ret)
125  break;
126  }
127 
128  return ret;
129 
130 }
131 
139 bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
140 {
141  const char *name;
142  name = dwarf_diename(dw_die);
143  return name ? (strcmp(tname, name) == 0) : false;
144 }
145 
153 int die_get_call_lineno(Dwarf_Die *in_die)
154 {
155  Dwarf_Attribute attr;
156  Dwarf_Word ret;
157 
158  if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
159  return -ENOENT;
160 
161  dwarf_formudata(&attr, &ret);
162  return (int)ret;
163 }
164 
173 Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
174 {
175  Dwarf_Attribute attr;
176 
177  if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
178  dwarf_formref_die(&attr, die_mem))
179  return die_mem;
180  else
181  return NULL;
182 }
183 
184 /* Get a type die, but skip qualifiers */
185 static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
186 {
187  int tag;
188 
189  do {
190  vr_die = die_get_type(vr_die, die_mem);
191  if (!vr_die)
192  break;
193  tag = dwarf_tag(vr_die);
194  } while (tag == DW_TAG_const_type ||
195  tag == DW_TAG_restrict_type ||
196  tag == DW_TAG_volatile_type ||
197  tag == DW_TAG_shared_type);
198 
199  return vr_die;
200 }
201 
212 Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
213 {
214  do {
215  vr_die = __die_get_real_type(vr_die, die_mem);
216  } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
217 
218  return vr_die;
219 }
220 
221 /* Get attribute and translate it as a udata */
222 static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
223  Dwarf_Word *result)
224 {
225  Dwarf_Attribute attr;
226 
227  if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
228  dwarf_formudata(&attr, result) != 0)
229  return -ENOENT;
230 
231  return 0;
232 }
233 
234 /* Get attribute and translate it as a sdata */
235 static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
236  Dwarf_Sword *result)
237 {
238  Dwarf_Attribute attr;
239 
240  if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
241  dwarf_formsdata(&attr, result) != 0)
242  return -ENOENT;
243 
244  return 0;
245 }
246 
254 bool die_is_signed_type(Dwarf_Die *tp_die)
255 {
256  Dwarf_Word ret;
257 
258  if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
259  return false;
260 
261  return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
262  ret == DW_ATE_signed_fixed);
263 }
264 
273 int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
274 {
275  Dwarf_Attribute attr;
276  Dwarf_Op *expr;
277  size_t nexpr;
278  int ret;
279 
280  if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
281  return -ENOENT;
282 
283  if (dwarf_formudata(&attr, offs) != 0) {
284  /* DW_AT_data_member_location should be DW_OP_plus_uconst */
285  ret = dwarf_getlocation(&attr, &expr, &nexpr);
286  if (ret < 0 || nexpr == 0)
287  return -ENOENT;
288 
289  if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
290  pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
291  expr[0].atom, nexpr);
292  return -ENOTSUP;
293  }
294  *offs = (Dwarf_Word)expr[0].number;
295  }
296  return 0;
297 }
298 
299 /* Get the call file index number in CU DIE */
300 static int die_get_call_fileno(Dwarf_Die *in_die)
301 {
302  Dwarf_Sword idx;
303 
304  if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0)
305  return (int)idx;
306  else
307  return -ENOENT;
308 }
309 
310 /* Get the declared file index number in CU DIE */
311 static int die_get_decl_fileno(Dwarf_Die *pdie)
312 {
313  Dwarf_Sword idx;
314 
315  if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0)
316  return (int)idx;
317  else
318  return -ENOENT;
319 }
320 
328 const char *die_get_call_file(Dwarf_Die *in_die)
329 {
330  Dwarf_Die cu_die;
331  Dwarf_Files *files;
332  int idx;
333 
334  idx = die_get_call_fileno(in_die);
335  if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) ||
336  dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
337  return NULL;
338 
339  return dwarf_filesrc(files, idx, NULL, NULL);
340 }
341 
342 
358 Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
359  int (*callback)(Dwarf_Die *, void *),
360  void *data, Dwarf_Die *die_mem)
361 {
362  Dwarf_Die child_die;
363  int ret;
364 
365  ret = dwarf_child(rt_die, die_mem);
366  if (ret != 0)
367  return NULL;
368 
369  do {
370  ret = callback(die_mem, data);
371  if (ret == DIE_FIND_CB_END)
372  return die_mem;
373 
374  if ((ret & DIE_FIND_CB_CHILD) &&
375  die_find_child(die_mem, callback, data, &child_die)) {
376  memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
377  return die_mem;
378  }
379  } while ((ret & DIE_FIND_CB_SIBLING) &&
380  dwarf_siblingof(die_mem, die_mem) == 0);
381 
382  return NULL;
383 }
384 
386  Dwarf_Addr addr;
387  Dwarf_Die *die_mem;
388 };
389 
390 /* die_find callback for non-inlined function search */
391 static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
392 {
393  struct __addr_die_search_param *ad = data;
394 
395  if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
396  dwarf_haspc(fn_die, ad->addr)) {
397  memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
398  return DWARF_CB_ABORT;
399  }
400  return DWARF_CB_OK;
401 }
402 
412 Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
413  Dwarf_Die *die_mem)
414 {
415  struct __addr_die_search_param ad;
416  ad.addr = addr;
417  ad.die_mem = die_mem;
418  /* dwarf_getscopes can't find subprogram. */
419  if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
420  return NULL;
421  else
422  return die_mem;
423 }
424 
425 /* die_find callback for inline function search */
426 static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
427 {
428  Dwarf_Addr *addr = data;
429 
430  if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
431  dwarf_haspc(die_mem, *addr))
432  return DIE_FIND_CB_END;
433 
434  return DIE_FIND_CB_CONTINUE;
435 }
436 
448 Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
449  Dwarf_Die *die_mem)
450 {
451  Dwarf_Die tmp_die;
452 
453  sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
454  if (!sp_die)
455  return NULL;
456 
457  /* Inlined function could be recursive. Trace it until fail */
458  while (sp_die) {
459  memcpy(die_mem, sp_die, sizeof(Dwarf_Die));
460  sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr,
461  &tmp_die);
462  }
463 
464  return die_mem;
465 }
466 
468  void *addr;
469  int (*callback)(Dwarf_Die *, void *);
470  void *data;
471  int retval;
472 };
473 
474 static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
475 {
476  struct __instance_walk_param *iwp = data;
477  Dwarf_Attribute attr_mem;
478  Dwarf_Die origin_mem;
479  Dwarf_Attribute *attr;
480  Dwarf_Die *origin;
481  int tmp;
482 
483  attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
484  if (attr == NULL)
485  return DIE_FIND_CB_CONTINUE;
486 
487  origin = dwarf_formref_die(attr, &origin_mem);
488  if (origin == NULL || origin->addr != iwp->addr)
489  return DIE_FIND_CB_CONTINUE;
490 
491  /* Ignore redundant instances */
492  if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) {
493  dwarf_decl_line(origin, &tmp);
494  if (die_get_call_lineno(inst) == tmp) {
495  tmp = die_get_decl_fileno(origin);
496  if (die_get_call_fileno(inst) == tmp)
497  return DIE_FIND_CB_CONTINUE;
498  }
499  }
500 
501  iwp->retval = iwp->callback(inst, iwp->data);
502 
503  return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE;
504 }
505 
516 int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *),
517  void *data)
518 {
519  Dwarf_Die cu_die;
520  Dwarf_Die die_mem;
521  struct __instance_walk_param iwp = {
522  .addr = or_die->addr,
523  .callback = callback,
524  .data = data,
525  .retval = -ENOENT,
526  };
527 
528  if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL)
529  return -ENOENT;
530 
531  die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem);
532 
533  return iwp.retval;
534 }
535 
536 /* Line walker internal parameters */
538  bool recursive;
540  void *data;
541  int retval;
542 };
543 
544 static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
545 {
546  struct __line_walk_param *lw = data;
547  Dwarf_Addr addr = 0;
548  const char *fname;
549  int lineno;
550 
551  if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
552  fname = die_get_call_file(in_die);
553  lineno = die_get_call_lineno(in_die);
554  if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
555  lw->retval = lw->callback(fname, lineno, addr, lw->data);
556  if (lw->retval != 0)
557  return DIE_FIND_CB_END;
558  }
559  }
560  if (!lw->recursive)
561  /* Don't need to search recursively */
562  return DIE_FIND_CB_SIBLING;
563 
564  if (addr) {
565  fname = dwarf_decl_file(in_die);
566  if (fname && dwarf_decl_line(in_die, &lineno) == 0) {
567  lw->retval = lw->callback(fname, lineno, addr, lw->data);
568  if (lw->retval != 0)
569  return DIE_FIND_CB_END;
570  }
571  }
572 
573  /* Continue to search nested inlined function call-sites */
574  return DIE_FIND_CB_CONTINUE;
575 }
576 
577 /* Walk on lines of blocks included in given DIE */
578 static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
579  line_walk_callback_t callback, void *data)
580 {
581  struct __line_walk_param lw = {
582  .recursive = recursive,
583  .callback = callback,
584  .data = data,
585  .retval = 0,
586  };
587  Dwarf_Die die_mem;
588  Dwarf_Addr addr;
589  const char *fname;
590  int lineno;
591 
592  /* Handle function declaration line */
593  fname = dwarf_decl_file(sp_die);
594  if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
595  dwarf_entrypc(sp_die, &addr) == 0) {
596  lw.retval = callback(fname, lineno, addr, data);
597  if (lw.retval != 0)
598  goto done;
599  }
600  die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
601 done:
602  return lw.retval;
603 }
604 
605 static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
606 {
607  struct __line_walk_param *lw = data;
608 
609  lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
610  if (lw->retval != 0)
611  return DWARF_CB_ABORT;
612 
613  return DWARF_CB_OK;
614 }
615 
628 int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
629 {
630  Dwarf_Lines *lines;
631  Dwarf_Line *line;
632  Dwarf_Addr addr;
633  const char *fname;
634  int lineno, ret = 0;
635  Dwarf_Die die_mem, *cu_die;
636  size_t nlines, i;
637 
638  /* Get the CU die */
639  if (dwarf_tag(rt_die) != DW_TAG_compile_unit)
640  cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
641  else
642  cu_die = rt_die;
643  if (!cu_die) {
644  pr_debug2("Failed to get CU from given DIE.\n");
645  return -EINVAL;
646  }
647 
648  /* Get lines list in the CU */
649  if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
650  pr_debug2("Failed to get source lines on this CU.\n");
651  return -ENOENT;
652  }
653  pr_debug2("Get %zd lines from this CU\n", nlines);
654 
655  /* Walk on the lines on lines list */
656  for (i = 0; i < nlines; i++) {
657  line = dwarf_onesrcline(lines, i);
658  if (line == NULL ||
659  dwarf_lineno(line, &lineno) != 0 ||
660  dwarf_lineaddr(line, &addr) != 0) {
661  pr_debug2("Failed to get line info. "
662  "Possible error in debuginfo.\n");
663  continue;
664  }
665  /* Filter lines based on address */
666  if (rt_die != cu_die)
667  /*
668  * Address filtering
669  * The line is included in given function, and
670  * no inline block includes it.
671  */
672  if (!dwarf_haspc(rt_die, addr) ||
673  die_find_inlinefunc(rt_die, addr, &die_mem))
674  continue;
675  /* Get source line */
676  fname = dwarf_linesrc(line, NULL, NULL);
677 
678  ret = callback(fname, lineno, addr, data);
679  if (ret != 0)
680  return ret;
681  }
682 
683  /*
684  * Dwarf lines doesn't include function declarations and inlined
685  * subroutines. We have to check functions list or given function.
686  */
687  if (rt_die != cu_die)
688  /*
689  * Don't need walk functions recursively, because nested
690  * inlined functions don't have lines of the specified DIE.
691  */
692  ret = __die_walk_funclines(rt_die, false, callback, data);
693  else {
694  struct __line_walk_param param = {
695  .callback = callback,
696  .data = data,
697  .retval = 0,
698  };
699  dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
700  ret = param.retval;
701  }
702 
703  return ret;
704 }
705 
707  const char *name;
708  Dwarf_Addr addr;
709 };
710 
711 static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
712 {
713  struct __find_variable_param *fvp = data;
714  int tag;
715 
716  tag = dwarf_tag(die_mem);
717  if ((tag == DW_TAG_formal_parameter ||
718  tag == DW_TAG_variable) &&
719  die_compare_name(die_mem, fvp->name))
720  return DIE_FIND_CB_END;
721 
722  if (dwarf_haspc(die_mem, fvp->addr))
723  return DIE_FIND_CB_CONTINUE;
724  else
725  return DIE_FIND_CB_SIBLING;
726 }
727 
737 Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
738  Dwarf_Addr addr, Dwarf_Die *die_mem)
739 {
740  struct __find_variable_param fvp = { .name = name, .addr = addr};
741 
742  return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
743  die_mem);
744 }
745 
746 static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
747 {
748  const char *name = data;
749 
750  if ((dwarf_tag(die_mem) == DW_TAG_member) &&
751  die_compare_name(die_mem, name))
752  return DIE_FIND_CB_END;
753 
754  return DIE_FIND_CB_SIBLING;
755 }
756 
765 Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
766  Dwarf_Die *die_mem)
767 {
768  return die_find_child(st_die, __die_find_member_cb, (void *)name,
769  die_mem);
770 }
771 
784 int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
785 {
786  Dwarf_Die type;
787  int tag, ret, ret2;
788  const char *tmp = "";
789 
790  if (__die_get_real_type(vr_die, &type) == NULL)
791  return -ENOENT;
792 
793  tag = dwarf_tag(&type);
794  if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
795  tmp = "*";
796  else if (tag == DW_TAG_subroutine_type) {
797  /* Function pointer */
798  ret = snprintf(buf, len, "(function_type)");
799  return (ret >= len) ? -E2BIG : ret;
800  } else {
801  if (!dwarf_diename(&type))
802  return -ENOENT;
803  if (tag == DW_TAG_union_type)
804  tmp = "union ";
805  else if (tag == DW_TAG_structure_type)
806  tmp = "struct ";
807  else if (tag == DW_TAG_enumeration_type)
808  tmp = "enum ";
809  /* Write a base name */
810  ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
811  return (ret >= len) ? -E2BIG : ret;
812  }
813  ret = die_get_typename(&type, buf, len);
814  if (ret > 0) {
815  ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
816  ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
817  }
818  return ret;
819 }
820 
829 int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
830 {
831  int ret, ret2;
832 
833  ret = die_get_typename(vr_die, buf, len);
834  if (ret < 0) {
835  pr_debug("Failed to get type, make it unknown.\n");
836  ret = snprintf(buf, len, "(unknown_type)");
837  }
838  if (ret > 0) {
839  ret2 = snprintf(buf + ret, len - ret, "\t%s",
840  dwarf_diename(vr_die));
841  ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
842  }
843  return ret;
844 }
845