mirror of
https://github.com/the-tcpdump-group/tcpdump.git
synced 2024-11-23 18:14:29 +08:00
40f420cf06
The first is a long, comparison with the long 'symcount'. The second is a int, comparison with the int 'profile_func_level'. Moreover: Add a cast to silence the following warning: ./instrument-functions.c:143:31: warning: implicit conversion changes signedness: 'long' to 'unsigned long' [-Wsign-conversion] symtab = (asymbol **)malloc(symsize); ~~~~~~ ^~~~~~~ (symsize is a long as return type of bfd_get_symtab_upper_bound().)
251 lines
6.5 KiB
C
251 lines
6.5 KiB
C
/*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that: (1) source code
|
|
* distributions retain the above copyright notice and this paragraph
|
|
* in its entirety, and (2) distributions including binary code include
|
|
* the above copyright notice and this paragraph in its entirety in
|
|
* the documentation or other materials provided with the distribution.
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND
|
|
* WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
|
|
* LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <bfd.h>
|
|
|
|
/*
|
|
* Generate instrumentation calls for entry and exit to functions.
|
|
* Just after function entry and just before function exit, the
|
|
* following profiling functions are called with the address of the
|
|
* current function and its call site (currently not use).
|
|
*
|
|
* The attribute 'no_instrument_function' causes this instrumentation is
|
|
* not done.
|
|
*
|
|
* These profiling functions call print_debug(). This function prints the
|
|
* current function name with indentation and call level.
|
|
* If entering in a function it prints also the calling function name with
|
|
* file name and line number.
|
|
*
|
|
* If the environment variable INSTRUMENT is
|
|
* unset or set to an empty string, print nothing, like with no instrumentation
|
|
* set to "all" or "a", print all the functions names
|
|
* set to "global" or "g", print only the global functions names
|
|
*/
|
|
|
|
#define ND_NO_INSTRUMENT __attribute__((no_instrument_function))
|
|
|
|
/* Store the function call level, used also in pretty_print_packet() */
|
|
extern int profile_func_level;
|
|
int profile_func_level = -1;
|
|
|
|
typedef enum {
|
|
ENTER,
|
|
EXIT
|
|
} action_type;
|
|
|
|
void __cyg_profile_func_enter(void *this_fn, void *call_site) ND_NO_INSTRUMENT;
|
|
|
|
void __cyg_profile_func_exit(void *this_fn, void *call_site) ND_NO_INSTRUMENT;
|
|
|
|
static void print_debug(void *this_fn, void *call_site, action_type action)
|
|
ND_NO_INSTRUMENT;
|
|
|
|
void
|
|
__cyg_profile_func_enter(void *this_fn, void *call_site)
|
|
{
|
|
print_debug(this_fn, call_site, ENTER);
|
|
}
|
|
|
|
void
|
|
__cyg_profile_func_exit(void *this_fn, void *call_site)
|
|
{
|
|
print_debug(this_fn, call_site, EXIT);
|
|
}
|
|
|
|
static void print_debug(void *this_fn, void *call_site, action_type action)
|
|
{
|
|
static bfd* abfd;
|
|
static asymbol **symtab;
|
|
static long symcount;
|
|
static asection *text;
|
|
static bfd_vma vma;
|
|
static int instrument_set;
|
|
static int instrument_off;
|
|
static int instrument_global;
|
|
|
|
if (!instrument_set) {
|
|
static char *instrument_type;
|
|
|
|
/* Get the configuration environment variable INSTRUMENT value if any */
|
|
instrument_type = getenv("INSTRUMENT");
|
|
/* unset or set to an empty string ? */
|
|
if (instrument_type == NULL ||
|
|
!strncmp(instrument_type, "", sizeof(""))) {
|
|
instrument_off = 1;
|
|
} else {
|
|
/* set to "global" or "g" ? */
|
|
if (!strncmp(instrument_type, "global", sizeof("global")) ||
|
|
!strncmp(instrument_type, "g", sizeof("g")))
|
|
instrument_global = 1;
|
|
else if (strncmp(instrument_type, "all", sizeof("all")) &&
|
|
strncmp(instrument_type, "a", sizeof("a"))) {
|
|
fprintf(stderr, "INSTRUMENT can be only \"\", \"all\", \"a\", "
|
|
"\"global\" or \"g\".\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
instrument_set = 1;
|
|
}
|
|
|
|
if (instrument_off)
|
|
return;
|
|
|
|
/* If no errors, this block should be executed one time */
|
|
if (!abfd) {
|
|
char pgm_name[1024];
|
|
long symsize;
|
|
|
|
ssize_t ret = readlink("/proc/self/exe", pgm_name, sizeof(pgm_name));
|
|
if (ret == -1) {
|
|
perror("failed to find executable");
|
|
return;
|
|
}
|
|
if (ret == sizeof(pgm_name)) {
|
|
/* no space for the '\0' */
|
|
printf("truncation may have occurred\n");
|
|
return;
|
|
}
|
|
pgm_name[ret] = '\0';
|
|
|
|
bfd_init();
|
|
|
|
abfd = bfd_openr(pgm_name, NULL);
|
|
if (!abfd) {
|
|
bfd_perror("bfd_openr");
|
|
return;
|
|
}
|
|
|
|
if (!bfd_check_format(abfd, bfd_object)) {
|
|
bfd_perror("bfd_check_format");
|
|
return;
|
|
}
|
|
|
|
if((symsize = bfd_get_symtab_upper_bound(abfd)) == -1) {
|
|
bfd_perror("bfd_get_symtab_upper_bound");
|
|
return;
|
|
}
|
|
|
|
symtab = (asymbol **)malloc((size_t)symsize);
|
|
symcount = bfd_canonicalize_symtab(abfd, symtab);
|
|
if (symcount < 0) {
|
|
free(symtab);
|
|
bfd_perror("bfd_canonicalize_symtab");
|
|
return;
|
|
}
|
|
|
|
if ((text = bfd_get_section_by_name(abfd, ".text")) == NULL) {
|
|
bfd_perror("bfd_get_section_by_name");
|
|
return;
|
|
}
|
|
vma = text->vma;
|
|
}
|
|
|
|
if (instrument_global) {
|
|
symbol_info syminfo;
|
|
int found;
|
|
long i;
|
|
|
|
i = 0;
|
|
found = 0;
|
|
while (i < symcount && !found) {
|
|
bfd_get_symbol_info(abfd, symtab[i], &syminfo);
|
|
if ((void *)syminfo.value == this_fn) {
|
|
found = 1;
|
|
}
|
|
i++;
|
|
}
|
|
/* type == 'T' for a global function */
|
|
if (found == 1 && syminfo.type != 'T')
|
|
return;
|
|
}
|
|
|
|
/* Current function */
|
|
if ((bfd_vma)this_fn < vma) {
|
|
printf("[ERROR address this_fn]");
|
|
} else {
|
|
const char *file;
|
|
const char *func;
|
|
unsigned int line;
|
|
|
|
if (!bfd_find_nearest_line(abfd, text, symtab, (bfd_vma)this_fn - vma,
|
|
&file, &func, &line)) {
|
|
printf("[ERROR bfd_find_nearest_line this_fn]");
|
|
} else {
|
|
int i;
|
|
|
|
if (action == ENTER)
|
|
profile_func_level += 1;
|
|
/* Indentation */
|
|
for (i = 0 ; i < profile_func_level ; i++)
|
|
putchar(' ');
|
|
if (action == ENTER)
|
|
printf("[>> ");
|
|
else
|
|
printf("[<< ");
|
|
/* Function name */
|
|
if (func == NULL || *func == '\0')
|
|
printf("???");
|
|
else
|
|
printf("%s", func);
|
|
printf(" (%d)", profile_func_level);
|
|
/* Print the "from" part except for the main function) */
|
|
if (action == ENTER && func != NULL &&
|
|
strncmp(func, "main", sizeof("main"))) {
|
|
/* Calling function */
|
|
if ((bfd_vma)call_site < vma) {
|
|
printf("[ERROR address call_site]");
|
|
} else {
|
|
if (!bfd_find_nearest_line(abfd, text, symtab,
|
|
(bfd_vma)call_site - vma, &file,
|
|
&func, &line)) {
|
|
printf("[ERROR bfd_find_nearest_line call_site]");
|
|
} else {
|
|
printf(" from ");
|
|
/* Function name */
|
|
if (func == NULL || *func == '\0')
|
|
printf("???");
|
|
else
|
|
printf("%s", func);
|
|
/* File name */
|
|
if (file == NULL || *file == '\0')
|
|
printf(" ??:");
|
|
else {
|
|
char *slashp = strrchr(file, '/');
|
|
if (slashp != NULL)
|
|
file = slashp + 1;
|
|
printf(" %s:", file);
|
|
}
|
|
/* Line number */
|
|
if (line == 0)
|
|
printf("?");
|
|
else
|
|
printf("%u", line);
|
|
printf("]");
|
|
}
|
|
}
|
|
}
|
|
putchar('\n');
|
|
if (action == EXIT)
|
|
profile_func_level -= 1;
|
|
}
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
/* vi: set tabstop=4 softtabstop=0 shiftwidth=4 smarttab autoindent : */
|