]>
The Tcpdump Group git mirrors - tcpdump/blob - instrument-functions.c
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that: (1) source code
4 * distributions retain the above copyright notice and this paragraph
5 * in its entirety, and (2) distributions including binary code include
6 * the above copyright notice and this paragraph in its entirety in
7 * the documentation or other materials provided with the distribution.
8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11 * FOR A PARTICULAR PURPOSE.
21 * Generate instrumentation calls for entry and exit to functions.
22 * Just after function entry and just before function exit, the
23 * following profiling functions are called with the address of the
24 * current function and its call site (currently not use).
26 * The attribute 'no_instrument_function' causes this instrumentation is
29 * These profiling functions call print_debug(). This function prints the
30 * current function name with indentation and call level.
31 * If entering in a function it prints also the calling function name with
32 * file name and line number.
34 * If the environment variable INSTRUMENT is
35 * unset or set to an empty string, print nothing, like with no instrumentation
36 * set to "all" or "a", print all the functions names
37 * set to "global" or "g", print only the global functions names
40 #define ND_NO_INSTRUMENT __attribute__((no_instrument_function))
42 /* Store the function call level, used also in pretty_print_packet() */
43 extern int profile_func_level
;
44 int profile_func_level
= -1;
51 void __cyg_profile_func_enter(void *this_fn
, void *call_site
) ND_NO_INSTRUMENT
;
53 void __cyg_profile_func_exit(void *this_fn
, void *call_site
) ND_NO_INSTRUMENT
;
55 static void print_debug(void *this_fn
, void *call_site
, action_type action
)
59 __cyg_profile_func_enter(void *this_fn
, void *call_site
)
61 print_debug(this_fn
, call_site
, ENTER
);
65 __cyg_profile_func_exit(void *this_fn
, void *call_site
)
67 print_debug(this_fn
, call_site
, EXIT
);
70 static void print_debug(void *this_fn
, void *call_site
, action_type action
)
73 static asymbol
**symtab
;
75 static asection
*text
;
77 static int instrument_set
;
78 static int instrument_off
;
79 static int instrument_global
;
81 if (!instrument_set
) {
82 static char *instrument_type
;
84 /* Get the configuration environment variable INSTRUMENT value if any */
85 instrument_type
= getenv("INSTRUMENT");
86 /* unset or set to an empty string ? */
87 if (instrument_type
== NULL
||
88 !strncmp(instrument_type
, "", sizeof(""))) {
91 /* set to "global" or "g" ? */
92 if (!strncmp(instrument_type
, "global", sizeof("global")) ||
93 !strncmp(instrument_type
, "g", sizeof("g")))
94 instrument_global
= 1;
95 else if (strncmp(instrument_type
, "all", sizeof("all")) &&
96 strncmp(instrument_type
, "a", sizeof("a"))) {
97 fprintf(stderr
, "INSTRUMENT can be only \"\", \"all\", \"a\", "
98 "\"global\" or \"g\".\n");
108 /* If no errors, this block should be executed one time */
113 ssize_t ret
= readlink("/proc/self/exe", pgm_name
, sizeof(pgm_name
));
115 perror("failed to find executable");
118 if (ret
== sizeof(pgm_name
)) {
119 /* no space for the '\0' */
120 printf("truncation may have occurred\n");
123 pgm_name
[ret
] = '\0';
127 abfd
= bfd_openr(pgm_name
, NULL
);
129 bfd_perror("bfd_openr");
133 if (!bfd_check_format(abfd
, bfd_object
)) {
134 bfd_perror("bfd_check_format");
138 if((symsize
= bfd_get_symtab_upper_bound(abfd
)) == -1) {
139 bfd_perror("bfd_get_symtab_upper_bound");
143 symtab
= (asymbol
**)malloc((size_t)symsize
);
144 symcount
= bfd_canonicalize_symtab(abfd
, symtab
);
147 bfd_perror("bfd_canonicalize_symtab");
151 if ((text
= bfd_get_section_by_name(abfd
, ".text")) == NULL
) {
152 bfd_perror("bfd_get_section_by_name");
158 if (instrument_global
) {
165 while (i
< symcount
&& !found
) {
166 bfd_get_symbol_info(abfd
, symtab
[i
], &syminfo
);
167 if ((void *)syminfo
.value
== this_fn
) {
172 /* type == 'T' for a global function */
173 if (found
== 1 && syminfo
.type
!= 'T')
177 /* Current function */
178 if ((bfd_vma
)this_fn
< vma
) {
179 printf("[ERROR address this_fn]");
185 if (!bfd_find_nearest_line(abfd
, text
, symtab
, (bfd_vma
)this_fn
- vma
,
186 &file
, &func
, &line
)) {
187 printf("[ERROR bfd_find_nearest_line this_fn]");
192 profile_func_level
+= 1;
194 for (i
= 0 ; i
< profile_func_level
; i
++)
201 if (func
== NULL
|| *func
== '\0')
205 printf(" (%d)", profile_func_level
);
206 /* Print the "from" part except for the main function) */
207 if (action
== ENTER
&& func
!= NULL
&&
208 strncmp(func
, "main", sizeof("main"))) {
209 /* Calling function */
210 if ((bfd_vma
)call_site
< vma
) {
211 printf("[ERROR address call_site]");
213 if (!bfd_find_nearest_line(abfd
, text
, symtab
,
214 (bfd_vma
)call_site
- vma
, &file
,
216 printf("[ERROR bfd_find_nearest_line call_site]");
220 if (func
== NULL
|| *func
== '\0')
225 if (file
== NULL
|| *file
== '\0')
228 char *slashp
= strrchr(file
, '/');
231 printf(" %s:", file
);
244 profile_func_level
-= 1;
250 /* vi: set tabstop=4 softtabstop=0 shiftwidth=4 smarttab autoindent : */