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