]> sourceware.org Git - systemtap.git/blob - loc2c-test.c
Consolidate task_finder/vma tracker initialization.
[systemtap.git] / loc2c-test.c
1 /* Simple test program for loc2c code. */
2
3 #include <config.h>
4 #include <assert.h>
5 #include <inttypes.h>
6 #include <sys/types.h>
7 #include <stdio.h>
8 #include <stdio_ext.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <error.h>
12 #include <locale.h>
13 #include <argp.h>
14 #include <elfutils/libdwfl.h>
15 #ifdef HAVE_ELFUTILS_VERSION_H
16 #include <elfutils/version.h>
17 #endif
18 #include <dwarf.h>
19 #include <obstack.h>
20 #include <unistd.h>
21 #include <stdarg.h>
22 #include "loc2c.h"
23
24 #if !defined(_ELFUTILS_PREREQ)
25 // make a dummy PREREQ check for elfutils < 0.138
26 #define _ELFUTILS_PREREQ(major, minor) (0 >= 1)
27 #endif
28
29 #define _(msg) msg
30
31 static void __attribute__ ((noreturn))
32 fail (void *arg __attribute__ ((unused)), const char *fmt, ...)
33 {
34 va_list ap;
35
36 fprintf (stderr, "%s: ", program_invocation_short_name);
37
38 va_start (ap, fmt);
39 vfprintf (stderr, _(fmt), ap);
40 va_end (ap);
41
42 fprintf (stderr, "\n");
43
44 exit (2);
45 }
46
47 static const Dwarf_Op *
48 get_location (Dwarf_Addr dwbias, Dwarf_Addr pc, Dwarf_Attribute *loc_attr,
49 size_t *len)
50 {
51 Dwarf_Op *expr;
52
53 switch (dwarf_getlocation_addr (loc_attr, pc - dwbias, &expr, len, 1))
54 {
55 case 1: /* Should always happen. */
56 if (*len == 0)
57 goto inaccessible;
58 break;
59
60 default: /* Shouldn't happen. */
61 case -1:
62 fail (NULL, _("dwarf_getlocation_addr (form %#x): %s"),
63 dwarf_whatform (loc_attr), dwarf_errmsg (-1));
64 return NULL;
65
66 case 0: /* Shouldn't happen. */
67 inaccessible:
68 fail (NULL, _("not accessible at this address"));
69 return NULL;
70 }
71
72 return expr;
73 }
74
75 static void
76 handle_variable (Dwarf_Die *lscopes, int lnscopes, int out,
77 Dwarf_Addr cubias, Dwarf_Die *vardie, Dwarf_Addr pc,
78 Dwarf_Op *cfa_ops, char **fields)
79 {
80 #define obstack_chunk_alloc malloc
81 #define obstack_chunk_free free
82 struct obstack pool;
83 obstack_init (&pool);
84
85 /* Figure out the appropriate frame base for accessing this variable.
86 * XXX not handling nested functions
87 */
88 Dwarf_Attribute fb_attr_mem, *fb_attr = NULL;
89 int inner;
90 /* We start out walking the "lexical scopes" as returned by
91 * as returned by dwarf_getscopes for the address, starting with the
92 * 'out' scope that the variable was found in.
93 */
94 Dwarf_Die *scopes = lscopes;
95 int nscopes = lnscopes;
96 for (inner = out; inner < nscopes && fb_attr == NULL; ++inner)
97 {
98 switch (dwarf_tag (&scopes[inner]))
99 {
100 default:
101 continue;
102 case DW_TAG_subprogram:
103 case DW_TAG_entry_point:
104 fb_attr = dwarf_attr_integrate (&scopes[inner],
105 DW_AT_frame_base,
106 &fb_attr_mem);
107 break;
108 case DW_TAG_inlined_subroutine:
109 /* Unless we already are going through the "pyshical die tree",
110 * we now need to start walking the die tree where this
111 * subroutine is inlined to find the appropriate frame base. */
112 if (out != -1)
113 {
114 nscopes = dwarf_getscopes_die (&scopes[inner], &scopes);
115 if (nscopes == -1)
116 error (2, 0, _("cannot get die scopes inlined_subroutine: %s"),
117 dwarf_errmsg (-1));
118 inner = 0; // zero is current scope, for look will increase.
119 out = -1;
120 }
121 break;
122 }
123 }
124
125 struct location *head, *tail = NULL;
126
127 Dwarf_Attribute attr_mem;
128 if (dwarf_attr_integrate (vardie, DW_AT_const_value, &attr_mem) != NULL)
129 /* There is no location expression, but a constant value instead. */
130 head = tail = c_translate_constant (&pool, &fail, NULL, NULL,
131 1, cubias, &attr_mem);
132 else
133 {
134
135 if (dwarf_attr_integrate (vardie, DW_AT_location, &attr_mem) == NULL)
136 error (2, 0, _("cannot get location of variable: %s"),
137 dwarf_errmsg (-1));
138
139 size_t locexpr_len;
140 const Dwarf_Op *locexpr = get_location (cubias, pc,
141 &attr_mem, &locexpr_len);
142
143 head = c_translate_location (&pool, &fail, NULL, NULL,
144 1, cubias, pc, &attr_mem,
145 locexpr, locexpr_len,
146 &tail, fb_attr, cfa_ops);
147 }
148
149 if (dwarf_attr_integrate (vardie, DW_AT_type, &attr_mem) == NULL)
150 error (2, 0, _("cannot get type of variable: %s"),
151 dwarf_errmsg (-1));
152
153 bool store = false;
154 Dwarf_Die die_mem, *die = vardie;
155 while (*fields != NULL)
156 {
157 if (!strcmp (*fields, "="))
158 {
159 store = true;
160 if (fields[1] != NULL)
161 error (2, 0, _("extra fields after ="));
162 break;
163 }
164
165 die = dwarf_formref_die (&attr_mem, &die_mem);
166
167 const int typetag = dwarf_tag (die);
168 switch (typetag)
169 {
170 case DW_TAG_typedef:
171 case DW_TAG_const_type:
172 case DW_TAG_volatile_type:
173 /* Just iterate on the referent type. */
174 break;
175
176 case DW_TAG_pointer_type:
177 if (**fields == '+')
178 goto subscript;
179 /* A "" field means explicit pointer dereference and we consume it.
180 Otherwise the next field implicitly gets the dereference. */
181 if (**fields == '\0')
182 ++fields;
183 c_translate_pointer (&pool, 1, cubias, die, &tail);
184 break;
185
186 case DW_TAG_array_type:
187 if (**fields == '+')
188 {
189 subscript:;
190 char *endp = *fields + 1;
191 uintmax_t idx = strtoumax (*fields + 1, &endp, 0);
192 if (endp == NULL || endp == *fields || *endp != '\0')
193 c_translate_array (&pool, 1, cubias, die, &tail,
194 *fields + 1, 0);
195 else
196 c_translate_array (&pool, 1, cubias, die, &tail,
197 NULL, idx);
198 ++fields;
199 }
200 else
201 error (2, 0, _("bad field for array type: %s"), *fields);
202 break;
203
204 case DW_TAG_structure_type:
205 case DW_TAG_union_type:
206 switch (dwarf_child (die, &die_mem))
207 {
208 case 1: /* No children. */
209 error (2, 0, _("empty struct %s"),
210 dwarf_diename (die) ?: "<anonymous>");
211 break;
212 case -1: /* Error. */
213 default: /* Shouldn't happen */
214 error (2, 0, _("%s %s: %s"),
215 typetag == DW_TAG_union_type ? "union" : "struct",
216 dwarf_diename (die) ?: "<anonymous>",
217 dwarf_errmsg (-1));
218 break;
219
220 case 0:
221 break;
222 }
223 while (dwarf_tag (die) != DW_TAG_member
224 || ({ const char *member = dwarf_diename (die);
225 member == NULL || strcmp (member, *fields); }))
226 if (dwarf_siblingof (die, &die_mem) != 0)
227 error (2, 0, _("field name %s not found"), *fields);
228
229 if (dwarf_attr_integrate (die, DW_AT_data_member_location,
230 &attr_mem) == NULL)
231 {
232 /* Union members don't usually have a location,
233 but just use the containing union's location. */
234 if (typetag != DW_TAG_union_type)
235 error (2, 0, _("no location for field %s: %s"),
236 *fields, dwarf_errmsg (-1));
237 }
238 else
239 {
240 /* We expect a block or a constant. In older elfutils,
241 dwarf_getlocation_addr would not handle the constant for
242 us, but newer ones do. For older ones, we work around
243 it by faking an expression, which is what newer ones do. */
244 #if !_ELFUTILS_PREREQ (0,142)
245 Dwarf_Op offset_loc = { .atom = DW_OP_plus_uconst };
246 if (dwarf_formudata (&attr_mem, &offset_loc.number) == 0)
247 c_translate_location (&pool, NULL, NULL, NULL,
248 1, cubias, pc, &attr_mem,
249 &offset_loc, 1,
250 &tail, NULL, NULL);
251 else
252 #endif
253 {
254 size_t locexpr_len;
255 const Dwarf_Op *locexpr = get_location (cubias, pc, &attr_mem,
256 &locexpr_len);
257 c_translate_location (&pool, NULL, NULL, NULL,
258 1, cubias, pc, &attr_mem,
259 locexpr, locexpr_len,
260 &tail, NULL, NULL);
261 }
262 }
263 ++fields;
264 break;
265
266 case DW_TAG_base_type:
267 error (2, 0, _("field %s vs base type %s"),
268 *fields, dwarf_diename (die) ?: "<anonymous type>");
269 break;
270
271 case -1:
272 error (2, 0, _("cannot find type: %s"), dwarf_errmsg (-1));
273 break;
274
275 default:
276 error (2, 0, _("%s: unexpected type tag %#x"),
277 dwarf_diename (die) ?: "<anonymous type>",
278 dwarf_tag (die));
279 break;
280 }
281
282 /* Now iterate on the type in DIE's attribute. */
283 if (dwarf_attr_integrate (die, DW_AT_type, &attr_mem) == NULL)
284 error (2, 0, _("cannot get type of field: %s"), dwarf_errmsg (-1));
285 }
286
287 /* Fetch the type DIE corresponding to the final location to be accessed.
288 It must be a base type or a typedef for one. */
289
290 Dwarf_Die typedie_mem;
291 Dwarf_Die *typedie;
292 int typetag;
293 while (1)
294 {
295 typedie = dwarf_formref_die (&attr_mem, &typedie_mem);
296 if (typedie == NULL)
297 error (2, 0, _("cannot get type of field: %s"), dwarf_errmsg (-1));
298 typetag = dwarf_tag (typedie);
299 if (typetag != DW_TAG_typedef &&
300 typetag != DW_TAG_const_type &&
301 typetag != DW_TAG_volatile_type)
302 break;
303 if (dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem) == NULL)
304 error (2, 0, _("cannot get type of field: %s"), dwarf_errmsg (-1));
305 }
306
307 switch (typetag)
308 {
309 case DW_TAG_base_type:
310 if (store)
311 c_translate_store (&pool, 1, cubias, die, typedie, &tail, "value");
312 else
313 c_translate_fetch (&pool, 1, cubias, die, typedie, &tail, "value");
314 break;
315
316 case DW_TAG_pointer_type:
317 case DW_TAG_reference_type:
318 if (store)
319 error (2, 0, _("store not supported for pointer type"));
320 c_translate_pointer (&pool, 1, cubias, typedie, &tail);
321 c_translate_addressof (&pool, 1, cubias, die, typedie, &tail, "value");
322 break;
323
324 default:
325 if (store)
326 error (2, 0, _("store supported only for base type"));
327 else
328 error (2, 0, _("fetch supported only for base type or pointer"));
329 break;
330 }
331
332 printf ("#define PROBEADDR %#" PRIx64 "ULL\n", pc);
333
334 puts (store
335 ? "static void set_value(struct pt_regs *regs, intptr_t value)\n{"
336 : "static void print_value(struct pt_regs *regs)\n"
337 "{\n"
338 " intptr_t value;");
339
340 unsigned int stack_depth;
341 bool deref = c_emit_location (stdout, head, 1, &stack_depth);
342
343 obstack_free (&pool, NULL);
344
345 printf (" /* max expression stack depth %u */\n", stack_depth);
346
347 puts (store ? " return;" :
348 " printk (\" ---> %ld\\n\", (unsigned long) value);\n"
349 " return;");
350
351 if (deref)
352 puts ("\n"
353 " deref_fault:\n"
354 " printk (\" => BAD ACCESS\\n\");");
355
356 puts ("}");
357 }
358
359 static void
360 paddr (const char *prefix, Dwarf_Addr addr, Dwfl_Line *line)
361 {
362 const char *src;
363 int lineno, linecol;
364 if (line != NULL
365 && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
366 NULL, NULL)) != NULL)
367 {
368 if (linecol != 0)
369 printf ("%s%#" PRIx64 " (%s:%d:%d)",
370 prefix, addr, src, lineno, linecol);
371 else
372 printf ("%s%#" PRIx64 " (%s:%d)",
373 prefix, addr, src, lineno);
374 }
375 else
376 printf ("%s%#" PRIx64, prefix, addr);
377 }
378
379 static void
380 print_type (Dwarf_Die *typedie, char space)
381 {
382 if (typedie == NULL)
383 printf ("%c<no type>", space);
384 else
385 {
386 const char *name = dwarf_diename (typedie);
387 if (name != NULL)
388 printf ("%c%s", space, name);
389 else
390 {
391 Dwarf_Attribute attr_mem;
392 Dwarf_Die die_mem;
393 Dwarf_Die *die = dwarf_formref_die
394 (dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem), &die_mem);
395 int tag = dwarf_tag (typedie);
396 switch (tag)
397 {
398 case DW_TAG_pointer_type:
399 print_type (die, space);
400 putchar ('*');
401 break;
402 case DW_TAG_array_type:
403 print_type (die, space);
404 printf ("[]");
405 break;
406 case DW_TAG_const_type:
407 print_type (die, space);
408 printf (" const");
409 break;
410 case DW_TAG_volatile_type:
411 print_type (die, space);
412 printf (" volatile");
413 break;
414 default:
415 printf ("%c<unknown %#x>", space, tag);
416 break;
417 }
418 }
419 }
420 }
421
422 static void
423 print_vars (unsigned int indent, Dwarf_Die *die)
424 {
425 Dwarf_Die child;
426 Dwarf_Attribute attr_mem;
427 Dwarf_Die typedie_mem;
428 Dwarf_Die *typedie;
429 if (dwarf_child (die, &child) == 0)
430 do
431 switch (dwarf_tag (&child))
432 {
433 case DW_TAG_variable:
434 case DW_TAG_formal_parameter:
435 printf ("%*s%-30s[%6" PRIx64 "]", indent, "",
436 dwarf_diename (&child),
437 (uint64_t) dwarf_dieoffset (&child));
438 typedie = dwarf_formref_die
439 (dwarf_attr_integrate (&child, DW_AT_type, &attr_mem),
440 &typedie_mem);
441 print_type (typedie, '\t');
442 puts ("");
443 break;
444 default:
445 break;
446 }
447 while (dwarf_siblingof (&child, &child) == 0);
448 }
449
450 #define INDENT 4
451
452 int
453 main (int argc, char **argv)
454 {
455 /* We use no threads here which can interfere with handling a stream. */
456 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
457
458 /* Set locale. */
459 (void) setlocale (LC_ALL, "");
460
461 Dwfl *dwfl = NULL;
462 int argi;
463 (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &argi, &dwfl);
464 assert (dwfl != NULL);
465
466 if (argi == argc)
467 error (2, 0, "need address argument");
468
469 char *endp;
470 uintmax_t pc = strtoumax (argv[argi], &endp, 0);
471 if (endp == argv[argi])
472 error (2, 0, "bad address argument");
473
474 Dwarf_Addr cubias;
475 Dwarf_Die *cudie = dwfl_addrdie (dwfl, pc, &cubias);
476 if (cudie == NULL)
477 error (EXIT_FAILURE, 0, "dwfl_addrdie: %s", dwfl_errmsg (-1));
478
479 Dwarf_Die *scopes;
480 int n = dwarf_getscopes (cudie, pc - cubias, &scopes);
481 if (n < 0)
482 error (EXIT_FAILURE, 0, "dwarf_getscopes: %s", dwarf_errmsg (-1));
483 else if (n == 0)
484 error (EXIT_FAILURE, 0, "%#" PRIx64 ": not in any scope\n", pc);
485
486 if (++argi == argc)
487 {
488 unsigned int indent = 0;
489 while (n-- > 0)
490 {
491 Dwarf_Die *const die = &scopes[n];
492
493 indent += INDENT;
494 printf ("%*s[%6" PRIx64 "] %s (%#x)", indent, "",
495 dwarf_dieoffset (die),
496 dwarf_diename (die) ?: "<unnamed>",
497 dwarf_tag (die));
498
499 Dwarf_Addr lowpc, highpc;
500 if (dwarf_lowpc (die, &lowpc) == 0
501 && dwarf_highpc (die, &highpc) == 0)
502 {
503 lowpc += cubias;
504 highpc += cubias;
505 Dwfl_Line *loline = dwfl_getsrc (dwfl, lowpc);
506 Dwfl_Line *hiline = dwfl_getsrc (dwfl, highpc);
507 paddr (": ", lowpc, loline);
508 if (highpc != lowpc)
509 paddr (" .. ", lowpc, hiline == loline ? NULL : hiline);
510 }
511 puts ("");
512
513 print_vars (indent + INDENT, die);
514 }
515 }
516 else
517 {
518 char *spec = argv[argi++];
519
520 int lineno = 0, colno = 0, shadow = 0;
521 char *at = strchr (spec, '@');
522 if (at != NULL)
523 {
524 *at++ = '\0';
525 if (sscanf (at, "%*[^:]:%i:%i", &lineno, &colno) < 1)
526 lineno = 0;
527 }
528 else
529 {
530 int len;
531 if (sscanf (spec, "%*[^+]%n+%i", &len, &shadow) == 2)
532 spec[len] = '\0';
533 }
534
535 Dwarf_Die vardie;
536 int out = dwarf_getscopevar (scopes, n, spec, shadow, at, lineno, colno,
537 &vardie);
538 if (out == -2)
539 error (0, 0, "no match for %s (+%d, %s:%d:%d)",
540 spec, shadow, at, lineno, colno);
541 else if (out < 0)
542 error (0, 0, "dwarf_getscopevar: %s (+%d, %s:%d:%d): %s",
543 spec, shadow, at, lineno, colno, dwarf_errmsg (-1));
544 else
545 {
546 Dwarf_Op *cfa_ops = NULL;
547
548 #if _ELFUTILS_PREREQ(0,142)
549 size_t cfa_nops;
550 Dwarf_Addr bias;
551 Dwfl_Module *module = dwfl_addrmodule (dwfl, pc);
552 if (module != NULL)
553 {
554 // Try debug_frame first, then fall back on eh_frame.
555 Dwarf_CFI *cfi = dwfl_module_dwarf_cfi (module, &bias);
556 if (cfi != NULL)
557 {
558 Dwarf_Frame *frame = NULL;
559 if (dwarf_cfi_addrframe (cfi, pc - bias, &frame) == 0)
560 dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops);
561 }
562 if (cfa_ops == NULL)
563 {
564 cfi = dwfl_module_eh_cfi (module, &bias);
565 if (cfi != NULL)
566 {
567 Dwarf_Frame *frame = NULL;
568 if (dwarf_cfi_addrframe (cfi, pc - bias, &frame) == 0)
569 dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops);
570 }
571 }
572 }
573 #endif
574
575 handle_variable (scopes, n, out, cubias, &vardie, pc, cfa_ops,
576 &argv[argi]);
577 }
578 }
579
580 free (scopes);
581
582 dwfl_end (dwfl);
583
584 return 0;
585 }
586
587 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.08652 seconds and 5 git commands to generate.