Home | History | Annotate | Download | only in tests
      1 /* Test program for dwarf_getscopes.
      2    Copyright (C) 2005, 2014 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by
      7    the Free Software Foundation; either version 3 of the License, or
      8    (at your option) any later version.
      9 
     10    elfutils is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     17 
     18 #include <config.h>
     19 #include <assert.h>
     20 #include <inttypes.h>
     21 #include ELFUTILS_HEADER(dwfl)
     22 #include <dwarf.h>
     23 #include <argp.h>
     24 #include <stdio.h>
     25 #include <stdio_ext.h>
     26 #include <locale.h>
     27 #include <stdlib.h>
     28 #include <error.h>
     29 #include <string.h>
     30 
     31 
     32 static void
     33 paddr (const char *prefix, Dwarf_Addr addr, Dwfl_Line *line)
     34 {
     35   const char *src;
     36   int lineno, linecol;
     37   if (line != NULL
     38       && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
     39 			       NULL, NULL)) != NULL)
     40     {
     41       if (linecol != 0)
     42 	printf ("%s%#" PRIx64 " (%s:%d:%d)",
     43 		prefix, addr, src, lineno, linecol);
     44       else
     45 	printf ("%s%#" PRIx64 " (%s:%d)",
     46 		prefix, addr, src, lineno);
     47     }
     48   else
     49     printf ("%s%#" PRIx64, prefix, addr);
     50 }
     51 
     52 static void
     53 print_vars (unsigned int indent, Dwarf_Die *die)
     54 {
     55   Dwarf_Die child;
     56   if (dwarf_child (die, &child) == 0)
     57     do
     58       switch (dwarf_tag (&child))
     59 	{
     60 	case DW_TAG_variable:
     61 	case DW_TAG_formal_parameter:
     62 	  printf ("%*s%-30s[%6" PRIx64 "]\n", indent, "",
     63 		  dwarf_diename (&child),
     64 		  (uint64_t) dwarf_dieoffset (&child));
     65 	  break;
     66 	default:
     67 	  break;
     68 	}
     69     while (dwarf_siblingof (&child, &child) == 0);
     70 
     71   Dwarf_Attribute attr_mem;
     72   Dwarf_Die origin;
     73   if (dwarf_hasattr (die, DW_AT_abstract_origin)
     74       && dwarf_formref_die (dwarf_attr (die, DW_AT_abstract_origin, &attr_mem),
     75 			    &origin) != NULL
     76       && dwarf_child (&origin, &child) == 0)
     77     do
     78       switch (dwarf_tag (&child))
     79 	{
     80 	case DW_TAG_variable:
     81 	case DW_TAG_formal_parameter:
     82 	  printf ("%*s%s (abstract)\n", indent, "",
     83 		  dwarf_diename (&child));
     84 	  break;
     85 	default:
     86 	  break;
     87 	}
     88     while (dwarf_siblingof (&child, &child) == 0);
     89 }
     90 
     91 
     92 #define INDENT 4
     93 
     94 static void
     95 handle_address (GElf_Addr pc, Dwfl *dwfl)
     96 {
     97   Dwarf_Addr cubias;
     98   Dwarf_Die *cudie = dwfl_addrdie (dwfl, pc, &cubias);
     99   if (cudie == NULL)
    100     error (EXIT_FAILURE, 0, "dwfl_addrdie: %s", dwfl_errmsg (-1));
    101 
    102   Dwarf_Die *scopes;
    103   int n = dwarf_getscopes (cudie, pc - cubias, &scopes);
    104   if (n < 0)
    105     error (EXIT_FAILURE, 0, "dwarf_getscopes: %s", dwarf_errmsg (-1));
    106   else if (n == 0)
    107     printf ("%#" PRIx64 ": not in any scope\n", pc);
    108   else
    109     {
    110       printf ("%#" PRIx64 ":\n", pc);
    111       unsigned int indent = 0;
    112       while (n-- > 0)
    113 	{
    114 	  Dwarf_Die *const die = &scopes[n];
    115 
    116 	  indent += INDENT;
    117 	  printf ("%*s%s (%#x)", indent, "",
    118 		  dwarf_diename (die) ?: "<unnamed>",
    119 		  dwarf_tag (die));
    120 
    121 	  Dwarf_Addr lowpc, highpc;
    122 	  if (dwarf_lowpc (die, &lowpc) == 0
    123 	      && dwarf_highpc (die, &highpc) == 0)
    124 	    {
    125 	      lowpc += cubias;
    126 	      highpc += cubias;
    127 	      Dwfl_Line *loline = dwfl_getsrc (dwfl, lowpc);
    128 	      Dwfl_Line *hiline = dwfl_getsrc (dwfl, highpc - 1);
    129 	      paddr (": ", lowpc, loline);
    130 	      if (highpc != lowpc)
    131 		paddr (" .. ", highpc - 1, hiline == loline ? NULL : hiline);
    132 	    }
    133 	  puts ("");
    134 
    135 	  print_vars (indent + INDENT, die);
    136 	}
    137       free (scopes);
    138     }
    139 }
    140 
    141 int
    142 main (int argc, char *argv[])
    143 {
    144   int remaining;
    145 
    146   /* Set locale.  */
    147   (void) setlocale (LC_ALL, "");
    148 
    149   Dwfl *dwfl = NULL;
    150   (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, &dwfl);
    151   assert (dwfl != NULL);
    152 
    153   int result = 0;
    154 
    155   /* Now handle the addresses.  In case none are given on the command
    156      line, read from stdin.  */
    157   if (remaining == argc)
    158     {
    159       /* We use no threads here which can interfere with handling a stream.  */
    160       (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
    161 
    162       char *buf = NULL;
    163       size_t len = 0;
    164       while (!feof_unlocked (stdin))
    165 	{
    166 	  if (getline (&buf, &len, stdin) < 0)
    167 	    break;
    168 
    169 	  char *endp;
    170 	  uintmax_t addr = strtoumax (buf, &endp, 0);
    171 	  if (endp != buf)
    172 	    handle_address (addr, dwfl);
    173 	  else
    174 	    result = 1;
    175 	}
    176 
    177       free (buf);
    178     }
    179   else
    180     {
    181       do
    182 	{
    183 	  char *endp;
    184 	  uintmax_t addr = strtoumax (argv[remaining], &endp, 0);
    185 	  if (endp != argv[remaining])
    186 	    handle_address (addr, dwfl);
    187 	  else
    188 	    result = 1;
    189 	}
    190       while (++remaining < argc);
    191     }
    192 
    193   dwfl_end (dwfl);
    194 
    195   return result;
    196 }
    197