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 /* Compare diename and tname */
144 static int die_compare_name(Dwarf_Die dw_die
, const char *tname
)
148 ret
= dwarf_diename(dw_die
, &name
, &__dw_error
);
149 DIE_IF(ret
== DW_DLV_ERROR
);
150 if (ret
== DW_DLV_OK
) {
151 ret
= strcmp(tname
, name
);
152 dwarf_dealloc(__dw_debug
, name
, DW_DLA_STRING
);
158 /* Check the address is in the subprogram(function). */
159 static int die_within_subprogram(Dwarf_Die sp_die
, Dwarf_Addr addr
,
162 Dwarf_Addr lopc
, hipc
;
165 /* TODO: check ranges */
166 ret
= dwarf_lowpc(sp_die
, &lopc
, &__dw_error
);
167 DIE_IF(ret
== DW_DLV_ERROR
);
168 if (ret
== DW_DLV_NO_ENTRY
)
170 ret
= dwarf_highpc(sp_die
, &hipc
, &__dw_error
);
171 DIE_IF(ret
!= DW_DLV_OK
);
172 if (lopc
<= addr
&& addr
< hipc
) {
179 /* Check the die is inlined function */
180 static Dwarf_Bool
die_inlined_subprogram(Dwarf_Die dw_die
)
182 /* TODO: check strictly */
186 ret
= dwarf_hasattr(dw_die
, DW_AT_inline
, &inl
, &__dw_error
);
187 DIE_IF(ret
== DW_DLV_ERROR
);
191 /* Get the offset of abstruct_origin */
192 static Dwarf_Off
die_get_abstract_origin(Dwarf_Die dw_die
)
194 Dwarf_Attribute attr
;
198 ret
= dwarf_attr(dw_die
, DW_AT_abstract_origin
, &attr
, &__dw_error
);
199 DIE_IF(ret
!= DW_DLV_OK
);
200 ret
= dwarf_formref(attr
, &cu_offs
, &__dw_error
);
201 DIE_IF(ret
!= DW_DLV_OK
);
202 dwarf_dealloc(__dw_debug
, attr
, DW_DLA_ATTR
);
206 /* Get entry pc(or low pc, 1st entry of ranges) of the die */
207 static Dwarf_Addr
die_get_entrypc(Dwarf_Die dw_die
)
209 Dwarf_Attribute attr
;
212 Dwarf_Ranges
*ranges
;
216 /* Try to get entry pc */
217 ret
= dwarf_attr(dw_die
, DW_AT_entry_pc
, &attr
, &__dw_error
);
218 DIE_IF(ret
== DW_DLV_ERROR
);
219 if (ret
== DW_DLV_OK
) {
220 ret
= dwarf_formaddr(attr
, &addr
, &__dw_error
);
221 DIE_IF(ret
!= DW_DLV_OK
);
222 dwarf_dealloc(__dw_debug
, attr
, DW_DLA_ATTR
);
226 /* Try to get low pc */
227 ret
= dwarf_lowpc(dw_die
, &addr
, &__dw_error
);
228 DIE_IF(ret
== DW_DLV_ERROR
);
229 if (ret
== DW_DLV_OK
)
232 /* Try to get ranges */
233 ret
= dwarf_attr(dw_die
, DW_AT_ranges
, &attr
, &__dw_error
);
234 DIE_IF(ret
!= DW_DLV_OK
);
235 ret
= dwarf_formref(attr
, &offs
, &__dw_error
);
236 DIE_IF(ret
!= DW_DLV_OK
);
237 ret
= dwarf_get_ranges(__dw_debug
, offs
, &ranges
, &cnt
, NULL
,
239 DIE_IF(ret
!= DW_DLV_OK
);
240 addr
= ranges
[0].dwr_addr1
;
241 dwarf_ranges_dealloc(__dw_debug
, ranges
, cnt
);
246 * Search a Die from Die tree.
247 * Note: cur_link->die should be deallocated in this function.
249 static int __search_die_tree(struct die_link
*cur_link
,
250 int (*die_cb
)(struct die_link
*, void *),
254 struct die_link new_link
;
260 /* Check current die */
261 while (!(ret
= die_cb(cur_link
, data
))) {
262 /* Check child die */
263 ret
= dwarf_child(cur_link
->die
, &new_die
, &__dw_error
);
264 DIE_IF(ret
== DW_DLV_ERROR
);
265 if (ret
== DW_DLV_OK
) {
266 new_link
.parent
= cur_link
;
267 new_link
.die
= new_die
;
268 ret
= __search_die_tree(&new_link
, die_cb
, data
);
273 /* Move to next sibling */
274 ret
= dwarf_siblingof(__dw_debug
, cur_link
->die
, &new_die
,
276 DIE_IF(ret
== DW_DLV_ERROR
);
277 dwarf_dealloc(__dw_debug
, cur_link
->die
, DW_DLA_DIE
);
278 cur_link
->die
= new_die
;
279 if (ret
== DW_DLV_NO_ENTRY
)
282 dwarf_dealloc(__dw_debug
, cur_link
->die
, DW_DLA_DIE
);
286 /* Search a die in its children's die tree */
287 static int search_die_from_children(Dwarf_Die parent_die
,
288 int (*die_cb
)(struct die_link
*, void *),
291 struct die_link new_link
;
294 new_link
.parent
= NULL
;
295 ret
= dwarf_child(parent_die
, &new_link
.die
, &__dw_error
);
296 DIE_IF(ret
== DW_DLV_ERROR
);
297 if (ret
== DW_DLV_OK
)
298 return __search_die_tree(&new_link
, die_cb
, data
);
303 /* Find a locdesc corresponding to the address */
304 static int attr_get_locdesc(Dwarf_Attribute attr
, Dwarf_Locdesc
*desc
,
308 Dwarf_Locdesc
**llbuf
;
311 ret
= dwarf_loclist_n(attr
, &llbuf
, &lcnt
, &__dw_error
);
312 DIE_IF(ret
!= DW_DLV_OK
);
313 ret
= DW_DLV_NO_ENTRY
;
314 for (i
= 0; i
< lcnt
; ++i
) {
315 if (llbuf
[i
]->ld_lopc
<= addr
&&
316 llbuf
[i
]->ld_hipc
> addr
) {
317 memcpy(desc
, llbuf
[i
], sizeof(Dwarf_Locdesc
));
319 malloc(sizeof(Dwarf_Loc
) * llbuf
[i
]->ld_cents
);
320 DIE_IF(desc
->ld_s
== NULL
);
321 memcpy(desc
->ld_s
, llbuf
[i
]->ld_s
,
322 sizeof(Dwarf_Loc
) * llbuf
[i
]->ld_cents
);
326 dwarf_dealloc(__dw_debug
, llbuf
[i
]->ld_s
, DW_DLA_LOC_BLOCK
);
327 dwarf_dealloc(__dw_debug
, llbuf
[i
], DW_DLA_LOCDESC
);
330 for (; i
< lcnt
; ++i
) {
331 dwarf_dealloc(__dw_debug
, llbuf
[i
]->ld_s
, DW_DLA_LOC_BLOCK
);
332 dwarf_dealloc(__dw_debug
, llbuf
[i
], DW_DLA_LOCDESC
);
334 dwarf_dealloc(__dw_debug
, llbuf
, DW_DLA_LIST
);
338 /* Get decl_file attribute value (file number) */
339 static Dwarf_Unsigned
die_get_decl_file(Dwarf_Die sp_die
)
341 Dwarf_Attribute attr
;
345 ret
= dwarf_attr(sp_die
, DW_AT_decl_file
, &attr
, &__dw_error
);
346 DIE_IF(ret
!= DW_DLV_OK
);
347 dwarf_formudata(attr
, &fno
, &__dw_error
);
348 DIE_IF(ret
!= DW_DLV_OK
);
349 dwarf_dealloc(__dw_debug
, attr
, DW_DLA_ATTR
);
353 /* Get decl_line attribute value (line number) */
354 static Dwarf_Unsigned
die_get_decl_line(Dwarf_Die sp_die
)
356 Dwarf_Attribute attr
;
360 ret
= dwarf_attr(sp_die
, DW_AT_decl_line
, &attr
, &__dw_error
);
361 DIE_IF(ret
!= DW_DLV_OK
);
362 dwarf_formudata(attr
, &lno
, &__dw_error
);
363 DIE_IF(ret
!= DW_DLV_OK
);
364 dwarf_dealloc(__dw_debug
, attr
, DW_DLA_ATTR
);
369 * Probe finder related functions
372 /* Show a location */
373 static void show_location(Dwarf_Loc
*loc
, struct probe_finder
*pf
)
383 /* If this is based on frame buffer, set the offset */
384 if (op
== DW_OP_fbreg
) {
386 offs
= (Dwarf_Signed
)loc
->lr_number
;
387 op
= pf
->fbloc
.ld_s
[0].lr_atom
;
388 loc
= &pf
->fbloc
.ld_s
[0];
392 if (op
>= DW_OP_breg0
&& op
<= DW_OP_breg31
) {
393 regn
= op
- DW_OP_breg0
;
394 offs
+= (Dwarf_Signed
)loc
->lr_number
;
396 } else if (op
>= DW_OP_reg0
&& op
<= DW_OP_reg31
) {
397 regn
= op
- DW_OP_reg0
;
398 } else if (op
== DW_OP_bregx
) {
399 regn
= loc
->lr_number
;
400 offs
+= (Dwarf_Signed
)loc
->lr_number2
;
402 } else if (op
== DW_OP_regx
) {
403 regn
= loc
->lr_number
;
405 die("Dwarf_OP %d is not supported.\n", op
);
407 regs
= get_arch_regstr(regn
);
409 die("%lld exceeds max register number.\n", regn
);
412 ret
= snprintf(pf
->buf
, pf
->len
,
413 " %s=%+lld(%s)", pf
->var
, offs
, regs
);
415 ret
= snprintf(pf
->buf
, pf
->len
, " %s=%s", pf
->var
, regs
);
417 DIE_IF(ret
>= pf
->len
);
420 /* Show a variables in kprobe event format */
421 static void show_variable(Dwarf_Die vr_die
, struct probe_finder
*pf
)
423 Dwarf_Attribute attr
;
427 ret
= dwarf_attr(vr_die
, DW_AT_location
, &attr
, &__dw_error
);
428 if (ret
!= DW_DLV_OK
)
430 ret
= attr_get_locdesc(attr
, &ld
, (pf
->addr
- pf
->cu_base
));
431 if (ret
!= DW_DLV_OK
)
434 DIE_IF(ld
.ld_cents
!= 1);
435 show_location(&ld
.ld_s
[0], pf
);
437 dwarf_dealloc(__dw_debug
, attr
, DW_DLA_ATTR
);
440 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", pf
->var
);
444 static int variable_callback(struct die_link
*dlink
, void *data
)
446 struct probe_finder
*pf
= (struct probe_finder
*)data
;
450 ret
= dwarf_tag(dlink
->die
, &tag
, &__dw_error
);
451 DIE_IF(ret
== DW_DLV_ERROR
);
452 if ((tag
== DW_TAG_formal_parameter
||
453 tag
== DW_TAG_variable
) &&
454 (die_compare_name(dlink
->die
, pf
->var
) == 0)) {
455 show_variable(dlink
->die
, pf
);
458 /* TODO: Support struct members and arrays */
462 /* Find a variable in a subprogram die */
463 static void find_variable(Dwarf_Die sp_die
, struct probe_finder
*pf
)
467 if (!is_c_varname(pf
->var
)) {
468 /* Output raw parameters */
469 ret
= snprintf(pf
->buf
, pf
->len
, " %s", pf
->var
);
471 DIE_IF(ret
>= pf
->len
);
475 pr_debug("Searching '%s' variable in context.\n", pf
->var
);
476 /* Search child die for local variables and parameters. */
477 ret
= search_die_from_children(sp_die
, variable_callback
, pf
);
479 die("Failed to find '%s' in this function.\n", pf
->var
);
482 /* Get a frame base on the address */
483 static void get_current_frame_base(Dwarf_Die sp_die
, struct probe_finder
*pf
)
485 Dwarf_Attribute attr
;
488 ret
= dwarf_attr(sp_die
, DW_AT_frame_base
, &attr
, &__dw_error
);
489 DIE_IF(ret
!= DW_DLV_OK
);
490 ret
= attr_get_locdesc(attr
, &pf
->fbloc
, (pf
->addr
- pf
->cu_base
));
491 DIE_IF(ret
!= DW_DLV_OK
);
492 dwarf_dealloc(__dw_debug
, attr
, DW_DLA_ATTR
);
495 static void free_current_frame_base(struct probe_finder
*pf
)
497 free(pf
->fbloc
.ld_s
);
498 memset(&pf
->fbloc
, 0, sizeof(Dwarf_Locdesc
));
501 /* Show a probe point to output buffer */
502 static void show_probepoint(Dwarf_Die sp_die
, Dwarf_Signed offs
,
503 struct probe_finder
*pf
)
505 struct probe_point
*pp
= pf
->pp
;
507 char tmp
[MAX_PROBE_BUFFER
];
510 /* Output name of probe point */
511 ret
= dwarf_diename(sp_die
, &name
, &__dw_error
);
512 DIE_IF(ret
== DW_DLV_ERROR
);
513 if (ret
== DW_DLV_OK
) {
514 ret
= snprintf(tmp
, MAX_PROBE_BUFFER
, "%s+%u", name
,
516 /* Copy the function name if possible */
518 pp
->function
= strdup(name
);
521 dwarf_dealloc(__dw_debug
, name
, DW_DLA_STRING
);
523 /* This function has no name. */
524 ret
= snprintf(tmp
, MAX_PROBE_BUFFER
, "0x%llx", pf
->addr
);
526 /* TODO: Use _stext */
527 pp
->function
= strdup("");
528 pp
->offset
= (int)pf
->addr
;
532 DIE_IF(ret
>= MAX_PROBE_BUFFER
);
534 pr_debug("Probe point found: %s\n", tmp
);
536 /* Find each argument */
537 get_current_frame_base(sp_die
, pf
);
538 for (i
= 0; i
< pp
->nr_args
; i
++) {
539 pf
->var
= pp
->args
[i
];
541 pf
->len
= MAX_PROBE_BUFFER
- len
;
542 find_variable(sp_die
, pf
);
543 len
+= strlen(pf
->buf
);
545 free_current_frame_base(pf
);
547 pp
->probes
[pp
->found
] = strdup(tmp
);
551 static int probeaddr_callback(struct die_link
*dlink
, void *data
)
553 struct probe_finder
*pf
= (struct probe_finder
*)data
;
558 ret
= dwarf_tag(dlink
->die
, &tag
, &__dw_error
);
559 DIE_IF(ret
== DW_DLV_ERROR
);
560 /* Check the address is in this subprogram */
561 if (tag
== DW_TAG_subprogram
&&
562 die_within_subprogram(dlink
->die
, pf
->addr
, &offs
)) {
563 show_probepoint(dlink
->die
, offs
, pf
);
569 /* Find probe point from its line number */
570 static void find_by_line(struct probe_finder
*pf
)
572 Dwarf_Signed cnt
, i
, clm
;
574 Dwarf_Unsigned lineno
= 0;
579 ret
= dwarf_srclines(pf
->cu_die
, &lines
, &cnt
, &__dw_error
);
580 DIE_IF(ret
!= DW_DLV_OK
);
582 for (i
= 0; i
< cnt
; i
++) {
583 ret
= dwarf_line_srcfileno(lines
[i
], &fno
, &__dw_error
);
584 DIE_IF(ret
!= DW_DLV_OK
);
588 ret
= dwarf_lineno(lines
[i
], &lineno
, &__dw_error
);
589 DIE_IF(ret
!= DW_DLV_OK
);
590 if (lineno
!= pf
->lno
)
593 ret
= dwarf_lineoff(lines
[i
], &clm
, &__dw_error
);
594 DIE_IF(ret
!= DW_DLV_OK
);
596 ret
= dwarf_lineaddr(lines
[i
], &addr
, &__dw_error
);
597 DIE_IF(ret
!= DW_DLV_OK
);
598 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
599 (int)i
, (unsigned)lineno
, (int)clm
, addr
);
601 /* Search a real subprogram including this line, */
602 ret
= search_die_from_children(pf
->cu_die
,
603 probeaddr_callback
, pf
);
605 die("Probe point is not found in subprograms.\n");
606 /* Continuing, because target line might be inlined. */
608 dwarf_srclines_dealloc(__dw_debug
, lines
, cnt
);
611 /* Search function from function name */
612 static int probefunc_callback(struct die_link
*dlink
, void *data
)
614 struct probe_finder
*pf
= (struct probe_finder
*)data
;
615 struct probe_point
*pp
= pf
->pp
;
621 ret
= dwarf_tag(dlink
->die
, &tag
, &__dw_error
);
622 DIE_IF(ret
== DW_DLV_ERROR
);
623 if (tag
== DW_TAG_subprogram
) {
624 if (die_compare_name(dlink
->die
, pp
->function
) == 0) {
625 if (pp
->line
) { /* Function relative line */
626 pf
->fno
= die_get_decl_file(dlink
->die
);
627 pf
->lno
= die_get_decl_line(dlink
->die
)
632 if (die_inlined_subprogram(dlink
->die
)) {
633 /* Inlined function, save it. */
634 ret
= dwarf_die_CU_offset(dlink
->die
,
637 DIE_IF(ret
!= DW_DLV_OK
);
638 pr_debug("inline definition offset %lld\n",
640 return 0; /* Continue to search */
642 /* Get probe address */
643 pf
->addr
= die_get_entrypc(dlink
->die
);
644 pf
->addr
+= pp
->offset
;
645 /* TODO: Check the address in this function */
646 show_probepoint(dlink
->die
, pp
->offset
, pf
);
647 return 1; /* Exit; no same symbol in this CU. */
649 } else if (tag
== DW_TAG_inlined_subroutine
&& pf
->inl_offs
) {
650 if (die_get_abstract_origin(dlink
->die
) == pf
->inl_offs
) {
651 /* Get probe address */
652 pf
->addr
= die_get_entrypc(dlink
->die
);
653 pf
->addr
+= pp
->offset
;
654 pr_debug("found inline addr: 0x%llx\n", pf
->addr
);
655 /* Inlined function. Get a real subprogram */
656 for (lk
= dlink
->parent
; lk
!= NULL
; lk
= lk
->parent
) {
658 dwarf_tag(lk
->die
, &tag
, &__dw_error
);
659 DIE_IF(ret
== DW_DLV_ERROR
);
660 if (tag
== DW_TAG_subprogram
&&
661 !die_inlined_subprogram(lk
->die
))
664 die("Failed to find real subprogram.\n");
666 /* Get offset from subprogram */
667 ret
= die_within_subprogram(lk
->die
, pf
->addr
, &offs
);
669 show_probepoint(lk
->die
, offs
, pf
);
670 /* Continue to search */
676 static void find_by_func(struct probe_finder
*pf
)
678 search_die_from_children(pf
->cu_die
, probefunc_callback
, pf
);
681 /* Find a probe point */
682 int find_probepoint(int fd
, struct probe_point
*pp
)
684 Dwarf_Half addr_size
= 0;
685 Dwarf_Unsigned next_cuh
= 0;
686 int cu_number
= 0, ret
;
687 struct probe_finder pf
= {.pp
= pp
};
689 ret
= dwarf_init(fd
, DW_DLC_READ
, 0, 0, &__dw_debug
, &__dw_error
);
690 if (ret
!= DW_DLV_OK
)
694 while (++cu_number
) {
695 /* Search CU (Compilation Unit) */
696 ret
= dwarf_next_cu_header(__dw_debug
, NULL
, NULL
, NULL
,
697 &addr_size
, &next_cuh
, &__dw_error
);
698 DIE_IF(ret
== DW_DLV_ERROR
);
699 if (ret
== DW_DLV_NO_ENTRY
)
702 /* Get the DIE(Debugging Information Entry) of this CU */
703 ret
= dwarf_siblingof(__dw_debug
, 0, &pf
.cu_die
, &__dw_error
);
704 DIE_IF(ret
!= DW_DLV_OK
);
706 /* Check if target file is included. */
708 pf
.fno
= cu_find_fileno(pf
.cu_die
, pp
->file
);
710 if (!pp
->file
|| pf
.fno
) {
711 /* Save CU base address (for frame_base) */
712 ret
= dwarf_lowpc(pf
.cu_die
, &pf
.cu_base
, &__dw_error
);
713 DIE_IF(ret
== DW_DLV_ERROR
);
714 if (ret
== DW_DLV_NO_ENTRY
)
723 dwarf_dealloc(__dw_debug
, pf
.cu_die
, DW_DLA_DIE
);
725 ret
= dwarf_finish(__dw_debug
, &__dw_error
);
726 DIE_IF(ret
!= DW_DLV_OK
);