1 /* Test program for dwarf_lowpc and dwarf_highpc
2    Copyright (C) 2012, 2018 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 <string.h>
29 #include <fnmatch.h>
30 
31 struct args
32 {
33   Dwfl *dwfl;
34   Dwarf_Die *cu;
35   Dwarf_Addr dwbias;
36   char **argv;
37   const char *file;
38 };
39 
40 static struct args *args;
41 
42 static void
fail(Dwarf_Off off,const char * name,const char * msg)43 fail(Dwarf_Off off, const char *name, const char *msg)
44 {
45   printf("%s: [%" PRIx64 "] '%s' %s\n", args->file, off, name, msg);
46   exit(-1);
47 }
48 
49 static int
handle_die(Dwarf_Die * die,void * arg)50 handle_die (Dwarf_Die *die, void *arg)
51 {
52   args = arg;
53   Dwarf_Off off = dwarf_dieoffset (die);
54 
55   const char *name = dwarf_diename (die);
56   if (name == NULL)
57     name = "<no name>";
58 
59   printf ("[%" PRIx64 "] %s\n", off, name);
60 
61   Dwarf_Addr lowpc = 0;
62   Dwarf_Addr highpc = 0;
63   if (dwarf_lowpc (die, &lowpc) != 0 && dwarf_hasattr (die, DW_AT_low_pc))
64     fail (off, name, "has DW_AT_low_pc but dwarf_lowpc fails");
65   if (dwarf_highpc (die, &highpc) != 0 && dwarf_hasattr (die, DW_AT_high_pc))
66     fail (off, name, "has DW_AT_high_pc but dwarf_highpc fails");
67 
68   /* GCC < 4.7 had a bug where no code CUs got a highpc == lowpc.
69      Allow that, because it is not the main purpose of this test.  */
70   if (dwarf_hasattr (die, DW_AT_low_pc)
71       && dwarf_hasattr (die, DW_AT_high_pc)
72       && highpc <= lowpc
73       && ! (dwarf_tag (die) == DW_TAG_compile_unit && highpc == lowpc))
74     {
75       printf("lowpc: %" PRIx64 ", highpc: %" PRIx64 "lx\n", lowpc, highpc);
76       fail (off, name, "highpc <= lowpc");
77     }
78 
79   return 0;
80 }
81 
82 
83 int
main(int argc,char * argv[])84 main (int argc, char *argv[])
85 {
86   int remaining;
87 
88   /* Set locale.  */
89   (void) setlocale (LC_ALL, "");
90 
91   struct args a = { .dwfl = NULL, .cu = NULL };
92 
93   (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining,
94 		     &a.dwfl);
95   assert (a.dwfl != NULL);
96   a.argv = &argv[remaining];
97 
98   int result = 0;
99 
100   while ((a.cu = dwfl_nextcu (a.dwfl, a.cu, &a.dwbias)) != NULL)
101     {
102       a.file = dwarf_diename (a.cu);
103       handle_die (a.cu, &a);
104       dwarf_getfuncs (a.cu, &handle_die, &a, 0);
105 
106       uint8_t unit_type;
107       Dwarf_Die subdie;
108       if (dwarf_cu_info (a.cu->cu, NULL, &unit_type, NULL, &subdie,
109 			 NULL, NULL, NULL) != 0)
110 	{
111 	  Dwarf_Off off = dwarf_dieoffset (a.cu);
112 	  fail (off, "dwarf_cu_info", dwarf_errmsg (-1));
113 	}
114 
115       if (unit_type == DW_UT_skeleton)
116 	{
117 	  const char *name = dwarf_diename (&subdie) ?: "<unknown>";
118 	  printf ("Following split subdie: %s\n", name);
119 	  struct args b = a;
120 	  b.cu = &subdie;
121 	  handle_die (b.cu, &b);
122 	  dwarf_getfuncs (b.cu, &handle_die, &b, 0);
123 	  printf ("Done subdie: %s\n", name);
124 	}
125     }
126 
127   dwfl_end (a.dwfl);
128 
129   printf ("\n");
130 
131   return result;
132 }
133