aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-02-25 08:35:42 -0500
committerIngo Molnar <mingo@elte.hu>2010-02-25 11:49:29 -0500
commit804b36068eccd8163ccea420c662fb5d1a21b141 (patch)
tree08837b6d7be24d56c30af2932e59fa1c23420396 /tools/perf/util/probe-finder.c
parent81cb8aa327b5923b38eccc795c8b7170be20b9ff (diff)
perf probe: Use elfutils-libdw for analyzing debuginfo
Newer gcc introduces newer & richer debuginfo, and only libdw in elfutils project can support it. So perf probe moves onto elfutils-libdw from libdwarf. Changes in v3: - Cast Dwarf_Addr/Dwarf_Word to uintmax_t for printf-formats. - Recover a sign-prefix which was removed in v2 by mistake. Changes in v2: - Fix a type-casting bug in Makefile. - Cast Dwarf_Addr/Dwarf_Word to unsigned long long for printf-formats. Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Cc: systemtap <systemtap@sources.redhat.com> Cc: DLE <dle-develop@lists.sourceforge.net> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> Cc: K.Prasad <prasad@linux.vnet.ibm.com> Cc: Ulrich Drepper <drepper@redhat.com> Cc: Roland McGrath <roland@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> LKML-Reference: <20100225133542.6725.34724.stgit@localhost6.localdomain6> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r--tools/perf/util/probe-finder.c696
1 files changed, 274 insertions, 422 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c819fd59da9e..c422472fe4d1 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -44,8 +44,6 @@ struct die_link {
44 Dwarf_Die die; /* Current die */ 44 Dwarf_Die die; /* Current die */
45}; 45};
46 46
47static Dwarf_Debug __dw_debug;
48static Dwarf_Error __dw_error;
49 47
50/* 48/*
51 * Generic dwarf analysis helpers 49 * Generic dwarf analysis helpers
@@ -114,157 +112,114 @@ static int strtailcmp(const char *s1, const char *s2)
114} 112}
115 113
116/* Find the fileno of the target file. */ 114/* Find the fileno of the target file. */
117static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname) 115static int cu_find_fileno(Dwarf_Die *cu_die, const char *fname)
118{ 116{
119 Dwarf_Signed cnt, i; 117 Dwarf_Files *files;
120 Dwarf_Unsigned found = 0; 118 size_t nfiles, i;
121 char **srcs; 119 const char *src;
122 int ret; 120 int ret;
123 121
124 if (!fname) 122 if (!fname)
125 return 0; 123 return -EINVAL;
126 124
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 125 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
128 if (ret == DW_DLV_OK) { 126 if (ret == 0) {
129 for (i = 0; i < cnt && !found; i++) { 127 for (i = 0; i < nfiles; i++) {
130 if (strtailcmp(srcs[i], fname) == 0) 128 src = dwarf_filesrc(files, i, NULL, NULL);
131 found = i + 1; 129 if (strtailcmp(src, fname) == 0) {
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 130 ret = (int)i; /*???: +1 or not?*/
131 break;
132 }
133 } 133 }
134 for (; i < cnt; i++) 134 if (ret)
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 135 pr_debug("found fno: %d\n", ret);
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
137 } 136 }
138 if (found) 137 return ret;
139 pr_debug("found fno: %d\n", (int)found);
140 return found;
141} 138}
142 139
143static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf) 140struct __addr_die_search_param {
141 Dwarf_Addr addr;
142 Dwarf_Die *die_mem;
143};
144
145static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
144{ 146{
145 Dwarf_Signed cnt, i; 147 struct __addr_die_search_param *ad = data;
146 char **srcs;
147 int ret = 0;
148 148
149 if (!buf || !fno) 149 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
150 return -EINVAL; 150 dwarf_haspc(fn_die, ad->addr)) {
151 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
152 return DWARF_CB_ABORT;
153 }
154 return DWARF_CB_OK;
155}
151 156
152 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 157/* Search a real subprogram including this line, */
153 if (ret == DW_DLV_OK) { 158static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
154 if ((Dwarf_Unsigned)cnt > fno - 1) { 159 Dwarf_Die *die_mem)
155 *buf = strdup(srcs[fno - 1]); 160{
156 ret = 0; 161 struct __addr_die_search_param ad;
157 pr_debug("found filename: %s\n", *buf); 162 ad.addr = addr;
158 } else 163 ad.die_mem = die_mem;
159 ret = -ENOENT; 164 /* dwarf_getscopes can't find subprogram. */
160 for (i = 0; i < cnt; i++) 165 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
161 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 166 return NULL;
162 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST); 167 else
163 } else 168 return die_mem;
164 ret = -EINVAL;
165 return ret;
166} 169}
167 170
168/* Compare diename and tname */ 171/* Compare diename and tname */
169static int die_compare_name(Dwarf_Die dw_die, const char *tname) 172static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
170{ 173{
171 char *name; 174 const char *name;
172 int ret; 175 name = dwarf_diename(dw_die);
173 ret = dwarf_diename(dw_die, &name, &__dw_error); 176 DIE_IF(name == NULL);
174 DIE_IF(ret == DW_DLV_ERROR); 177 return strcmp(tname, name);
175 if (ret == DW_DLV_OK) {
176 ret = strcmp(tname, name);
177 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
178 } else
179 ret = -1;
180 return ret;
181} 178}
182 179
183/* Check the address is in the subprogram(function). */ 180/* Check the address is in the subprogram(function). */
184static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, 181static bool die_within_subprogram(Dwarf_Die *sp_die, Dwarf_Addr addr,
185 Dwarf_Signed *offs) 182 size_t *offs)
186{ 183{
187 Dwarf_Addr lopc, hipc; 184 Dwarf_Addr epc;
188 int ret; 185 int ret;
189 186
190 /* TODO: check ranges */ 187 ret = dwarf_haspc(sp_die, addr);
191 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error); 188 if (ret <= 0)
192 DIE_IF(ret == DW_DLV_ERROR); 189 return false;
193 if (ret == DW_DLV_NO_ENTRY)
194 return 0;
195 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
196 DIE_IF(ret != DW_DLV_OK);
197 if (lopc <= addr && addr < hipc) {
198 *offs = addr - lopc;
199 return 1;
200 } else
201 return 0;
202}
203 190
204/* Check the die is inlined function */ 191 if (offs) {
205static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die) 192 ret = dwarf_entrypc(sp_die, &epc);
206{ 193 DIE_IF(ret == -1);
207 /* TODO: check strictly */ 194 *offs = addr - epc;
208 Dwarf_Bool inl; 195 }
209 int ret;
210 196
211 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); 197 return true;
212 DIE_IF(ret == DW_DLV_ERROR);
213 return inl;
214} 198}
215 199
216/* Get the offset of abstruct_origin */ 200/* Get entry pc(or low pc, 1st entry of ranges) of the die */
217static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die) 201static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
218{ 202{
219 Dwarf_Attribute attr; 203 Dwarf_Addr epc;
220 Dwarf_Off cu_offs;
221 int ret; 204 int ret;
222 205
223 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); 206 ret = dwarf_entrypc(dw_die, &epc);
224 DIE_IF(ret != DW_DLV_OK); 207 DIE_IF(ret == -1);
225 ret = dwarf_formref(attr, &cu_offs, &__dw_error); 208 return epc;
226 DIE_IF(ret != DW_DLV_OK);
227 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
228 return cu_offs;
229} 209}
230 210
231/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 211/* Check if the abstract origin's address or not */
232static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) 212static bool die_compare_abstract_origin(Dwarf_Die *in_die, void *origin_addr)
233{ 213{
234 Dwarf_Attribute attr; 214 Dwarf_Attribute attr;
235 Dwarf_Addr addr; 215 Dwarf_Die origin;
236 Dwarf_Off offs;
237 Dwarf_Ranges *ranges;
238 Dwarf_Signed cnt;
239 int ret;
240 216
241 /* Try to get entry pc */ 217 if (!dwarf_attr(in_die, DW_AT_abstract_origin, &attr))
242 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); 218 return false;
243 DIE_IF(ret == DW_DLV_ERROR); 219 if (!dwarf_formref_die(&attr, &origin))
244 if (ret == DW_DLV_OK) { 220 return false;
245 ret = dwarf_formaddr(attr, &addr, &__dw_error);
246 DIE_IF(ret != DW_DLV_OK);
247 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
248 return addr;
249 }
250 221
251 /* Try to get low pc */ 222 return origin.addr == origin_addr;
252 ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
253 DIE_IF(ret == DW_DLV_ERROR);
254 if (ret == DW_DLV_OK)
255 return addr;
256
257 /* Try to get ranges */
258 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
259 DIE_IF(ret != DW_DLV_OK);
260 ret = dwarf_formref(attr, &offs, &__dw_error);
261 DIE_IF(ret != DW_DLV_OK);
262 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
263 &__dw_error);
264 DIE_IF(ret != DW_DLV_OK);
265 addr = ranges[0].dwr_addr1;
266 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
267 return addr;
268} 223}
269 224
270/* 225/*
@@ -275,7 +230,6 @@ static int __search_die_tree(struct die_link *cur_link,
275 int (*die_cb)(struct die_link *, void *), 230 int (*die_cb)(struct die_link *, void *),
276 void *data) 231 void *data)
277{ 232{
278 Dwarf_Die new_die;
279 struct die_link new_link; 233 struct die_link new_link;
280 int ret; 234 int ret;
281 235
@@ -285,31 +239,24 @@ static int __search_die_tree(struct die_link *cur_link,
285 /* Check current die */ 239 /* Check current die */
286 while (!(ret = die_cb(cur_link, data))) { 240 while (!(ret = die_cb(cur_link, data))) {
287 /* Check child die */ 241 /* Check child die */
288 ret = dwarf_child(cur_link->die, &new_die, &__dw_error); 242 ret = dwarf_child(&cur_link->die, &new_link.die);
289 DIE_IF(ret == DW_DLV_ERROR); 243 if (ret == 0) {
290 if (ret == DW_DLV_OK) {
291 new_link.parent = cur_link; 244 new_link.parent = cur_link;
292 new_link.die = new_die;
293 ret = __search_die_tree(&new_link, die_cb, data); 245 ret = __search_die_tree(&new_link, die_cb, data);
294 if (ret) 246 if (ret)
295 break; 247 break;
296 } 248 }
297 249
298 /* Move to next sibling */ 250 /* Move to next sibling */
299 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die, 251 ret = dwarf_siblingof(&cur_link->die, &cur_link->die);
300 &__dw_error); 252 if (ret != 0)
301 DIE_IF(ret == DW_DLV_ERROR);
302 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
303 cur_link->die = new_die;
304 if (ret == DW_DLV_NO_ENTRY)
305 return 0; 253 return 0;
306 } 254 }
307 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
308 return ret; 255 return ret;
309} 256}
310 257
311/* Search a die in its children's die tree */ 258/* Search a die in its children's die tree */
312static int search_die_from_children(Dwarf_Die parent_die, 259static int search_die_from_children(Dwarf_Die *parent_die,
313 int (*die_cb)(struct die_link *, void *), 260 int (*die_cb)(struct die_link *, void *),
314 void *data) 261 void *data)
315{ 262{
@@ -317,125 +264,58 @@ static int search_die_from_children(Dwarf_Die parent_die,
317 int ret; 264 int ret;
318 265
319 new_link.parent = NULL; 266 new_link.parent = NULL;
320 ret = dwarf_child(parent_die, &new_link.die, &__dw_error); 267 ret = dwarf_child(parent_die, &new_link.die);
321 DIE_IF(ret == DW_DLV_ERROR); 268 if (ret == 0)
322 if (ret == DW_DLV_OK)
323 return __search_die_tree(&new_link, die_cb, data); 269 return __search_die_tree(&new_link, die_cb, data);
324 else 270 else
325 return 0; 271 return 0;
326} 272}
327 273
328/* Find a locdesc corresponding to the address */
329static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
330 Dwarf_Addr addr)
331{
332 Dwarf_Signed lcnt;
333 Dwarf_Locdesc **llbuf;
334 int ret, i;
335
336 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
337 DIE_IF(ret != DW_DLV_OK);
338 ret = DW_DLV_NO_ENTRY;
339 for (i = 0; i < lcnt; ++i) {
340 if (llbuf[i]->ld_lopc <= addr &&
341 llbuf[i]->ld_hipc > addr) {
342 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
343 desc->ld_s =
344 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
345 DIE_IF(desc->ld_s == NULL);
346 memcpy(desc->ld_s, llbuf[i]->ld_s,
347 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
348 ret = DW_DLV_OK;
349 break;
350 }
351 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
352 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
353 }
354 /* Releasing loop */
355 for (; i < lcnt; ++i) {
356 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
357 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
358 }
359 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
360 return ret;
361}
362
363/* Get decl_file attribute value (file number) */
364static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die)
365{
366 Dwarf_Attribute attr;
367 Dwarf_Unsigned fno;
368 int ret;
369
370 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error);
371 DIE_IF(ret != DW_DLV_OK);
372 dwarf_formudata(attr, &fno, &__dw_error);
373 DIE_IF(ret != DW_DLV_OK);
374 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
375 return fno;
376}
377
378/* Get decl_line attribute value (line number) */
379static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
380{
381 Dwarf_Attribute attr;
382 Dwarf_Unsigned lno;
383 int ret;
384
385 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error);
386 DIE_IF(ret != DW_DLV_OK);
387 dwarf_formudata(attr, &lno, &__dw_error);
388 DIE_IF(ret != DW_DLV_OK);
389 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
390 return lno;
391}
392 274
393/* 275/*
394 * Probe finder related functions 276 * Probe finder related functions
395 */ 277 */
396 278
397/* Show a location */ 279/* Show a location */
398static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) 280static void show_location(Dwarf_Op *op, struct probe_finder *pf)
399{ 281{
400 Dwarf_Small op; 282 unsigned int regn;
401 Dwarf_Unsigned regn; 283 Dwarf_Word offs = 0;
402 Dwarf_Signed offs;
403 int deref = 0, ret; 284 int deref = 0, ret;
404 const char *regs; 285 const char *regs;
405 286
406 op = loc->lr_atom; 287 /* TODO: support CFA */
407
408 /* If this is based on frame buffer, set the offset */ 288 /* If this is based on frame buffer, set the offset */
409 if (op == DW_OP_fbreg) { 289 if (op->atom == DW_OP_fbreg) {
290 if (pf->fb_ops == NULL)
291 die("The attribute of frame base is not supported.\n");
410 deref = 1; 292 deref = 1;
411 offs = (Dwarf_Signed)loc->lr_number; 293 offs = op->number;
412 op = pf->fbloc.ld_s[0].lr_atom; 294 op = &pf->fb_ops[0];
413 loc = &pf->fbloc.ld_s[0]; 295 }
414 } else
415 offs = 0;
416 296
417 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { 297 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
418 regn = op - DW_OP_breg0; 298 regn = op->atom - DW_OP_breg0;
419 offs += (Dwarf_Signed)loc->lr_number; 299 offs += op->number;
420 deref = 1; 300 deref = 1;
421 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { 301 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
422 regn = op - DW_OP_reg0; 302 regn = op->atom - DW_OP_reg0;
423 } else if (op == DW_OP_bregx) { 303 } else if (op->atom == DW_OP_bregx) {
424 regn = loc->lr_number; 304 regn = op->number;
425 offs += (Dwarf_Signed)loc->lr_number2; 305 offs += op->number2;
426 deref = 1; 306 deref = 1;
427 } else if (op == DW_OP_regx) { 307 } else if (op->atom == DW_OP_regx) {
428 regn = loc->lr_number; 308 regn = op->number;
429 } else 309 } else
430 die("Dwarf_OP %d is not supported.", op); 310 die("DW_OP %d is not supported.", op->atom);
431 311
432 regs = get_arch_regstr(regn); 312 regs = get_arch_regstr(regn);
433 if (!regs) 313 if (!regs)
434 die("%lld exceeds max register number.", regn); 314 die("%u exceeds max register number.", regn);
435 315
436 if (deref) 316 if (deref)
437 ret = snprintf(pf->buf, pf->len, 317 ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)",
438 " %s=%+lld(%s)", pf->var, offs, regs); 318 pf->var, (uintmax_t)offs, regs);
439 else 319 else
440 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 320 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
441 DIE_IF(ret < 0); 321 DIE_IF(ret < 0);
@@ -443,41 +323,41 @@ static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
443} 323}
444 324
445/* Show a variables in kprobe event format */ 325/* Show a variables in kprobe event format */
446static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) 326static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
447{ 327{
448 Dwarf_Attribute attr; 328 Dwarf_Attribute attr;
449 Dwarf_Locdesc ld; 329 Dwarf_Op *expr;
330 size_t nexpr;
450 int ret; 331 int ret;
451 332
452 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); 333 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
453 if (ret != DW_DLV_OK)
454 goto error; 334 goto error;
455 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); 335 /* TODO: handle more than 1 exprs */
456 if (ret != DW_DLV_OK) 336 ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base),
337 &expr, &nexpr, 1);
338 if (ret <= 0 || nexpr == 0)
457 goto error; 339 goto error;
458 /* TODO? */ 340
459 DIE_IF(ld.ld_cents != 1); 341 show_location(expr, pf);
460 show_location(&ld.ld_s[0], pf); 342 /* *expr will be cached in libdw. Don't free it. */
461 free(ld.ld_s);
462 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
463 return ; 343 return ;
464error: 344error:
345 /* TODO: Support const_value */
465 die("Failed to find the location of %s at this address.\n" 346 die("Failed to find the location of %s at this address.\n"
466 " Perhaps, it has been optimized out.", pf->var); 347 " Perhaps, it has been optimized out.", pf->var);
467} 348}
468 349
469static int variable_callback(struct die_link *dlink, void *data) 350static int variable_search_cb(struct die_link *dlink, void *data)
470{ 351{
471 struct probe_finder *pf = (struct probe_finder *)data; 352 struct probe_finder *pf = (struct probe_finder *)data;
472 Dwarf_Half tag; 353 int tag;
473 int ret;
474 354
475 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 355 tag = dwarf_tag(&dlink->die);
476 DIE_IF(ret == DW_DLV_ERROR); 356 DIE_IF(tag < 0);
477 if ((tag == DW_TAG_formal_parameter || 357 if ((tag == DW_TAG_formal_parameter ||
478 tag == DW_TAG_variable) && 358 tag == DW_TAG_variable) &&
479 (die_compare_name(dlink->die, pf->var) == 0)) { 359 (die_compare_name(&dlink->die, pf->var) == 0)) {
480 show_variable(dlink->die, pf); 360 show_variable(&dlink->die, pf);
481 return 1; 361 return 1;
482 } 362 }
483 /* TODO: Support struct members and arrays */ 363 /* TODO: Support struct members and arrays */
@@ -485,7 +365,7 @@ static int variable_callback(struct die_link *dlink, void *data)
485} 365}
486 366
487/* Find a variable in a subprogram die */ 367/* Find a variable in a subprogram die */
488static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) 368static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
489{ 369{
490 int ret; 370 int ret;
491 371
@@ -499,43 +379,25 @@ static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
499 379
500 pr_debug("Searching '%s' variable in context.\n", pf->var); 380 pr_debug("Searching '%s' variable in context.\n", pf->var);
501 /* Search child die for local variables and parameters. */ 381 /* Search child die for local variables and parameters. */
502 ret = search_die_from_children(sp_die, variable_callback, pf); 382 ret = search_die_from_children(sp_die, variable_search_cb, pf);
503 if (!ret) 383 if (!ret)
504 die("Failed to find '%s' in this function.", pf->var); 384 die("Failed to find '%s' in this function.", pf->var);
505} 385}
506 386
507/* Get a frame base on the address */
508static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
509{
510 Dwarf_Attribute attr;
511 int ret;
512
513 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
514 DIE_IF(ret != DW_DLV_OK);
515 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
516 DIE_IF(ret != DW_DLV_OK);
517 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
518}
519
520static void free_current_frame_base(struct probe_finder *pf)
521{
522 free(pf->fbloc.ld_s);
523 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
524}
525
526/* Show a probe point to output buffer */ 387/* Show a probe point to output buffer */
527static void show_probe_point(Dwarf_Die sp_die, Dwarf_Signed offs, 388static void show_probe_point(Dwarf_Die *sp_die, size_t offs,
528 struct probe_finder *pf) 389 struct probe_finder *pf)
529{ 390{
530 struct probe_point *pp = pf->pp; 391 struct probe_point *pp = pf->pp;
531 char *name; 392 const char *name;
532 char tmp[MAX_PROBE_BUFFER]; 393 char tmp[MAX_PROBE_BUFFER];
533 int ret, i, len; 394 int ret, i, len;
395 Dwarf_Attribute fb_attr;
396 size_t nops;
534 397
535 /* Output name of probe point */ 398 /* Output name of probe point */
536 ret = dwarf_diename(sp_die, &name, &__dw_error); 399 name = dwarf_diename(sp_die);
537 DIE_IF(ret == DW_DLV_ERROR); 400 if (name) {
538 if (ret == DW_DLV_OK) {
539 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 401 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
540 (unsigned int)offs); 402 (unsigned int)offs);
541 /* Copy the function name if possible */ 403 /* Copy the function name if possible */
@@ -543,14 +405,14 @@ static void show_probe_point(Dwarf_Die sp_die, Dwarf_Signed offs,
543 pp->function = strdup(name); 405 pp->function = strdup(name);
544 pp->offset = offs; 406 pp->offset = offs;
545 } 407 }
546 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
547 } else { 408 } else {
548 /* This function has no name. */ 409 /* This function has no name. */
549 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); 410 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
411 (uintmax_t)pf->addr);
550 if (!pp->function) { 412 if (!pp->function) {
551 /* TODO: Use _stext */ 413 /* TODO: Use _stext */
552 pp->function = strdup(""); 414 pp->function = strdup("");
553 pp->offset = (int)pf->addr; 415 pp->offset = (size_t)pf->addr;
554 } 416 }
555 } 417 }
556 DIE_IF(ret < 0); 418 DIE_IF(ret < 0);
@@ -558,8 +420,15 @@ static void show_probe_point(Dwarf_Die sp_die, Dwarf_Signed offs,
558 len = ret; 420 len = ret;
559 pr_debug("Probe point found: %s\n", tmp); 421 pr_debug("Probe point found: %s\n", tmp);
560 422
423 /* Get the frame base attribute/ops */
424 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
425 ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base),
426 &pf->fb_ops, &nops, 1);
427 if (ret <= 0 || nops == 0)
428 pf->fb_ops = NULL;
429
561 /* Find each argument */ 430 /* Find each argument */
562 get_current_frame_base(sp_die, pf); 431 /* TODO: use dwarf_cfi_addrframe */
563 for (i = 0; i < pp->nr_args; i++) { 432 for (i = 0; i < pp->nr_args; i++) {
564 pf->var = pp->args[i]; 433 pf->var = pp->args[i];
565 pf->buf = &tmp[len]; 434 pf->buf = &tmp[len];
@@ -567,131 +436,106 @@ static void show_probe_point(Dwarf_Die sp_die, Dwarf_Signed offs,
567 find_variable(sp_die, pf); 436 find_variable(sp_die, pf);
568 len += strlen(pf->buf); 437 len += strlen(pf->buf);
569 } 438 }
570 free_current_frame_base(pf); 439
440 /* *pf->fb_ops will be cached in libdw. Don't free it. */
441 pf->fb_ops = NULL;
571 442
572 pp->probes[pp->found] = strdup(tmp); 443 pp->probes[pp->found] = strdup(tmp);
573 pp->found++; 444 pp->found++;
574} 445}
575 446
576static int probeaddr_callback(struct die_link *dlink, void *data)
577{
578 struct probe_finder *pf = (struct probe_finder *)data;
579 Dwarf_Half tag;
580 Dwarf_Signed offs;
581 int ret;
582
583 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
584 DIE_IF(ret == DW_DLV_ERROR);
585 /* Check the address is in this subprogram */
586 if (tag == DW_TAG_subprogram &&
587 die_within_subprogram(dlink->die, pf->addr, &offs)) {
588 show_probe_point(dlink->die, offs, pf);
589 return 1;
590 }
591 return 0;
592}
593
594/* Find probe point from its line number */ 447/* Find probe point from its line number */
595static void find_probe_point_by_line(struct probe_finder *pf) 448static void find_probe_point_by_line(struct probe_finder *pf)
596{ 449{
597 Dwarf_Signed cnt, i, clm; 450 Dwarf_Lines *lines;
598 Dwarf_Line *lines; 451 Dwarf_Line *line;
599 Dwarf_Unsigned lineno = 0; 452 size_t nlines, i;
600 Dwarf_Addr addr; 453 Dwarf_Addr addr, epc;
601 Dwarf_Unsigned fno; 454 int lineno;
602 int ret; 455 int ret;
456 Dwarf_Die *sp_die, die_mem;
603 457
604 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); 458 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
605 DIE_IF(ret != DW_DLV_OK); 459 DIE_IF(ret != 0);
606
607 for (i = 0; i < cnt; i++) {
608 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
609 DIE_IF(ret != DW_DLV_OK);
610 if (fno != pf->fno)
611 continue;
612 460
613 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 461 for (i = 0; i < nlines; i++) {
614 DIE_IF(ret != DW_DLV_OK); 462 line = dwarf_onesrcline(lines, i);
463 dwarf_lineno(line, &lineno);
615 if (lineno != pf->lno) 464 if (lineno != pf->lno)
616 continue; 465 continue;
617 466
618 ret = dwarf_lineoff(lines[i], &clm, &__dw_error); 467 /* TODO: Get fileno from line, but how? */
619 DIE_IF(ret != DW_DLV_OK); 468 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
469 continue;
620 470
621 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 471 ret = dwarf_lineaddr(line, &addr);
622 DIE_IF(ret != DW_DLV_OK); 472 DIE_IF(ret != 0);
623 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n", 473 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
624 (int)i, (unsigned)lineno, (int)clm, addr); 474 (int)i, lineno, (uintmax_t)addr);
625 pf->addr = addr; 475 pf->addr = addr;
626 /* Search a real subprogram including this line, */ 476
627 ret = search_die_from_children(pf->cu_die, 477 sp_die = die_get_real_subprogram(&pf->cu_die, addr, &die_mem);
628 probeaddr_callback, pf); 478 if (!sp_die)
629 if (ret == 0)
630 die("Probe point is not found in subprograms."); 479 die("Probe point is not found in subprograms.");
480 dwarf_entrypc(sp_die, &epc);
481 show_probe_point(sp_die, (size_t)(addr - epc), pf);
631 /* Continuing, because target line might be inlined. */ 482 /* Continuing, because target line might be inlined. */
632 } 483 }
633 dwarf_srclines_dealloc(__dw_debug, lines, cnt);
634} 484}
635 485
486
636/* Search function from function name */ 487/* Search function from function name */
637static int probefunc_callback(struct die_link *dlink, void *data) 488static int probe_point_search_cb(struct die_link *dlink, void *data)
638{ 489{
639 struct probe_finder *pf = (struct probe_finder *)data; 490 struct probe_finder *pf = (struct probe_finder *)data;
640 struct probe_point *pp = pf->pp; 491 struct probe_point *pp = pf->pp;
641 struct die_link *lk; 492 struct die_link *lk;
642 Dwarf_Signed offs; 493 size_t offs;
643 Dwarf_Half tag; 494 int tag;
644 int ret; 495 int ret;
645 496
646 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 497 tag = dwarf_tag(&dlink->die);
647 DIE_IF(ret == DW_DLV_ERROR);
648 if (tag == DW_TAG_subprogram) { 498 if (tag == DW_TAG_subprogram) {
649 if (die_compare_name(dlink->die, pp->function) == 0) { 499 if (die_compare_name(&dlink->die, pp->function) == 0) {
650 if (pp->line) { /* Function relative line */ 500 if (pp->line) { /* Function relative line */
651 pf->fno = die_get_decl_file(dlink->die); 501 pf->fname = dwarf_decl_file(&dlink->die);
652 pf->lno = die_get_decl_line(dlink->die) 502 dwarf_decl_line(&dlink->die, &pf->lno);
653 + pp->line; 503 pf->lno += pp->line;
654 find_probe_point_by_line(pf); 504 find_probe_point_by_line(pf);
655 return 1; 505 return 1;
656 } 506 }
657 if (die_inlined_subprogram(dlink->die)) { 507 if (dwarf_func_inline(&dlink->die)) {
658 /* Inlined function, save it. */ 508 /* Inlined function, save it. */
659 ret = dwarf_die_CU_offset(dlink->die, 509 pf->origin = dlink->die.addr;
660 &pf->inl_offs,
661 &__dw_error);
662 DIE_IF(ret != DW_DLV_OK);
663 pr_debug("inline definition offset %lld\n",
664 pf->inl_offs);
665 return 0; /* Continue to search */ 510 return 0; /* Continue to search */
666 } 511 }
667 /* Get probe address */ 512 /* Get probe address */
668 pf->addr = die_get_entrypc(dlink->die); 513 pf->addr = die_get_entrypc(&dlink->die);
669 pf->addr += pp->offset; 514 pf->addr += pp->offset;
670 /* TODO: Check the address in this function */ 515 /* TODO: Check the address in this function */
671 show_probe_point(dlink->die, pp->offset, pf); 516 show_probe_point(&dlink->die, pp->offset, pf);
672 return 1; /* Exit; no same symbol in this CU. */ 517 return 1; /* Exit; no same symbol in this CU. */
673 } 518 }
674 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) { 519 } else if (tag == DW_TAG_inlined_subroutine && pf->origin) {
675 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) { 520 if (die_compare_abstract_origin(&dlink->die, pf->origin)) {
676 /* Get probe address */ 521 /* Get probe address */
677 pf->addr = die_get_entrypc(dlink->die); 522 pf->addr = die_get_entrypc(&dlink->die);
678 pf->addr += pp->offset; 523 pf->addr += pp->offset;
679 pr_debug("found inline addr: 0x%llx\n", pf->addr); 524 pr_debug("found inline addr: 0x%jx\n",
525 (uintmax_t)pf->addr);
680 /* Inlined function. Get a real subprogram */ 526 /* Inlined function. Get a real subprogram */
681 for (lk = dlink->parent; lk != NULL; lk = lk->parent) { 527 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
682 tag = 0; 528 tag = dwarf_tag(&lk->die);
683 dwarf_tag(lk->die, &tag, &__dw_error);
684 DIE_IF(ret == DW_DLV_ERROR);
685 if (tag == DW_TAG_subprogram && 529 if (tag == DW_TAG_subprogram &&
686 !die_inlined_subprogram(lk->die)) 530 !dwarf_func_inline(&lk->die))
687 goto found; 531 goto found;
688 } 532 }
689 die("Failed to find real subprogram."); 533 die("Failed to find real subprogram.");
690found: 534found:
691 /* Get offset from subprogram */ 535 /* Get offset from subprogram */
692 ret = die_within_subprogram(lk->die, pf->addr, &offs); 536 ret = die_within_subprogram(&lk->die, pf->addr, &offs);
693 DIE_IF(!ret); 537 DIE_IF(!ret);
694 show_probe_point(lk->die, offs, pf); 538 show_probe_point(&lk->die, offs, pf);
695 /* Continue to search */ 539 /* Continue to search */
696 } 540 }
697 } 541 }
@@ -700,43 +544,43 @@ found:
700 544
701static void find_probe_point_by_func(struct probe_finder *pf) 545static void find_probe_point_by_func(struct probe_finder *pf)
702{ 546{
703 search_die_from_children(pf->cu_die, probefunc_callback, pf); 547 search_die_from_children(&pf->cu_die, probe_point_search_cb, pf);
704} 548}
705 549
706/* Find a probe point */ 550/* Find a probe point */
707int find_probe_point(int fd, struct probe_point *pp) 551int find_probe_point(int fd, struct probe_point *pp)
708{ 552{
709 Dwarf_Half addr_size = 0;
710 Dwarf_Unsigned next_cuh = 0;
711 int cu_number = 0, ret;
712 struct probe_finder pf = {.pp = pp}; 553 struct probe_finder pf = {.pp = pp};
713 554 int ret;
714 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 555 Dwarf_Off off, noff;
715 if (ret != DW_DLV_OK) 556 size_t cuhl;
557 Dwarf_Die *diep;
558 Dwarf *dbg;
559 int fno = 0;
560
561 dbg = dwarf_begin(fd, DWARF_C_READ);
562 if (!dbg)
716 return -ENOENT; 563 return -ENOENT;
717 564
718 pp->found = 0; 565 pp->found = 0;
719 while (++cu_number) { 566 off = 0;
720 /* Search CU (Compilation Unit) */ 567 /* Loop on CUs (Compilation Unit) */
721 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 568 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
722 &addr_size, &next_cuh, &__dw_error);
723 DIE_IF(ret == DW_DLV_ERROR);
724 if (ret == DW_DLV_NO_ENTRY)
725 break;
726
727 /* Get the DIE(Debugging Information Entry) of this CU */ 569 /* Get the DIE(Debugging Information Entry) of this CU */
728 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); 570 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
729 DIE_IF(ret != DW_DLV_OK); 571 if (!diep)
572 continue;
730 573
731 /* Check if target file is included. */ 574 /* Check if target file is included. */
732 if (pp->file) 575 if (pp->file)
733 pf.fno = cu_find_fileno(pf.cu_die, pp->file); 576 fno = cu_find_fileno(&pf.cu_die, pp->file);
577 else
578 fno = 0;
734 579
735 if (!pp->file || pf.fno) { 580 if (!pp->file || fno) {
736 /* Save CU base address (for frame_base) */ 581 /* Save CU base address (for frame_base) */
737 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); 582 ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base);
738 DIE_IF(ret == DW_DLV_ERROR); 583 if (ret != 0)
739 if (ret == DW_DLV_NO_ENTRY)
740 pf.cu_base = 0; 584 pf.cu_base = 0;
741 if (pp->function) 585 if (pp->function)
742 find_probe_point_by_func(&pf); 586 find_probe_point_by_func(&pf);
@@ -745,10 +589,9 @@ int find_probe_point(int fd, struct probe_point *pp)
745 find_probe_point_by_line(&pf); 589 find_probe_point_by_line(&pf);
746 } 590 }
747 } 591 }
748 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 592 off = noff;
749 } 593 }
750 ret = dwarf_finish(__dw_debug, &__dw_error); 594 dwarf_end(dbg);
751 DIE_IF(ret != DW_DLV_OK);
752 595
753 return pp->found; 596 return pp->found;
754} 597}
@@ -781,69 +624,76 @@ found:
781/* Find line range from its line number */ 624/* Find line range from its line number */
782static void find_line_range_by_line(struct line_finder *lf) 625static void find_line_range_by_line(struct line_finder *lf)
783{ 626{
784 Dwarf_Signed cnt, i; 627 Dwarf_Lines *lines;
785 Dwarf_Line *lines; 628 Dwarf_Line *line;
786 Dwarf_Unsigned lineno = 0; 629 size_t nlines, i;
787 Dwarf_Unsigned fno;
788 Dwarf_Addr addr; 630 Dwarf_Addr addr;
631 int lineno;
789 int ret; 632 int ret;
633 const char *src;
790 634
791 INIT_LIST_HEAD(&lf->lr->line_list); 635 INIT_LIST_HEAD(&lf->lr->line_list);
792 ret = dwarf_srclines(lf->cu_die, &lines, &cnt, &__dw_error); 636 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
793 DIE_IF(ret != DW_DLV_OK); 637 DIE_IF(ret != 0);
794 638
795 for (i = 0; i < cnt; i++) { 639 for (i = 0; i < nlines; i++) {
796 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 640 line = dwarf_onesrcline(lines, i);
797 DIE_IF(ret != DW_DLV_OK); 641 dwarf_lineno(line, &lineno);
798 if (fno != lf->fno) 642 if (lf->lno_s > lineno || lf->lno_e < lineno)
799 continue; 643 continue;
800 644
801 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 645 /* TODO: Get fileno from line, but how? */
802 DIE_IF(ret != DW_DLV_OK); 646 src = dwarf_linesrc(line, NULL, NULL);
803 if (lf->lno_s > lineno || lf->lno_e < lineno) 647 if (strtailcmp(src, lf->fname) != 0)
804 continue; 648 continue;
805 649
806 /* Filter line in the function address range */ 650 /* Filter line in the function address range */
807 if (lf->addr_s && lf->addr_e) { 651 if (lf->addr_s && lf->addr_e) {
808 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 652 ret = dwarf_lineaddr(line, &addr);
809 DIE_IF(ret != DW_DLV_OK); 653 DIE_IF(ret != 0);
810 if (lf->addr_s > addr || lf->addr_e <= addr) 654 if (lf->addr_s > addr || lf->addr_e <= addr)
811 continue; 655 continue;
812 } 656 }
657 /* Copy real path */
658 if (!lf->lr->path)
659 lf->lr->path = strdup(src);
813 line_range_add_line(lf->lr, (unsigned int)lineno); 660 line_range_add_line(lf->lr, (unsigned int)lineno);
814 } 661 }
815 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 662 /* Update status */
816 if (!list_empty(&lf->lr->line_list)) 663 if (!list_empty(&lf->lr->line_list))
817 lf->found = 1; 664 lf->found = 1;
665 else {
666 free(lf->lr->path);
667 lf->lr->path = NULL;
668 }
818} 669}
819 670
820/* Search function from function name */ 671/* Search function from function name */
821static int linefunc_callback(struct die_link *dlink, void *data) 672static int line_range_search_cb(struct die_link *dlink, void *data)
822{ 673{
823 struct line_finder *lf = (struct line_finder *)data; 674 struct line_finder *lf = (struct line_finder *)data;
824 struct line_range *lr = lf->lr; 675 struct line_range *lr = lf->lr;
825 Dwarf_Half tag; 676 int tag;
826 int ret; 677 int ret;
827 678
828 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 679 tag = dwarf_tag(&dlink->die);
829 DIE_IF(ret == DW_DLV_ERROR);
830 if (tag == DW_TAG_subprogram && 680 if (tag == DW_TAG_subprogram &&
831 die_compare_name(dlink->die, lr->function) == 0) { 681 die_compare_name(&dlink->die, lr->function) == 0) {
832 /* Get the address range of this function */ 682 /* Get the address range of this function */
833 ret = dwarf_highpc(dlink->die, &lf->addr_e, &__dw_error); 683 ret = dwarf_highpc(&dlink->die, &lf->addr_e);
834 if (ret == DW_DLV_OK) 684 if (ret == 0)
835 ret = dwarf_lowpc(dlink->die, &lf->addr_s, &__dw_error); 685 ret = dwarf_lowpc(&dlink->die, &lf->addr_s);
836 DIE_IF(ret == DW_DLV_ERROR); 686 if (ret != 0) {
837 if (ret == DW_DLV_NO_ENTRY) {
838 lf->addr_s = 0; 687 lf->addr_s = 0;
839 lf->addr_e = 0; 688 lf->addr_e = 0;
840 } 689 }
841 690
842 lf->fno = die_get_decl_file(dlink->die); 691 lf->fname = dwarf_decl_file(&dlink->die);
843 lr->offset = die_get_decl_line(dlink->die);; 692 dwarf_decl_line(&dlink->die, &lr->offset);
693 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
844 lf->lno_s = lr->offset + lr->start; 694 lf->lno_s = lr->offset + lr->start;
845 if (!lr->end) 695 if (!lr->end)
846 lf->lno_e = (Dwarf_Unsigned)-1; 696 lf->lno_e = INT_MAX;
847 else 697 else
848 lf->lno_e = lr->offset + lr->end; 698 lf->lno_e = lr->offset + lr->end;
849 lr->start = lf->lno_s; 699 lr->start = lf->lno_s;
@@ -856,55 +706,57 @@ static int linefunc_callback(struct die_link *dlink, void *data)
856 706
857static void find_line_range_by_func(struct line_finder *lf) 707static void find_line_range_by_func(struct line_finder *lf)
858{ 708{
859 search_die_from_children(lf->cu_die, linefunc_callback, lf); 709 search_die_from_children(&lf->cu_die, line_range_search_cb, lf);
860} 710}
861 711
862int find_line_range(int fd, struct line_range *lr) 712int find_line_range(int fd, struct line_range *lr)
863{ 713{
864 Dwarf_Half addr_size = 0; 714 struct line_finder lf = {.lr = lr, .found = 0};
865 Dwarf_Unsigned next_cuh = 0;
866 int ret; 715 int ret;
867 struct line_finder lf = {.lr = lr}; 716 Dwarf_Off off = 0, noff;
868 717 size_t cuhl;
869 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 718 Dwarf_Die *diep;
870 if (ret != DW_DLV_OK) 719 Dwarf *dbg;
720 int fno;
721
722 dbg = dwarf_begin(fd, DWARF_C_READ);
723 if (!dbg)
871 return -ENOENT; 724 return -ENOENT;
872 725
726 /* Loop on CUs (Compilation Unit) */
873 while (!lf.found) { 727 while (!lf.found) {
874 /* Search CU (Compilation Unit) */ 728 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
875 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 729 if (ret != 0)
876 &addr_size, &next_cuh, &__dw_error);
877 DIE_IF(ret == DW_DLV_ERROR);
878 if (ret == DW_DLV_NO_ENTRY)
879 break; 730 break;
880 731
881 /* Get the DIE(Debugging Information Entry) of this CU */ 732 /* Get the DIE(Debugging Information Entry) of this CU */
882 ret = dwarf_siblingof(__dw_debug, 0, &lf.cu_die, &__dw_error); 733 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
883 DIE_IF(ret != DW_DLV_OK); 734 if (!diep)
735 continue;
884 736
885 /* Check if target file is included. */ 737 /* Check if target file is included. */
886 if (lr->file) 738 if (lr->file)
887 lf.fno = cu_find_fileno(lf.cu_die, lr->file); 739 fno = cu_find_fileno(&lf.cu_die, lr->file);
740 else
741 fno = 0;
888 742
889 if (!lr->file || lf.fno) { 743 if (!lr->file || fno) {
890 if (lr->function) 744 if (lr->function)
891 find_line_range_by_func(&lf); 745 find_line_range_by_func(&lf);
892 else { 746 else {
747 lf.fname = lr->file;
893 lf.lno_s = lr->start; 748 lf.lno_s = lr->start;
894 if (!lr->end) 749 if (!lr->end)
895 lf.lno_e = (Dwarf_Unsigned)-1; 750 lf.lno_e = INT_MAX;
896 else 751 else
897 lf.lno_e = lr->end; 752 lf.lno_e = lr->end;
898 find_line_range_by_line(&lf); 753 find_line_range_by_line(&lf);
899 } 754 }
900 /* Get the real file path */
901 if (lf.found)
902 cu_get_filename(lf.cu_die, lf.fno, &lr->path);
903 } 755 }
904 dwarf_dealloc(__dw_debug, lf.cu_die, DW_DLA_DIE); 756 off = noff;
905 } 757 }
906 ret = dwarf_finish(__dw_debug, &__dw_error); 758 pr_debug("path: %lx\n", (unsigned long)lr->path);
907 DIE_IF(ret != DW_DLV_OK); 759 dwarf_end(dbg);
908 return lf.found; 760 return lf.found;
909} 761}
910 762