1*16cef5f7SJoseph Mingrone /*
2*16cef5f7SJoseph Mingrone * Redistribution and use in source and binary forms, with or without
3*16cef5f7SJoseph Mingrone * modification, are permitted provided that: (1) source code
4*16cef5f7SJoseph Mingrone * distributions retain the above copyright notice and this paragraph
5*16cef5f7SJoseph Mingrone * in its entirety, and (2) distributions including binary code include
6*16cef5f7SJoseph Mingrone * the above copyright notice and this paragraph in its entirety in
7*16cef5f7SJoseph Mingrone * the documentation or other materials provided with the distribution.
8*16cef5f7SJoseph Mingrone * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9*16cef5f7SJoseph Mingrone * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10*16cef5f7SJoseph Mingrone * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11*16cef5f7SJoseph Mingrone * FOR A PARTICULAR PURPOSE.
12*16cef5f7SJoseph Mingrone */
13*16cef5f7SJoseph Mingrone
14*16cef5f7SJoseph Mingrone #include <stdio.h>
15*16cef5f7SJoseph Mingrone #include <string.h>
16*16cef5f7SJoseph Mingrone #include <stdlib.h>
17*16cef5f7SJoseph Mingrone #include <unistd.h>
18*16cef5f7SJoseph Mingrone #include <bfd.h>
19*16cef5f7SJoseph Mingrone
20*16cef5f7SJoseph Mingrone /*
21*16cef5f7SJoseph Mingrone * Generate instrumentation calls for entry and exit to functions.
22*16cef5f7SJoseph Mingrone * Just after function entry and just before function exit, the
23*16cef5f7SJoseph Mingrone * following profiling functions are called with the address of the
24*16cef5f7SJoseph Mingrone * current function and its call site (currently not use).
25*16cef5f7SJoseph Mingrone *
26*16cef5f7SJoseph Mingrone * The attribute 'no_instrument_function' causes this instrumentation is
27*16cef5f7SJoseph Mingrone * not done.
28*16cef5f7SJoseph Mingrone *
29*16cef5f7SJoseph Mingrone * These profiling functions call print_debug(). This function prints the
30*16cef5f7SJoseph Mingrone * current function name with indentation and call level.
31*16cef5f7SJoseph Mingrone * If entering in a function it prints also the calling function name with
32*16cef5f7SJoseph Mingrone * file name and line number.
33*16cef5f7SJoseph Mingrone *
34*16cef5f7SJoseph Mingrone * If the environment variable INSTRUMENT is
35*16cef5f7SJoseph Mingrone * unset or set to an empty string, print nothing, like with no instrumentation
36*16cef5f7SJoseph Mingrone * set to "all" or "a", print all the functions names
37*16cef5f7SJoseph Mingrone * set to "global" or "g", print only the global functions names
38*16cef5f7SJoseph Mingrone */
39*16cef5f7SJoseph Mingrone
40*16cef5f7SJoseph Mingrone #define ND_NO_INSTRUMENT __attribute__((no_instrument_function))
41*16cef5f7SJoseph Mingrone
42*16cef5f7SJoseph Mingrone /* Store the function call level, used also in pretty_print_packet() */
43*16cef5f7SJoseph Mingrone extern int profile_func_level;
44*16cef5f7SJoseph Mingrone int profile_func_level = -1;
45*16cef5f7SJoseph Mingrone
46*16cef5f7SJoseph Mingrone typedef enum {
47*16cef5f7SJoseph Mingrone ENTER,
48*16cef5f7SJoseph Mingrone EXIT
49*16cef5f7SJoseph Mingrone } action_type;
50*16cef5f7SJoseph Mingrone
51*16cef5f7SJoseph Mingrone void __cyg_profile_func_enter(void *this_fn, void *call_site) ND_NO_INSTRUMENT;
52*16cef5f7SJoseph Mingrone
53*16cef5f7SJoseph Mingrone void __cyg_profile_func_exit(void *this_fn, void *call_site) ND_NO_INSTRUMENT;
54*16cef5f7SJoseph Mingrone
55*16cef5f7SJoseph Mingrone static void print_debug(void *this_fn, void *call_site, action_type action)
56*16cef5f7SJoseph Mingrone ND_NO_INSTRUMENT;
57*16cef5f7SJoseph Mingrone
58*16cef5f7SJoseph Mingrone void
__cyg_profile_func_enter(void * this_fn,void * call_site)59*16cef5f7SJoseph Mingrone __cyg_profile_func_enter(void *this_fn, void *call_site)
60*16cef5f7SJoseph Mingrone {
61*16cef5f7SJoseph Mingrone print_debug(this_fn, call_site, ENTER);
62*16cef5f7SJoseph Mingrone }
63*16cef5f7SJoseph Mingrone
64*16cef5f7SJoseph Mingrone void
__cyg_profile_func_exit(void * this_fn,void * call_site)65*16cef5f7SJoseph Mingrone __cyg_profile_func_exit(void *this_fn, void *call_site)
66*16cef5f7SJoseph Mingrone {
67*16cef5f7SJoseph Mingrone print_debug(this_fn, call_site, EXIT);
68*16cef5f7SJoseph Mingrone }
69*16cef5f7SJoseph Mingrone
print_debug(void * this_fn,void * call_site,action_type action)70*16cef5f7SJoseph Mingrone static void print_debug(void *this_fn, void *call_site, action_type action)
71*16cef5f7SJoseph Mingrone {
72*16cef5f7SJoseph Mingrone static bfd* abfd;
73*16cef5f7SJoseph Mingrone static asymbol **symtab;
74*16cef5f7SJoseph Mingrone static long symcount;
75*16cef5f7SJoseph Mingrone static asection *text;
76*16cef5f7SJoseph Mingrone static bfd_vma vma;
77*16cef5f7SJoseph Mingrone static int instrument_set;
78*16cef5f7SJoseph Mingrone static int instrument_off;
79*16cef5f7SJoseph Mingrone static int instrument_global;
80*16cef5f7SJoseph Mingrone
81*16cef5f7SJoseph Mingrone if (!instrument_set) {
82*16cef5f7SJoseph Mingrone static char *instrument_type;
83*16cef5f7SJoseph Mingrone
84*16cef5f7SJoseph Mingrone /* Get the configuration environment variable INSTRUMENT value if any */
85*16cef5f7SJoseph Mingrone instrument_type = getenv("INSTRUMENT");
86*16cef5f7SJoseph Mingrone /* unset or set to an empty string ? */
87*16cef5f7SJoseph Mingrone if (instrument_type == NULL ||
88*16cef5f7SJoseph Mingrone !strncmp(instrument_type, "", sizeof(""))) {
89*16cef5f7SJoseph Mingrone instrument_off = 1;
90*16cef5f7SJoseph Mingrone } else {
91*16cef5f7SJoseph Mingrone /* set to "global" or "g" ? */
92*16cef5f7SJoseph Mingrone if (!strncmp(instrument_type, "global", sizeof("global")) ||
93*16cef5f7SJoseph Mingrone !strncmp(instrument_type, "g", sizeof("g")))
94*16cef5f7SJoseph Mingrone instrument_global = 1;
95*16cef5f7SJoseph Mingrone else if (strncmp(instrument_type, "all", sizeof("all")) &&
96*16cef5f7SJoseph Mingrone strncmp(instrument_type, "a", sizeof("a"))) {
97*16cef5f7SJoseph Mingrone fprintf(stderr, "INSTRUMENT can be only \"\", \"all\", \"a\", "
98*16cef5f7SJoseph Mingrone "\"global\" or \"g\".\n");
99*16cef5f7SJoseph Mingrone exit(1);
100*16cef5f7SJoseph Mingrone }
101*16cef5f7SJoseph Mingrone }
102*16cef5f7SJoseph Mingrone instrument_set = 1;
103*16cef5f7SJoseph Mingrone }
104*16cef5f7SJoseph Mingrone
105*16cef5f7SJoseph Mingrone if (instrument_off)
106*16cef5f7SJoseph Mingrone return;
107*16cef5f7SJoseph Mingrone
108*16cef5f7SJoseph Mingrone /* If no errors, this block should be executed one time */
109*16cef5f7SJoseph Mingrone if (!abfd) {
110*16cef5f7SJoseph Mingrone char pgm_name[1024];
111*16cef5f7SJoseph Mingrone long symsize;
112*16cef5f7SJoseph Mingrone
113*16cef5f7SJoseph Mingrone ssize_t ret = readlink("/proc/self/exe", pgm_name, sizeof(pgm_name));
114*16cef5f7SJoseph Mingrone if (ret == -1) {
115*16cef5f7SJoseph Mingrone perror("failed to find executable");
116*16cef5f7SJoseph Mingrone return;
117*16cef5f7SJoseph Mingrone }
118*16cef5f7SJoseph Mingrone if (ret == sizeof(pgm_name)) {
119*16cef5f7SJoseph Mingrone /* no space for the '\0' */
120*16cef5f7SJoseph Mingrone printf("truncation may have occurred\n");
121*16cef5f7SJoseph Mingrone return;
122*16cef5f7SJoseph Mingrone }
123*16cef5f7SJoseph Mingrone pgm_name[ret] = '\0';
124*16cef5f7SJoseph Mingrone
125*16cef5f7SJoseph Mingrone bfd_init();
126*16cef5f7SJoseph Mingrone
127*16cef5f7SJoseph Mingrone abfd = bfd_openr(pgm_name, NULL);
128*16cef5f7SJoseph Mingrone if (!abfd) {
129*16cef5f7SJoseph Mingrone bfd_perror("bfd_openr");
130*16cef5f7SJoseph Mingrone return;
131*16cef5f7SJoseph Mingrone }
132*16cef5f7SJoseph Mingrone
133*16cef5f7SJoseph Mingrone if (!bfd_check_format(abfd, bfd_object)) {
134*16cef5f7SJoseph Mingrone bfd_perror("bfd_check_format");
135*16cef5f7SJoseph Mingrone return;
136*16cef5f7SJoseph Mingrone }
137*16cef5f7SJoseph Mingrone
138*16cef5f7SJoseph Mingrone if((symsize = bfd_get_symtab_upper_bound(abfd)) == -1) {
139*16cef5f7SJoseph Mingrone bfd_perror("bfd_get_symtab_upper_bound");
140*16cef5f7SJoseph Mingrone return;
141*16cef5f7SJoseph Mingrone }
142*16cef5f7SJoseph Mingrone
143*16cef5f7SJoseph Mingrone symtab = (asymbol **)malloc((size_t)symsize);
144*16cef5f7SJoseph Mingrone symcount = bfd_canonicalize_symtab(abfd, symtab);
145*16cef5f7SJoseph Mingrone if (symcount < 0) {
146*16cef5f7SJoseph Mingrone free(symtab);
147*16cef5f7SJoseph Mingrone bfd_perror("bfd_canonicalize_symtab");
148*16cef5f7SJoseph Mingrone return;
149*16cef5f7SJoseph Mingrone }
150*16cef5f7SJoseph Mingrone
151*16cef5f7SJoseph Mingrone if ((text = bfd_get_section_by_name(abfd, ".text")) == NULL) {
152*16cef5f7SJoseph Mingrone bfd_perror("bfd_get_section_by_name");
153*16cef5f7SJoseph Mingrone return;
154*16cef5f7SJoseph Mingrone }
155*16cef5f7SJoseph Mingrone vma = text->vma;
156*16cef5f7SJoseph Mingrone }
157*16cef5f7SJoseph Mingrone
158*16cef5f7SJoseph Mingrone if (instrument_global) {
159*16cef5f7SJoseph Mingrone symbol_info syminfo;
160*16cef5f7SJoseph Mingrone int found;
161*16cef5f7SJoseph Mingrone long i;
162*16cef5f7SJoseph Mingrone
163*16cef5f7SJoseph Mingrone i = 0;
164*16cef5f7SJoseph Mingrone found = 0;
165*16cef5f7SJoseph Mingrone while (i < symcount && !found) {
166*16cef5f7SJoseph Mingrone bfd_get_symbol_info(abfd, symtab[i], &syminfo);
167*16cef5f7SJoseph Mingrone if ((void *)syminfo.value == this_fn) {
168*16cef5f7SJoseph Mingrone found = 1;
169*16cef5f7SJoseph Mingrone }
170*16cef5f7SJoseph Mingrone i++;
171*16cef5f7SJoseph Mingrone }
172*16cef5f7SJoseph Mingrone /* type == 'T' for a global function */
173*16cef5f7SJoseph Mingrone if (found == 1 && syminfo.type != 'T')
174*16cef5f7SJoseph Mingrone return;
175*16cef5f7SJoseph Mingrone }
176*16cef5f7SJoseph Mingrone
177*16cef5f7SJoseph Mingrone /* Current function */
178*16cef5f7SJoseph Mingrone if ((bfd_vma)this_fn < vma) {
179*16cef5f7SJoseph Mingrone printf("[ERROR address this_fn]");
180*16cef5f7SJoseph Mingrone } else {
181*16cef5f7SJoseph Mingrone const char *file;
182*16cef5f7SJoseph Mingrone const char *func;
183*16cef5f7SJoseph Mingrone unsigned int line;
184*16cef5f7SJoseph Mingrone
185*16cef5f7SJoseph Mingrone if (!bfd_find_nearest_line(abfd, text, symtab, (bfd_vma)this_fn - vma,
186*16cef5f7SJoseph Mingrone &file, &func, &line)) {
187*16cef5f7SJoseph Mingrone printf("[ERROR bfd_find_nearest_line this_fn]");
188*16cef5f7SJoseph Mingrone } else {
189*16cef5f7SJoseph Mingrone int i;
190*16cef5f7SJoseph Mingrone
191*16cef5f7SJoseph Mingrone if (action == ENTER)
192*16cef5f7SJoseph Mingrone profile_func_level += 1;
193*16cef5f7SJoseph Mingrone /* Indentation */
194*16cef5f7SJoseph Mingrone for (i = 0 ; i < profile_func_level ; i++)
195*16cef5f7SJoseph Mingrone putchar(' ');
196*16cef5f7SJoseph Mingrone if (action == ENTER)
197*16cef5f7SJoseph Mingrone printf("[>> ");
198*16cef5f7SJoseph Mingrone else
199*16cef5f7SJoseph Mingrone printf("[<< ");
200*16cef5f7SJoseph Mingrone /* Function name */
201*16cef5f7SJoseph Mingrone if (func == NULL || *func == '\0')
202*16cef5f7SJoseph Mingrone printf("???");
203*16cef5f7SJoseph Mingrone else
204*16cef5f7SJoseph Mingrone printf("%s", func);
205*16cef5f7SJoseph Mingrone printf(" (%d)", profile_func_level);
206*16cef5f7SJoseph Mingrone /* Print the "from" part except for the main function) */
207*16cef5f7SJoseph Mingrone if (action == ENTER && func != NULL &&
208*16cef5f7SJoseph Mingrone strncmp(func, "main", sizeof("main"))) {
209*16cef5f7SJoseph Mingrone /* Calling function */
210*16cef5f7SJoseph Mingrone if ((bfd_vma)call_site < vma) {
211*16cef5f7SJoseph Mingrone printf("[ERROR address call_site]");
212*16cef5f7SJoseph Mingrone } else {
213*16cef5f7SJoseph Mingrone if (!bfd_find_nearest_line(abfd, text, symtab,
214*16cef5f7SJoseph Mingrone (bfd_vma)call_site - vma, &file,
215*16cef5f7SJoseph Mingrone &func, &line)) {
216*16cef5f7SJoseph Mingrone printf("[ERROR bfd_find_nearest_line call_site]");
217*16cef5f7SJoseph Mingrone } else {
218*16cef5f7SJoseph Mingrone printf(" from ");
219*16cef5f7SJoseph Mingrone /* Function name */
220*16cef5f7SJoseph Mingrone if (func == NULL || *func == '\0')
221*16cef5f7SJoseph Mingrone printf("???");
222*16cef5f7SJoseph Mingrone else
223*16cef5f7SJoseph Mingrone printf("%s", func);
224*16cef5f7SJoseph Mingrone /* File name */
225*16cef5f7SJoseph Mingrone if (file == NULL || *file == '\0')
226*16cef5f7SJoseph Mingrone printf(" ??:");
227*16cef5f7SJoseph Mingrone else {
228*16cef5f7SJoseph Mingrone char *slashp = strrchr(file, '/');
229*16cef5f7SJoseph Mingrone if (slashp != NULL)
230*16cef5f7SJoseph Mingrone file = slashp + 1;
231*16cef5f7SJoseph Mingrone printf(" %s:", file);
232*16cef5f7SJoseph Mingrone }
233*16cef5f7SJoseph Mingrone /* Line number */
234*16cef5f7SJoseph Mingrone if (line == 0)
235*16cef5f7SJoseph Mingrone printf("?");
236*16cef5f7SJoseph Mingrone else
237*16cef5f7SJoseph Mingrone printf("%u", line);
238*16cef5f7SJoseph Mingrone printf("]");
239*16cef5f7SJoseph Mingrone }
240*16cef5f7SJoseph Mingrone }
241*16cef5f7SJoseph Mingrone }
242*16cef5f7SJoseph Mingrone putchar('\n');
243*16cef5f7SJoseph Mingrone if (action == EXIT)
244*16cef5f7SJoseph Mingrone profile_func_level -= 1;
245*16cef5f7SJoseph Mingrone }
246*16cef5f7SJoseph Mingrone }
247*16cef5f7SJoseph Mingrone fflush(stdout);
248*16cef5f7SJoseph Mingrone }
249*16cef5f7SJoseph Mingrone
250*16cef5f7SJoseph Mingrone /* vi: set tabstop=4 softtabstop=0 shiftwidth=4 smarttab autoindent : */
251