2 * probe-finder.c : C expression to kprobe event converter
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <sys/utsname.h>
23 #include <sys/types.h>
38 #include "probe-finder.h"
41 /* Dwarf_Die Linkage to parent Die */
43 struct die_link
*parent
; /* Parent die */
44 Dwarf_Die die
; /* Current die */
47 static Dwarf_Debug __dw_debug
;
48 static Dwarf_Error __dw_error
;
51 * Generic dwarf analysis helpers
54 #define X86_32_MAX_REGS 8
55 const char *x86_32_regs_table
[X86_32_MAX_REGS
] = {
60 "$stack", /* Stack address instead of %sp */
66 #define X86_64_MAX_REGS 16
67 const char *x86_64_regs_table
[X86_64_MAX_REGS
] = {
86 /* TODO: switching by dwarf address size */
88 #define ARCH_MAX_REGS X86_64_MAX_REGS
89 #define arch_regs_table x86_64_regs_table
91 #define ARCH_MAX_REGS X86_32_MAX_REGS
92 #define arch_regs_table x86_32_regs_table
95 /* Return architecture dependent register string (for kprobe-tracer) */
96 static const char *get_arch_regstr(unsigned int n
)
98 return (n
<= ARCH_MAX_REGS
) ? arch_regs_table
[n
] : NULL
;
102 * Compare the tail of two strings.
103 * Return 0 if whole of either string is same as another's tail part.
105 static int strtailcmp(const char *s1
, const char *s2
)
109 while (--i1
>= 0 && --i2
>= 0) {
110 if (s1
[i1
] != s2
[i2
])
111 return s1
[i1
] - s2
[i2
];
116 /* Find the fileno of the target file. */
117 static Dwarf_Unsigned
cu_find_fileno(Dwarf_Die cu_die
, const char *fname
)
120 Dwarf_Unsigned found
= 0;
127 ret
= dwarf_srcfiles(cu_die
, &srcs
, &cnt
, &__dw_error
);
128 if (ret
== DW_DLV_OK
) {
129 for (i
= 0; i
< cnt
&& !found
; i
++) {
130 if (strtailcmp(srcs
[i
], fname
) == 0)
132 dwarf_dealloc(__dw_debug
, srcs
[i
], DW_DLA_STRING
);
135 dwarf_dealloc(__dw_debug
, srcs
[i
], DW_DLA_STRING
);
136 dwarf_dealloc(__dw_debug
, srcs
, DW_DLA_LIST
);
139 pr_debug("found fno: %d\n", (int)found
);
143 static int cu_get_filename(Dwarf_Die cu_die
, Dwarf_Unsigned fno
, char **buf
)
152 ret
= dwarf_srcfiles(cu_die
, &srcs
, &cnt
, &__dw_error
);
153 if (ret
== DW_DLV_OK
) {
154 if ((Dwarf_Unsigned
)cnt
> fno
- 1) {
155 *buf
= strdup(srcs
[fno
- 1]);
157 pr_debug("found filename: %s\n", *buf
);
160 for (i
= 0; i
< cnt
; i
++)
161 dwarf_dealloc(__dw_debug
, srcs
[i
], DW_DLA_STRING
);
162 dwarf_dealloc(__dw_debug
, srcs
, DW_DLA_LIST
);
168 /* Compare diename and tname */
169 static int die_compare_name(Dwarf_Die dw_die
, const char *tname
)
173 ret
= dwarf_diename(dw_die
, &name
, &__dw_error
);
174 DIE_IF(ret
== DW_DLV_ERROR
);
175 if (ret
== DW_DLV_OK
) {
176 ret
= strcmp(tname
, name
);
177 dwarf_dealloc(__dw_debug
, name
, DW_DLA_STRING
);
183 /* Check the address is in the subprogram(function). */
184 static int die_within_subprogram(Dwarf_Die sp_die
, Dwarf_Addr addr
,
187 Dwarf_Addr lopc
, hipc
;
190 /* TODO: check ranges */
191 ret
= dwarf_lowpc(sp_die
, &lopc
, &__dw_error
);
192 DIE_IF(ret
== DW_DLV_ERROR
);
193 if (ret
== DW_DLV_NO_ENTRY
)
195 ret
= dwarf_highpc(sp_die
, &hipc
, &__dw_error
);
196 DIE_IF(ret
!= DW_DLV_OK
);
197 if (lopc
<= addr
&& addr
< hipc
) {
204 /* Check the die is inlined function */
205 static Dwarf_Bool
die_inlined_subprogram(Dwarf_Die dw_die
)
207 /* TODO: check strictly */
211 ret
= dwarf_hasattr(dw_die
, DW_AT_inline
, &inl
, &__dw_error
);
212 DIE_IF(ret
== DW_DLV_ERROR
);
216 /* Get the offset of abstruct_origin */
217 static Dwarf_Off
die_get_abstract_origin(Dwarf_Die dw_die
)
219 Dwarf_Attribute attr
;
223 ret
= dwarf_attr(dw_die
, DW_AT_abstract_origin
, &attr
, &__dw_error
);
224 DIE_IF(ret
!= DW_DLV_OK
);
225 ret
= dwarf_formref(attr
, &cu_offs
, &__dw_error
);
226 DIE_IF(ret
!= DW_DLV_OK
);
227 dwarf_dealloc(__dw_debug
, attr
, DW_DLA_ATTR
);
231 /* Get entry pc(or low pc, 1st entry of ranges) of the die */
232 static Dwarf_Addr
die_get_entrypc(Dwarf_Die dw_die
)
234 Dwarf_Attribute attr
;
237 Dwarf_Ranges
*ranges
;
241 /* Try to get entry pc */
242 ret
= dwarf_attr(dw_die
, DW_AT_entry_pc
, &attr
, &__dw_error
);
243 DIE_IF(ret
== DW_DLV_ERROR
);
244 if (ret
== DW_DLV_OK
) {
245 ret
= dwarf_formaddr(attr
, &addr
, &__dw_error
);
246 DIE_IF(ret
!= DW_DLV_OK
);
247 dwarf_dealloc(__dw_debug
, attr
, DW_DLA_ATTR
);
251 /* Try to get low pc */
252 ret
= dwarf_lowpc(dw_die
, &addr
, &__dw_error
);
253 DIE_IF(ret
== DW_DLV_ERROR
);
254 if (ret
== DW_DLV_OK
)
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
,
264 DIE_IF(ret
!= DW_DLV_OK
);
265 addr
= ranges
[0].dwr_addr1
;
266 dwarf_ranges_dealloc(__dw_debug
, ranges
, cnt
);
271 * Search a Die from Die tree.
272 * Note: cur_link->die should be deallocated in this function.
274 static int __search_die_tree(struct die_link
*cur_link
,
275 int (*die_cb
)(struct die_link
*, void *),
279 struct die_link new_link
;
285 /* Check current die */
286 while (!(ret
= die_cb(cur_link
, data
))) {
287 /* Check child die */
288 ret
= dwarf_child(cur_link
->die
, &new_die
, &__dw_error
);
289 DIE_IF(ret
== DW_DLV_ERROR
);
290 if (ret
== DW_DLV_OK
) {
291 new_link
.parent
= cur_link
;
292 new_link
.die
= new_die
;
293 ret
= __search_die_tree(&new_link
, die_cb
, data
);
298 /* Move to next sibling */
299 ret
= dwarf_siblingof(__dw_debug
, cur_link
->die
, &new_die
,
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
)
307 dwarf_dealloc(__dw_debug
, cur_link
->die
, DW_DLA_DIE
);
311 /* Search a die in its children's die tree */
312 static int search_die_from_children(Dwarf_Die parent_die
,
313 int (*die_cb
)(struct die_link
*, void *),
316 struct die_link new_link
;
319 new_link
.parent
= NULL
;
320 ret
= dwarf_child(parent_die
, &new_link
.die
, &__dw_error
);
321 DIE_IF(ret
== DW_DLV_ERROR
);
322 if (ret
== DW_DLV_OK
)
323 return __search_die_tree(&new_link
, die_cb
, data
);
328 /* Find a locdesc corresponding to the address */
329 static int attr_get_locdesc(Dwarf_Attribute attr
, Dwarf_Locdesc
*desc
,
333 Dwarf_Locdesc
**llbuf
;
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
));
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
);
351 dwarf_dealloc(__dw_debug
, llbuf
[i
]->ld_s
, DW_DLA_LOC_BLOCK
);
352 dwarf_dealloc(__dw_debug
, llbuf
[i
], DW_DLA_LOCDESC
);
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
);
359 dwarf_dealloc(__dw_debug
, llbuf
, DW_DLA_LIST
);
363 /* Get decl_file attribute value (file number) */
364 static Dwarf_Unsigned
die_get_decl_file(Dwarf_Die sp_die
)
366 Dwarf_Attribute attr
;
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
);
378 /* Get decl_line attribute value (line number) */
379 static Dwarf_Unsigned
die_get_decl_line(Dwarf_Die sp_die
)
381 Dwarf_Attribute attr
;
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
);
394 * Probe finder related functions
397 /* Show a location */
398 static void show_location(Dwarf_Loc
*loc
, struct probe_finder
*pf
)
408 /* If this is based on frame buffer, set the offset */
409 if (op
== DW_OP_fbreg
) {
411 offs
= (Dwarf_Signed
)loc
->lr_number
;
412 op
= pf
->fbloc
.ld_s
[0].lr_atom
;
413 loc
= &pf
->fbloc
.ld_s
[0];
417 if (op
>= DW_OP_breg0
&& op
<= DW_OP_breg31
) {
418 regn
= op
- DW_OP_breg0
;
419 offs
+= (Dwarf_Signed
)loc
->lr_number
;
421 } else if (op
>= DW_OP_reg0
&& op
<= DW_OP_reg31
) {
422 regn
= op
- DW_OP_reg0
;
423 } else if (op
== DW_OP_bregx
) {
424 regn
= loc
->lr_number
;
425 offs
+= (Dwarf_Signed
)loc
->lr_number2
;
427 } else if (op
== DW_OP_regx
) {
428 regn
= loc
->lr_number
;
430 die("Dwarf_OP %d is not supported.", op
);
432 regs
= get_arch_regstr(regn
);
434 die("%lld exceeds max register number.", regn
);
437 ret
= snprintf(pf
->buf
, pf
->len
,
438 " %s=%+lld(%s)", pf
->var
, offs
, regs
);
440 ret
= snprintf(pf
->buf
, pf
->len
, " %s=%s", pf
->var
, regs
);
442 DIE_IF(ret
>= pf
->len
);
445 /* Show a variables in kprobe event format */
446 static void show_variable(Dwarf_Die vr_die
, struct probe_finder
*pf
)
448 Dwarf_Attribute attr
;
452 ret
= dwarf_attr(vr_die
, DW_AT_location
, &attr
, &__dw_error
);
453 if (ret
!= DW_DLV_OK
)
455 ret
= attr_get_locdesc(attr
, &ld
, (pf
->addr
- pf
->cu_base
));
456 if (ret
!= DW_DLV_OK
)
459 DIE_IF(ld
.ld_cents
!= 1);
460 show_location(&ld
.ld_s
[0], pf
);
462 dwarf_dealloc(__dw_debug
, attr
, DW_DLA_ATTR
);
465 die("Failed to find the location of %s at this address.\n"
466 " Perhaps, it has been optimized out.", pf
->var
);
469 static int variable_callback(struct die_link
*dlink
, void *data
)
471 struct probe_finder
*pf
= (struct probe_finder
*)data
;
475 ret
= dwarf_tag(dlink
->die
, &tag
, &__dw_error
);
476 DIE_IF(ret
== DW_DLV_ERROR
);
477 if ((tag
== DW_TAG_formal_parameter
||
478 tag
== DW_TAG_variable
) &&
479 (die_compare_name(dlink
->die
, pf
->var
) == 0)) {
480 show_variable(dlink
->die
, pf
);
483 /* TODO: Support struct members and arrays */
487 /* Find a variable in a subprogram die */
488 static void find_variable(Dwarf_Die sp_die
, struct probe_finder
*pf
)
492 if (!is_c_varname(pf
->var
)) {
493 /* Output raw parameters */
494 ret
= snprintf(pf
->buf
, pf
->len
, " %s", pf
->var
);
496 DIE_IF(ret
>= pf
->len
);
500 pr_debug("Searching '%s' variable in context.\n", pf
->var
);
501 /* Search child die for local variables and parameters. */
502 ret
= search_die_from_children(sp_die
, variable_callback
, pf
);
504 die("Failed to find '%s' in this function.", pf
->var
);
507 /* Get a frame base on the address */
508 static void get_current_frame_base(Dwarf_Die sp_die
, struct probe_finder
*pf
)
510 Dwarf_Attribute attr
;
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
);
520 static void free_current_frame_base(struct probe_finder
*pf
)
522 free(pf
->fbloc
.ld_s
);
523 memset(&pf
->fbloc
, 0, sizeof(Dwarf_Locdesc
));
526 /* Show a probe point to output buffer */
527 static void show_probe_point(Dwarf_Die sp_die
, Dwarf_Signed offs
,
528 struct probe_finder
*pf
)
530 struct probe_point
*pp
= pf
->pp
;
532 char tmp
[MAX_PROBE_BUFFER
];
535 /* Output name of probe point */
536 ret
= dwarf_diename(sp_die
, &name
, &__dw_error
);
537 DIE_IF(ret
== DW_DLV_ERROR
);
538 if (ret
== DW_DLV_OK
) {
539 ret
= snprintf(tmp
, MAX_PROBE_BUFFER
, "%s+%u", name
,
541 /* Copy the function name if possible */
543 pp
->function
= strdup(name
);
546 dwarf_dealloc(__dw_debug
, name
, DW_DLA_STRING
);
548 /* This function has no name. */
549 ret
= snprintf(tmp
, MAX_PROBE_BUFFER
, "0x%llx", pf
->addr
);
551 /* TODO: Use _stext */
552 pp
->function
= strdup("");
553 pp
->offset
= (int)pf
->addr
;
557 DIE_IF(ret
>= MAX_PROBE_BUFFER
);
559 pr_debug("Probe point found: %s\n", tmp
);
561 /* Find each argument */
562 get_current_frame_base(sp_die
, pf
);
563 for (i
= 0; i
< pp
->nr_args
; i
++) {
564 pf
->var
= pp
->args
[i
];
566 pf
->len
= MAX_PROBE_BUFFER
- len
;
567 find_variable(sp_die
, pf
);
568 len
+= strlen(pf
->buf
);
570 free_current_frame_base(pf
);
572 pp
->probes
[pp
->found
] = strdup(tmp
);
576 static int probeaddr_callback(struct die_link
*dlink
, void *data
)
578 struct probe_finder
*pf
= (struct probe_finder
*)data
;
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
);
594 /* Find probe point from its line number */
595 static void find_probe_point_by_line(struct probe_finder
*pf
)
597 Dwarf_Signed cnt
, i
, clm
;
599 Dwarf_Unsigned lineno
= 0;
604 ret
= dwarf_srclines(pf
->cu_die
, &lines
, &cnt
, &__dw_error
);
605 DIE_IF(ret
!= DW_DLV_OK
);
607 for (i
= 0; i
< cnt
; i
++) {
608 ret
= dwarf_line_srcfileno(lines
[i
], &fno
, &__dw_error
);
609 DIE_IF(ret
!= DW_DLV_OK
);
613 ret
= dwarf_lineno(lines
[i
], &lineno
, &__dw_error
);
614 DIE_IF(ret
!= DW_DLV_OK
);
615 if (lineno
!= pf
->lno
)
618 ret
= dwarf_lineoff(lines
[i
], &clm
, &__dw_error
);
619 DIE_IF(ret
!= DW_DLV_OK
);
621 ret
= dwarf_lineaddr(lines
[i
], &addr
, &__dw_error
);
622 DIE_IF(ret
!= DW_DLV_OK
);
623 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
624 (int)i
, (unsigned)lineno
, (int)clm
, addr
);
626 /* Search a real subprogram including this line, */
627 ret
= search_die_from_children(pf
->cu_die
,
628 probeaddr_callback
, pf
);
630 die("Probe point is not found in subprograms.");
631 /* Continuing, because target line might be inlined. */
633 dwarf_srclines_dealloc(__dw_debug
, lines
, cnt
);
636 /* Search function from function name */
637 static int probefunc_callback(struct die_link
*dlink
, void *data
)
639 struct probe_finder
*pf
= (struct probe_finder
*)data
;
640 struct probe_point
*pp
= pf
->pp
;
646 ret
= dwarf_tag(dlink
->die
, &tag
, &__dw_error
);
647 DIE_IF(ret
== DW_DLV_ERROR
);
648 if (tag
== DW_TAG_subprogram
) {
649 if (die_compare_name(dlink
->die
, pp
->function
) == 0) {
650 if (pp
->line
) { /* Function relative line */
651 pf
->fno
= die_get_decl_file(dlink
->die
);
652 pf
->lno
= die_get_decl_line(dlink
->die
)
654 find_probe_point_by_line(pf
);
657 if (die_inlined_subprogram(dlink
->die
)) {
658 /* Inlined function, save it. */
659 ret
= dwarf_die_CU_offset(dlink
->die
,
662 DIE_IF(ret
!= DW_DLV_OK
);
663 pr_debug("inline definition offset %lld\n",
665 return 0; /* Continue to search */
667 /* Get probe address */
668 pf
->addr
= die_get_entrypc(dlink
->die
);
669 pf
->addr
+= pp
->offset
;
670 /* TODO: Check the address in this function */
671 show_probe_point(dlink
->die
, pp
->offset
, pf
);
672 return 1; /* Exit; no same symbol in this CU. */
674 } else if (tag
== DW_TAG_inlined_subroutine
&& pf
->inl_offs
) {
675 if (die_get_abstract_origin(dlink
->die
) == pf
->inl_offs
) {
676 /* Get probe address */
677 pf
->addr
= die_get_entrypc(dlink
->die
);
678 pf
->addr
+= pp
->offset
;
679 pr_debug("found inline addr: 0x%llx\n", pf
->addr
);
680 /* Inlined function. Get a real subprogram */
681 for (lk
= dlink
->parent
; lk
!= NULL
; lk
= lk
->parent
) {
683 dwarf_tag(lk
->die
, &tag
, &__dw_error
);
684 DIE_IF(ret
== DW_DLV_ERROR
);
685 if (tag
== DW_TAG_subprogram
&&
686 !die_inlined_subprogram(lk
->die
))
689 die("Failed to find real subprogram.");
691 /* Get offset from subprogram */
692 ret
= die_within_subprogram(lk
->die
, pf
->addr
, &offs
);
694 show_probe_point(lk
->die
, offs
, pf
);
695 /* Continue to search */
701 static void find_probe_point_by_func(struct probe_finder
*pf
)
703 search_die_from_children(pf
->cu_die
, probefunc_callback
, pf
);
706 /* Find a probe point */
707 int find_probe_point(int fd
, struct probe_point
*pp
)
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
};
714 ret
= dwarf_init(fd
, DW_DLC_READ
, 0, 0, &__dw_debug
, &__dw_error
);
715 if (ret
!= DW_DLV_OK
)
719 while (++cu_number
) {
720 /* Search CU (Compilation Unit) */
721 ret
= dwarf_next_cu_header(__dw_debug
, NULL
, NULL
, NULL
,
722 &addr_size
, &next_cuh
, &__dw_error
);
723 DIE_IF(ret
== DW_DLV_ERROR
);
724 if (ret
== DW_DLV_NO_ENTRY
)
727 /* Get the DIE(Debugging Information Entry) of this CU */
728 ret
= dwarf_siblingof(__dw_debug
, 0, &pf
.cu_die
, &__dw_error
);
729 DIE_IF(ret
!= DW_DLV_OK
);
731 /* Check if target file is included. */
733 pf
.fno
= cu_find_fileno(pf
.cu_die
, pp
->file
);
735 if (!pp
->file
|| pf
.fno
) {
736 /* Save CU base address (for frame_base) */
737 ret
= dwarf_lowpc(pf
.cu_die
, &pf
.cu_base
, &__dw_error
);
738 DIE_IF(ret
== DW_DLV_ERROR
);
739 if (ret
== DW_DLV_NO_ENTRY
)
742 find_probe_point_by_func(&pf
);
745 find_probe_point_by_line(&pf
);
748 dwarf_dealloc(__dw_debug
, pf
.cu_die
, DW_DLA_DIE
);
750 ret
= dwarf_finish(__dw_debug
, &__dw_error
);
751 DIE_IF(ret
!= DW_DLV_OK
);
757 static void line_range_add_line(struct line_range
*lr
, unsigned int line
)
759 struct line_node
*ln
;
762 /* Reverse search, because new line will be the last one */
763 list_for_each_entry_reverse(ln
, &lr
->line_list
, list
) {
764 if (ln
->line
< line
) {
767 } else if (ln
->line
== line
) /* Already exist */
770 /* List is empty, or the smallest entry */
773 pr_debug("Debug: add a line %u\n", line
);
774 ln
= zalloc(sizeof(struct line_node
));
777 INIT_LIST_HEAD(&ln
->list
);
778 list_add(&ln
->list
, p
);
781 /* Find line range from its line number */
782 static void find_line_range_by_line(struct line_finder
*lf
)
786 Dwarf_Unsigned lineno
= 0;
791 INIT_LIST_HEAD(&lf
->lr
->line_list
);
792 ret
= dwarf_srclines(lf
->cu_die
, &lines
, &cnt
, &__dw_error
);
793 DIE_IF(ret
!= DW_DLV_OK
);
795 for (i
= 0; i
< cnt
; i
++) {
796 ret
= dwarf_line_srcfileno(lines
[i
], &fno
, &__dw_error
);
797 DIE_IF(ret
!= DW_DLV_OK
);
801 ret
= dwarf_lineno(lines
[i
], &lineno
, &__dw_error
);
802 DIE_IF(ret
!= DW_DLV_OK
);
803 if (lf
->lno_s
> lineno
|| lf
->lno_e
< lineno
)
806 /* Filter line in the function address range */
807 if (lf
->addr_s
&& lf
->addr_e
) {
808 ret
= dwarf_lineaddr(lines
[i
], &addr
, &__dw_error
);
809 DIE_IF(ret
!= DW_DLV_OK
);
810 if (lf
->addr_s
> addr
|| lf
->addr_e
<= addr
)
813 line_range_add_line(lf
->lr
, (unsigned int)lineno
);
815 dwarf_srclines_dealloc(__dw_debug
, lines
, cnt
);
816 if (!list_empty(&lf
->lr
->line_list
))
820 /* Search function from function name */
821 static int linefunc_callback(struct die_link
*dlink
, void *data
)
823 struct line_finder
*lf
= (struct line_finder
*)data
;
824 struct line_range
*lr
= lf
->lr
;
828 ret
= dwarf_tag(dlink
->die
, &tag
, &__dw_error
);
829 DIE_IF(ret
== DW_DLV_ERROR
);
830 if (tag
== DW_TAG_subprogram
&&
831 die_compare_name(dlink
->die
, lr
->function
) == 0) {
832 /* Get the address range of this function */
833 ret
= dwarf_highpc(dlink
->die
, &lf
->addr_e
, &__dw_error
);
834 if (ret
== DW_DLV_OK
)
835 ret
= dwarf_lowpc(dlink
->die
, &lf
->addr_s
, &__dw_error
);
836 DIE_IF(ret
== DW_DLV_ERROR
);
837 if (ret
== DW_DLV_NO_ENTRY
) {
842 lf
->fno
= die_get_decl_file(dlink
->die
);
843 lr
->offset
= die_get_decl_line(dlink
->die
);;
844 lf
->lno_s
= lr
->offset
+ lr
->start
;
846 lf
->lno_e
= (Dwarf_Unsigned
)-1;
848 lf
->lno_e
= lr
->offset
+ lr
->end
;
849 lr
->start
= lf
->lno_s
;
851 find_line_range_by_line(lf
);
857 static void find_line_range_by_func(struct line_finder
*lf
)
859 search_die_from_children(lf
->cu_die
, linefunc_callback
, lf
);
862 int find_line_range(int fd
, struct line_range
*lr
)
864 Dwarf_Half addr_size
= 0;
865 Dwarf_Unsigned next_cuh
= 0;
867 struct line_finder lf
= {.lr
= lr
};
869 ret
= dwarf_init(fd
, DW_DLC_READ
, 0, 0, &__dw_debug
, &__dw_error
);
870 if (ret
!= DW_DLV_OK
)
874 /* Search CU (Compilation Unit) */
875 ret
= dwarf_next_cu_header(__dw_debug
, NULL
, NULL
, NULL
,
876 &addr_size
, &next_cuh
, &__dw_error
);
877 DIE_IF(ret
== DW_DLV_ERROR
);
878 if (ret
== DW_DLV_NO_ENTRY
)
881 /* Get the DIE(Debugging Information Entry) of this CU */
882 ret
= dwarf_siblingof(__dw_debug
, 0, &lf
.cu_die
, &__dw_error
);
883 DIE_IF(ret
!= DW_DLV_OK
);
885 /* Check if target file is included. */
887 lf
.fno
= cu_find_fileno(lf
.cu_die
, lr
->file
);
889 if (!lr
->file
|| lf
.fno
) {
891 find_line_range_by_func(&lf
);
893 lf
.lno_s
= lr
->start
;
895 lf
.lno_e
= (Dwarf_Unsigned
)-1;
898 find_line_range_by_line(&lf
);
900 /* Get the real file path */
902 cu_get_filename(lf
.cu_die
, lf
.fno
, &lr
->path
);
904 dwarf_dealloc(__dw_debug
, lf
.cu_die
, DW_DLA_DIE
);
906 ret
= dwarf_finish(__dw_debug
, &__dw_error
);
907 DIE_IF(ret
!= DW_DLV_OK
);