Path: blob/main/contrib/libpcap/instrument-functions.c
178435 views
/*1* Redistribution and use in source and binary forms, with or without2* modification, are permitted provided that: (1) source code3* distributions retain the above copyright notice and this paragraph4* in its entirety, and (2) distributions including binary code include5* the above copyright notice and this paragraph in its entirety in6* the documentation or other materials provided with the distribution.7* THIS SOFTWARE IS PROVIDED ``AS IS'' AND8* WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT9* LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS10* FOR A PARTICULAR PURPOSE.11*/1213#include <stdio.h>14#include <string.h>15#include <stdlib.h>16#include <unistd.h>17#include <bfd.h>1819/*20* Generate instrumentation calls for entry and exit to functions.21* Just after function entry and just before function exit, the22* following profiling functions are called with the address of the23* current function and its call site (currently not use).24*25* The attribute 'no_instrument_function' causes this instrumentation is26* not done.27*28* These profiling functions call print_debug(). This function prints the29* current function name with indentation and call level.30* If entering in a function it prints also the calling function name with31* file name and line number.32*33* If the environment variable INSTRUMENT is34* unset or set to an empty string, print nothing, like with no instrumentation35* set to "all" or "a", print all the functions names36* set to "global" or "g", print only the global functions names37*/3839#define ND_NO_INSTRUMENT __attribute__((no_instrument_function))4041/* Store the function call level, used also in pretty_print_packet() */42extern int profile_func_level;43int profile_func_level = -1;4445typedef enum {46ENTER,47EXIT48} action_type;4950void __cyg_profile_func_enter(void *this_fn, void *call_site) ND_NO_INSTRUMENT;5152void __cyg_profile_func_exit(void *this_fn, void *call_site) ND_NO_INSTRUMENT;5354static void print_debug(void *this_fn, void *call_site, action_type action)55ND_NO_INSTRUMENT;5657void58__cyg_profile_func_enter(void *this_fn, void *call_site)59{60print_debug(this_fn, call_site, ENTER);61}6263void64__cyg_profile_func_exit(void *this_fn, void *call_site)65{66print_debug(this_fn, call_site, EXIT);67}6869static void print_debug(void *this_fn, void *call_site, action_type action)70{71static bfd* abfd;72static asymbol **symtab;73static long symcount;74static asection *text;75static bfd_vma vma;76static int instrument_set;77static int instrument_off;78static int instrument_global;7980if (!instrument_set) {81static char *instrument_type;8283/* Get the configuration environment variable INSTRUMENT value if any */84instrument_type = getenv("INSTRUMENT");85/* unset or set to an empty string ? */86if (instrument_type == NULL ||87!strncmp(instrument_type, "", sizeof(""))) {88instrument_off = 1;89} else {90/* set to "global" or "g" ? */91if (!strncmp(instrument_type, "global", sizeof("global")) ||92!strncmp(instrument_type, "g", sizeof("g")))93instrument_global = 1;94else if (strncmp(instrument_type, "all", sizeof("all")) &&95strncmp(instrument_type, "a", sizeof("a"))) {96fprintf(stderr, "INSTRUMENT can be only \"\", \"all\", \"a\", "97"\"global\" or \"g\".\n");98exit(1);99}100}101instrument_set = 1;102}103104if (instrument_off)105return;106107/* If no errors, this block should be executed one time */108if (!abfd) {109char pgm_name[1024];110long symsize;111112ssize_t ret = readlink("/proc/self/exe", pgm_name, sizeof(pgm_name));113if (ret == -1) {114perror("failed to find executable");115return;116}117if (ret == sizeof(pgm_name)) {118/* no space for the '\0' */119printf("truncation may have occurred\n");120return;121}122pgm_name[ret] = '\0';123124bfd_init();125126abfd = bfd_openr(pgm_name, NULL);127if (!abfd) {128bfd_perror("bfd_openr");129return;130}131132if (!bfd_check_format(abfd, bfd_object)) {133bfd_perror("bfd_check_format");134return;135}136137if((symsize = bfd_get_symtab_upper_bound(abfd)) == -1) {138bfd_perror("bfd_get_symtab_upper_bound");139return;140}141142symtab = (asymbol **)malloc((size_t)symsize);143symcount = bfd_canonicalize_symtab(abfd, symtab);144if (symcount < 0) {145free(symtab);146bfd_perror("bfd_canonicalize_symtab");147return;148}149150if ((text = bfd_get_section_by_name(abfd, ".text")) == NULL) {151bfd_perror("bfd_get_section_by_name");152return;153}154vma = text->vma;155}156157if (instrument_global) {158symbol_info syminfo;159int found;160long i;161162i = 0;163found = 0;164while (i < symcount && !found) {165bfd_get_symbol_info(abfd, symtab[i], &syminfo);166if ((void *)syminfo.value == this_fn) {167found = 1;168}169i++;170}171/* type == 'T' for a global function */172if (found == 1 && syminfo.type != 'T')173return;174}175176/* Current function */177if ((bfd_vma)this_fn < vma) {178printf("[ERROR address this_fn]");179} else {180const char *file;181const char *func;182unsigned int line;183184if (!bfd_find_nearest_line(abfd, text, symtab, (bfd_vma)this_fn - vma,185&file, &func, &line)) {186printf("[ERROR bfd_find_nearest_line this_fn]");187} else {188int i;189190if (action == ENTER)191profile_func_level += 1;192/* Indentation */193for (i = 0 ; i < profile_func_level ; i++)194putchar(' ');195if (action == ENTER)196printf("[>> ");197else198printf("[<< ");199/* Function name */200if (func == NULL || *func == '\0')201printf("???");202else203printf("%s", func);204printf(" (%d)", profile_func_level);205/* Print the "from" part except for the main function) */206if (action == ENTER && func != NULL &&207strncmp(func, "main", sizeof("main"))) {208/* Calling function */209if ((bfd_vma)call_site < vma) {210printf("[ERROR address call_site]");211} else {212if (!bfd_find_nearest_line(abfd, text, symtab,213(bfd_vma)call_site - vma, &file,214&func, &line)) {215printf("[ERROR bfd_find_nearest_line call_site]");216} else {217printf(" from ");218/* Function name */219if (func == NULL || *func == '\0')220printf("???");221else222printf("%s", func);223/* File name */224if (file == NULL || *file == '\0')225printf(" ??:");226else {227char *slashp = strrchr(file, '/');228if (slashp != NULL)229file = slashp + 1;230printf(" %s:", file);231}232/* Line number */233if (line == 0)234printf("?");235else236printf("%u", line);237printf("]");238}239}240}241putchar('\n');242if (action == EXIT)243profile_func_level -= 1;244}245}246fflush(stdout);247}248249/* vi: set tabstop=4 softtabstop=0 shiftwidth=4 smarttab autoindent : */250251252