Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libpcap/instrument-functions.c
178435 views
1
/*
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.
12
*/
13
14
#include <stdio.h>
15
#include <string.h>
16
#include <stdlib.h>
17
#include <unistd.h>
18
#include <bfd.h>
19
20
/*
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).
25
*
26
* The attribute 'no_instrument_function' causes this instrumentation is
27
* not done.
28
*
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.
33
*
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
38
*/
39
40
#define ND_NO_INSTRUMENT __attribute__((no_instrument_function))
41
42
/* Store the function call level, used also in pretty_print_packet() */
43
extern int profile_func_level;
44
int profile_func_level = -1;
45
46
typedef enum {
47
ENTER,
48
EXIT
49
} action_type;
50
51
void __cyg_profile_func_enter(void *this_fn, void *call_site) ND_NO_INSTRUMENT;
52
53
void __cyg_profile_func_exit(void *this_fn, void *call_site) ND_NO_INSTRUMENT;
54
55
static void print_debug(void *this_fn, void *call_site, action_type action)
56
ND_NO_INSTRUMENT;
57
58
void
59
__cyg_profile_func_enter(void *this_fn, void *call_site)
60
{
61
print_debug(this_fn, call_site, ENTER);
62
}
63
64
void
65
__cyg_profile_func_exit(void *this_fn, void *call_site)
66
{
67
print_debug(this_fn, call_site, EXIT);
68
}
69
70
static void print_debug(void *this_fn, void *call_site, action_type action)
71
{
72
static bfd* abfd;
73
static asymbol **symtab;
74
static long symcount;
75
static asection *text;
76
static bfd_vma vma;
77
static int instrument_set;
78
static int instrument_off;
79
static int instrument_global;
80
81
if (!instrument_set) {
82
static char *instrument_type;
83
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(""))) {
89
instrument_off = 1;
90
} else {
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");
99
exit(1);
100
}
101
}
102
instrument_set = 1;
103
}
104
105
if (instrument_off)
106
return;
107
108
/* If no errors, this block should be executed one time */
109
if (!abfd) {
110
char pgm_name[1024];
111
long symsize;
112
113
ssize_t ret = readlink("/proc/self/exe", pgm_name, sizeof(pgm_name));
114
if (ret == -1) {
115
perror("failed to find executable");
116
return;
117
}
118
if (ret == sizeof(pgm_name)) {
119
/* no space for the '\0' */
120
printf("truncation may have occurred\n");
121
return;
122
}
123
pgm_name[ret] = '\0';
124
125
bfd_init();
126
127
abfd = bfd_openr(pgm_name, NULL);
128
if (!abfd) {
129
bfd_perror("bfd_openr");
130
return;
131
}
132
133
if (!bfd_check_format(abfd, bfd_object)) {
134
bfd_perror("bfd_check_format");
135
return;
136
}
137
138
if((symsize = bfd_get_symtab_upper_bound(abfd)) == -1) {
139
bfd_perror("bfd_get_symtab_upper_bound");
140
return;
141
}
142
143
symtab = (asymbol **)malloc((size_t)symsize);
144
symcount = bfd_canonicalize_symtab(abfd, symtab);
145
if (symcount < 0) {
146
free(symtab);
147
bfd_perror("bfd_canonicalize_symtab");
148
return;
149
}
150
151
if ((text = bfd_get_section_by_name(abfd, ".text")) == NULL) {
152
bfd_perror("bfd_get_section_by_name");
153
return;
154
}
155
vma = text->vma;
156
}
157
158
if (instrument_global) {
159
symbol_info syminfo;
160
int found;
161
long i;
162
163
i = 0;
164
found = 0;
165
while (i < symcount && !found) {
166
bfd_get_symbol_info(abfd, symtab[i], &syminfo);
167
if ((void *)syminfo.value == this_fn) {
168
found = 1;
169
}
170
i++;
171
}
172
/* type == 'T' for a global function */
173
if (found == 1 && syminfo.type != 'T')
174
return;
175
}
176
177
/* Current function */
178
if ((bfd_vma)this_fn < vma) {
179
printf("[ERROR address this_fn]");
180
} else {
181
const char *file;
182
const char *func;
183
unsigned int line;
184
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]");
188
} else {
189
int i;
190
191
if (action == ENTER)
192
profile_func_level += 1;
193
/* Indentation */
194
for (i = 0 ; i < profile_func_level ; i++)
195
putchar(' ');
196
if (action == ENTER)
197
printf("[>> ");
198
else
199
printf("[<< ");
200
/* Function name */
201
if (func == NULL || *func == '\0')
202
printf("???");
203
else
204
printf("%s", func);
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]");
212
} else {
213
if (!bfd_find_nearest_line(abfd, text, symtab,
214
(bfd_vma)call_site - vma, &file,
215
&func, &line)) {
216
printf("[ERROR bfd_find_nearest_line call_site]");
217
} else {
218
printf(" from ");
219
/* Function name */
220
if (func == NULL || *func == '\0')
221
printf("???");
222
else
223
printf("%s", func);
224
/* File name */
225
if (file == NULL || *file == '\0')
226
printf(" ??:");
227
else {
228
char *slashp = strrchr(file, '/');
229
if (slashp != NULL)
230
file = slashp + 1;
231
printf(" %s:", file);
232
}
233
/* Line number */
234
if (line == 0)
235
printf("?");
236
else
237
printf("%u", line);
238
printf("]");
239
}
240
}
241
}
242
putchar('\n');
243
if (action == EXIT)
244
profile_func_level -= 1;
245
}
246
}
247
fflush(stdout);
248
}
249
250
/* vi: set tabstop=4 softtabstop=0 shiftwidth=4 smarttab autoindent : */
251
252