]> The Tcpdump Group git mirrors - tcpdump/blob - instrument-functions.c
Rename print-rrcp.c to print-realtek.c.
[tcpdump] / instrument-functions.c
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 #ifndef _GNU_SOURCE
15 #define _GNU_SOURCE
16 #endif
17
18 #include <stdio.h>
19 #include <dlfcn.h>
20
21 extern int profile_func_level;
22 int profile_func_level = -1;
23
24 /*
25 * Generate instrumentation calls for entry and exit to functions.
26 * Just after function entry and just before function exit, the
27 * following profiling functions are called with the address of the
28 * current function and its call site (currently not use).
29 *
30 * The attribute 'no_instrument_function' causes this instrumentation is
31 * not done.
32 *
33 * These profiling functions print the function names with indentation
34 * and call level.
35 *
36 * To instument a static function, remove temporarily the static specifier.
37 */
38
39 #ifndef ND_NO_INSTRUMENT
40 #define ND_NO_INSTRUMENT __attribute__((no_instrument_function))
41 #endif
42
43 void __cyg_profile_func_enter(void *this_fn, void *call_site) ND_NO_INSTRUMENT;
44
45 void __cyg_profile_func_exit(void *this_fn, void *call_site) ND_NO_INSTRUMENT;
46
47 /*
48 * Structure table to store the functions data from FILE_NAME.
49 * FILE_NAME is generated via:
50 * $ nm $(PROG) | grep ' [tT] '
51 * or
52 * $ nm $(PROG) | grep ' [T] '
53 */
54
55 #define MAX_FUNCTIONS 20000
56 static struct {
57 void *addr;
58 char type;
59 char name[128];
60 } functions[MAX_FUNCTIONS] ;
61 static int functions_count;
62 static int initialization_done;
63
64 /*
65 * Read the result of nm in functions[]
66 */
67
68 #define FILE_NAME "tcpdump_instrument_functions.nm"
69
70 void read_functions_table(void) ND_NO_INSTRUMENT;
71
72 void
73 read_functions_table(void)
74 {
75 FILE *fp;
76 int i = 0;
77 if ((fp = fopen(FILE_NAME, "r")) == NULL) {
78 printf("Warning: Cannot open \"%s\" file\n", FILE_NAME);
79 return;
80 }
81 while (i < MAX_FUNCTIONS && fscanf(fp, "%p %c %s", &functions[i].addr,
82 &functions[i].type, functions[i].name) != EOF)
83 i++;
84 fclose(fp);
85 functions_count = i;
86 }
87
88 /*
89 * Get the function name by searching in functions[]
90 */
91
92 static const char * get_function_name(void *func) ND_NO_INSTRUMENT;
93
94 static const char *
95 get_function_name(void *func)
96 {
97 int i = 0;
98 int found = 0;
99 if (!initialization_done) {
100 read_functions_table();
101 initialization_done = 1;
102 }
103 while (i < functions_count) {
104 if (functions[i].addr == func) {
105 found = 1;
106 break;
107 }
108 i++;
109 }
110 if (found)
111 return (functions[i].name);
112 else
113 return NULL;
114 }
115
116 void
117 __cyg_profile_func_enter(void *this_fn,
118 void *call_site __attribute__((unused)))
119 {
120 int i;
121 const char *function_name;
122
123 if ((function_name = get_function_name(this_fn)) != NULL) {
124 profile_func_level += 1;
125 for (i = 0 ; i < profile_func_level ; i++)
126 putchar(' ');
127 printf("[>> %s (%d)]\n", function_name, profile_func_level);
128 }
129 fflush(stdout);
130 }
131
132 void
133 __cyg_profile_func_exit(void *this_fn,
134 void *call_site __attribute__((unused)))
135 {
136 int i;
137 const char *function_name;
138
139 if ((function_name = get_function_name(this_fn)) != NULL) {
140 for (i = 0 ; i < profile_func_level ; i++)
141 putchar(' ');
142 printf ("[<< %s (%d)]\n", function_name, profile_func_level);
143 profile_func_level -= 1;
144 }
145 fflush(stdout);
146 }