1/* Test program for libdwfl basic module tracking, relocation.
2   Copyright (C) 2005, 2007 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 <sys/types.h>
22#include <stdio.h>
23#include <stdio_ext.h>
24#include <stdlib.h>
25#include <string.h>
26#include <error.h>
27#include <locale.h>
28#include <argp.h>
29#include ELFUTILS_HEADER(dwfl)
30#include <dwarf.h>
31
32static bool show_inlines;
33
34struct info
35{
36  Dwarf_Die *cudie;
37  Dwarf_Addr dwbias;
38};
39
40static int
41print_instance (Dwarf_Die *instance, void *arg)
42{
43  const struct info *info = arg;
44
45  printf ("    inlined");
46
47  Dwarf_Files *files;
48  if (dwarf_getsrcfiles (info->cudie, &files, NULL) == 0)
49    {
50      Dwarf_Attribute attr_mem;
51      Dwarf_Word val;
52      if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_file,
53				       &attr_mem), &val) == 0)
54	{
55	  const char *file = dwarf_filesrc (files, val, NULL, NULL);
56	  int lineno = 0, colno = 0;
57	  if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_line,
58					   &attr_mem), &val) == 0)
59	    lineno = val;
60	  if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_column,
61					   &attr_mem), &val) == 0)
62	    colno = val;
63	  if (lineno == 0)
64	    {
65	      if (file != NULL)
66		printf (" from %s", file);
67	    }
68	  else if (colno == 0)
69	    printf (" at %s:%u", file, lineno);
70	  else
71	    printf (" at %s:%u:%u", file, lineno, colno);
72	}
73    }
74
75  Dwarf_Addr lo = -1, hi = -1, entry = -1;
76  if (dwarf_lowpc (instance, &lo) == 0)
77    lo += info->dwbias;
78  else
79    printf (" (lowpc => %s)", dwarf_errmsg (-1));
80  if (dwarf_highpc (instance, &hi) == 0)
81    hi += info->dwbias;
82  else
83    printf (" (highpc => %s)", dwarf_errmsg (-1));
84
85  Dwarf_Attribute attr_mem;
86  Dwarf_Attribute *attr = dwarf_attr (instance, DW_AT_entry_pc, &attr_mem);
87  if (attr != NULL)
88    {
89      if (dwarf_formaddr (attr, &entry) == 0)
90	entry += info->dwbias;
91      else
92	printf (" (entrypc => %s)", dwarf_errmsg (-1));
93    }
94
95  if (lo != (Dwarf_Addr) -1 || hi != (Dwarf_Addr) -1)
96    printf (" %#" PRIx64 "..%#" PRIx64, lo, hi);
97  if (entry != (Dwarf_Addr) -1)
98    printf (" => %#" PRIx64 "\n", entry);
99  else
100    puts ("");
101
102  return DWARF_CB_OK;
103}
104
105static void
106print_inline (Dwarf_Die *func, void *arg)
107{
108  if (dwarf_func_inline_instances (func, &print_instance, arg) != 0)
109    printf ("  error finding instances: %s\n", dwarf_errmsg (-1));
110}
111
112static int
113print_func (Dwarf_Die *func, void *arg)
114{
115  const struct info *info = arg;
116
117  const char *file = dwarf_decl_file (func);
118  int line = -1;
119  dwarf_decl_line (func, &line);
120  const char *fct = dwarf_diename (func);
121
122  printf ("  %s:%d: %s:", file, line, fct);
123
124  if (dwarf_func_inline (func))
125    {
126      puts (" inline function");
127      if (show_inlines)
128	print_inline (func, arg);
129    }
130  else
131    {
132      Dwarf_Addr lo = -1, hi = -1, entry = -1;
133      if (dwarf_lowpc (func, &lo) == 0)
134	lo += info->dwbias;
135      else
136	printf (" (lowpc => %s)", dwarf_errmsg (-1));
137      if (dwarf_highpc (func, &hi) == 0)
138	hi += info->dwbias;
139      else
140	printf (" (highpc => %s)", dwarf_errmsg (-1));
141      if (dwarf_entrypc (func, &entry) == 0)
142	entry += info->dwbias;
143      else
144	printf (" (entrypc => %s)", dwarf_errmsg (-1));
145
146      if (lo != (Dwarf_Addr) -1 || hi != (Dwarf_Addr) -1
147	  || entry != (Dwarf_Addr) -1)
148	printf (" %#" PRIx64 "..%#" PRIx64 " => %#" PRIx64 "\n",
149		lo, hi, entry);
150      else
151	puts ("");
152    }
153
154  return DWARF_CB_OK;
155}
156
157static int
158list_module (Dwfl_Module *mod __attribute__ ((unused)),
159	     void **userdata __attribute__ ((unused)),
160	     const char *name, Dwarf_Addr base,
161	     void *arg __attribute__ ((unused)))
162{
163  Dwarf_Addr start;
164  Dwarf_Addr end;
165  const char *file;
166  const char *debug;
167  if (dwfl_module_info (mod, NULL, &start, &end,
168			NULL, NULL, &file, &debug) != name
169      || start != base)
170    abort ();
171  printf ("module: %30s %08" PRIx64 "..%08" PRIx64 " %s %s\n",
172	  name, start, end, file, debug);
173  return DWARF_CB_OK;
174}
175
176static int
177print_module (Dwfl_Module *mod __attribute__ ((unused)),
178	      void **userdata __attribute__ ((unused)),
179	      const char *name, Dwarf_Addr base,
180	      Dwarf *dw, Dwarf_Addr bias,
181	      void *arg)
182{
183  printf ("module: %30s %08" PRIx64 " %s %" PRIx64 " (%s)\n",
184	  name, base, dw == NULL ? "no" : "DWARF", bias, dwfl_errmsg (-1));
185
186  if (dw != NULL && *(const bool *) arg)
187    {
188      Dwarf_Off off = 0;
189      size_t cuhl;
190      Dwarf_Off noff;
191
192      while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0)
193	{
194	  Dwarf_Die die_mem;
195	  struct info info = { dwarf_offdie (dw, off + cuhl, &die_mem), bias };
196	  (void) dwarf_getfuncs (info.cudie, print_func, &info, 0);
197
198	  off = noff;
199	}
200    }
201
202  return DWARF_CB_OK;
203}
204
205static bool show_functions;
206
207/* gettext helper macro.  */
208#undef	N_
209#define N_(Str) Str
210
211static const struct argp_option options[] =
212  {
213    { "functions", 'f', NULL, 0, N_("Additionally show function names"), 0 },
214    { "inlines", 'i', NULL, 0, N_("Show instances of inlined functions"), 0 },
215    { NULL, 0, NULL, 0, NULL, 0 }
216  };
217
218static error_t
219parse_opt (int key, char *arg __attribute__ ((unused)),
220	   struct argp_state *state __attribute__ ((unused)))
221{
222  switch (key)
223    {
224    case ARGP_KEY_INIT:
225      state->child_inputs[0] = state->input;
226      break;
227
228    case 'f':
229      show_functions = true;
230      break;
231
232    case 'i':
233      show_inlines = show_functions = true;
234      break;
235
236    default:
237      return ARGP_ERR_UNKNOWN;
238    }
239  return 0;
240}
241
242int
243main (int argc, char **argv)
244{
245  /* We use no threads here which can interfere with handling a stream.  */
246  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
247
248  /* Set locale.  */
249  (void) setlocale (LC_ALL, "");
250
251  Dwfl *dwfl = NULL;
252  const struct argp_child argp_children[] =
253    {
254      { .argp = dwfl_standard_argp () },
255      { .argp = NULL }
256    };
257  const struct argp argp =
258    {
259      options, parse_opt, NULL, NULL, argp_children, NULL, NULL
260    };
261  (void) argp_parse (&argp, argc, argv, 0, NULL, &dwfl);
262  assert (dwfl != NULL);
263
264  ptrdiff_t p = 0;
265  do
266    p = dwfl_getmodules (dwfl, &list_module, NULL, p);
267  while (p > 0);
268  if (p < 0)
269    error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
270
271  do
272    p = dwfl_getdwarf (dwfl, &print_module, &show_functions, p);
273  while (p > 0);
274  if (p < 0)
275    error (2, 0, "dwfl_getdwarf: %s", dwfl_errmsg (-1));
276
277  p = 0;
278  do
279    p = dwfl_getmodules (dwfl, &list_module, NULL, p);
280  while (p > 0);
281  if (p < 0)
282    error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
283
284  dwfl_end (dwfl);
285
286  return 0;
287}
288