blob: 4c1e7ade6d70c5362a394337309464811f95ec31 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001#include <config.h>
2#include <assert.h>
3#include <inttypes.h>
4#include <sys/types.h>
5#include <stdio.h>
6#include <stdio_ext.h>
7#include <stdlib.h>
8#include <string.h>
9#include <error.h>
10#include <locale.h>
11#include <argp.h>
12#include <libdwfl.h>
13#include <dwarf.h>
14#include "../libdw/libdwP.h"
15#include <obstack.h>
16
17#include "loc2c.h"
18
19static const char *
20dwarf_diename_integrate (Dwarf_Die *die)
21{
22 Dwarf_Attribute attr_mem;
23 return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem));
24}
25
26
27
28static void
29handle_variable (Dwarf_Die *scopes, int nscopes, int out,
30 Dwarf_Addr cubias, Dwarf_Die *vardie, Dwarf_Addr pc,
31 char **fields)
32{
33#define obstack_chunk_alloc malloc
34#define obstack_chunk_free free
35 struct obstack pool;
36 obstack_init (&pool);
37
38 /* Figure out the appropriate frame base for accessing this variable.
39 XXX not handling nested functions
40 XXX inlines botched
41 */
42 Dwarf_Attribute fb_attr_mem, *fb_attr = NULL;
43 for (int inner = 0; inner < nscopes; ++inner)
44 {
45 switch (dwarf_tag (&scopes[inner]))
46 {
47 default:
48 continue;
49 case DW_TAG_subprogram:
50 case DW_TAG_entry_point:
51 case DW_TAG_inlined_subroutine: /* XXX */
52 if (inner >= out)
53 fb_attr = dwarf_attr_integrate (&scopes[inner],
54 DW_AT_frame_base,
55 &fb_attr_mem);
56 break;
57 }
58 break;
59 }
60
61 Dwarf_Attribute attr_mem;
62
63 if (dwarf_attr_integrate (vardie, DW_AT_location, &attr_mem) == NULL)
64 error (2, 0, _("cannot get location of variable: %s"),
65 dwarf_errmsg (-1));
66
67#define FIELD "addr"
68#define emit(fmt, ...) printf (" addr = " fmt "\n", ## __VA_ARGS__)
69
70 struct location *head, *tail = NULL;
71 head = c_translate_location (&pool, 1, cubias, &attr_mem, pc,
72 &tail, fb_attr);
73
74 if (dwarf_attr_integrate (vardie, DW_AT_type, &attr_mem) == NULL)
75 error (2, 0, _("cannot get type of variable: %s"),
76 dwarf_errmsg (-1));
77
78 Dwarf_Die die_mem, *die = vardie;
79 while (*fields != NULL)
80 {
81 die = dwarf_formref_die (&attr_mem, &die_mem);
82
83 const int typetag = dwarf_tag (die);
84 switch (typetag)
85 {
86 case DW_TAG_typedef:
87 /* Just iterate on the referent type. */
88 break;
89
90 case DW_TAG_pointer_type:
91 if (**fields == '+')
92 goto subscript;
93 /* A "" field means explicit pointer dereference and we consume it.
94 Otherwise the next field implicitly gets the dereference. */
95 if (**fields == '\0')
96 ++fields;
97 c_translate_pointer (&pool, 1, cubias, die, &tail);
98 break;
99
100 case DW_TAG_array_type:
101 if (**fields == '+')
102 {
103 subscript:;
104 char *endp = *fields + 1;
105 uintmax_t idx = strtoumax (*fields + 1, &endp, 0);
106 if (endp == NULL || endp == *fields || *endp != '\0')
107 c_translate_array (&pool, 1, cubias, die, &tail,
108 *fields + 1, 0);
109 else
110 c_translate_array (&pool, 1, cubias, die, &tail,
111 NULL, idx);
112 ++fields;
113 }
114 else
115 error (2, 0, _("bad field for array type: %s"), *fields);
116 break;
117
118 case DW_TAG_structure_type:
119 case DW_TAG_union_type:
120 switch (dwarf_child (die, &die_mem))
121 {
122 case 1: /* No children. */
123 error (2, 0, _("empty struct %s"),
124 dwarf_diename_integrate (die) ?: "<anonymous>");
125 break;
126 case -1: /* Error. */
127 default: /* Shouldn't happen */
128 error (2, 0, _("%s %s: %s"),
129 typetag == DW_TAG_union_type ? "union" : "struct",
130 dwarf_diename_integrate (die) ?: "<anonymous>",
131 dwarf_errmsg (-1));
132 break;
133
134 case 0:
135 break;
136 }
137 while (dwarf_tag (die) != DW_TAG_member
138 || ({ const char *member = dwarf_diename_integrate (die);
139 member == NULL || strcmp (member, *fields); }))
140 if (dwarf_siblingof (die, &die_mem) != 0)
141 error (2, 0, _("field name %s not found"), *fields);
142
143 if (dwarf_attr_integrate (die, DW_AT_data_member_location,
144 &attr_mem) == NULL)
145 {
146 /* Union members don't usually have a location,
147 but just use the containing union's location. */
148 if (typetag != DW_TAG_union_type)
149 error (2, 0, _("no location for field %s: %s"),
150 *fields, dwarf_errmsg (-1));
151 }
152 else
153 c_translate_location (&pool, 1, cubias, &attr_mem, pc,
154 &tail, NULL);
155 ++fields;
156 break;
157
158 case DW_TAG_base_type:
159 error (2, 0, _("field %s vs base type %s"),
160 *fields, dwarf_diename_integrate (die) ?: "<anonymous type>");
161 break;
162
163 case -1:
164 error (2, 0, _("cannot find type: %s"), dwarf_errmsg (-1));
165 break;
166
167 default:
168 error (2, 0, _("%s: unexpected type tag %#x"),
169 dwarf_diename_integrate (die) ?: "<anonymous type>",
170 dwarf_tag (die));
171 break;
172 }
173
174 /* Now iterate on the type in DIE's attribute. */
175 if (dwarf_attr_integrate (die, DW_AT_type, &attr_mem) == NULL)
176 error (2, 0, _("cannot get type of field: %s"), dwarf_errmsg (-1));
177 }
178
179 c_translate_fetch (&pool, 1, cubias, die, &attr_mem, &tail, "value");
180
181 printf ("#define PROBEADDR %#" PRIx64 "ULL\n", pc);
182 puts ("static void print_value(struct pt_regs *regs)\n"
183 "{\n"
184 " intptr_t value;");
185
186 bool deref = c_emit_location (stdout, head, 1);
187
188 puts (" printk (\" ---> %ld\\n\", (unsigned long) value);\n"
189 " return;");
190
191 if (deref)
192 puts ("\n"
193 " deref_fault:\n"
194 " printk (\" => BAD FETCH\\n\");");
195
196 puts ("}");
197}
198
199int
200main (int argc, char **argv)
201{
202 /* We use no threads here which can interfere with handling a stream. */
203 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
204
205 /* Set locale. */
206 (void) setlocale (LC_ALL, "");
207
208 Dwfl *dwfl = NULL;
209 int argi;
210 (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &argi, &dwfl);
211 assert (dwfl != NULL);
212
213 if (argi == argc)
214 error (2, 0, "need address argument");
215
216 char *endp;
217 uintmax_t pc = strtoumax (argv[argi], &endp, 0);
218 if (endp == argv[argi])
219 error (2, 0, "bad address argument");
220
221 Dwarf_Addr cubias;
222 Dwarf_Die *cudie = dwfl_addrdie (dwfl, pc, &cubias);
223 if (cudie == NULL)
224 error (EXIT_FAILURE, 0, "dwfl_addrdie: %s", dwfl_errmsg (-1));
225
226 Dwarf_Die *scopes;
227 int n = dwarf_getscopes (cudie, pc - cubias, &scopes);
228 if (n < 0)
229 error (EXIT_FAILURE, 0, "dwarf_getscopes: %s", dwarf_errmsg (-1));
230 else if (n == 0)
231 error (EXIT_FAILURE, 0, "%#" PRIx64 ": not in any scope\n", pc);
232
233 if (++argi == argc)
234 error (2, 0, "need variable arguments");
235
236 char *spec = argv[argi++];
237
238 int lineno = 0, colno = 0, shadow = 0;
239 char *at = strchr (spec, '@');
240 if (at != NULL)
241 {
242 *at++ = '\0';
243 if (sscanf (at, "%*[^:]:%i:%i", &lineno, &colno) < 1)
244 lineno = 0;
245 }
246 else
247 {
248 int len;
249 if (sscanf (spec, "%*[^+]%n+%i", &len, &shadow) == 2)
250 spec[len] = '\0';
251 }
252
253 Dwarf_Die vardie;
254 int out = dwarf_getscopevar (scopes, n, spec, shadow, at, lineno, colno,
255 &vardie);
256 if (out == -2)
257 error (0, 0, "no match for %s (+%d, %s:%d:%d)",
258 spec, shadow, at, lineno, colno);
259 else if (out < 0)
260 error (0, 0, "dwarf_getscopevar: %s (+%d, %s:%d:%d): %s",
261 spec, shadow, at, lineno, colno, dwarf_errmsg (-1));
262 else
263 handle_variable (scopes, n, out, cubias, &vardie, pc, &argv[argi]);
264
265 dwfl_end (dwfl);
266
267 return 0;
268}