forked from makelinux/ldt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ctracer.h
379 lines (315 loc) · 9.88 KB
/
ctracer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
/*
Tracing utility for C
implemented in include-file only
Copyright (C) 2012 Constantine Shulyupin http://www.makelinux.net/
Dual BSD/GPL License
*/
#if 0
/* Optional configuration flags: */
#define TRACE_TIME
#define TRACE_MALLOC
#define TRACE_LINUX_MEMORY_ON
#endif
/*
VI command to include label _entry to each function start for tracing
:%s/) *\n{ *$/)\r{\t_entry:;/
*/
#ifndef __ASSEMBLY__
#ifndef CTRACER_H_INCLUDED
#define CTRACER_H_INCLUDED
extern __thread int ret;
#define multistatement(ms) ms /* trick to bypass checkpatch.pl error */
/*
#define _entry multistatement(trllog(); goto _entry; _entry)
*/
#define _entry multistatement(_trace_enter_exit_(); trln(); goto _entry_second; _entry_second)
/*
#define _entry once(trl()); goto _entry; _entry
#define return trlm("} "); return
*/
#define do_statement(a) do { a } while (0)
/*
trace variables: integer, hex, string, pointer, float, time value, with and w/o new line
macro with '_' doesn't prints new line
notation:
tr = trace
v<letter> = printf Variable in specified format (d, x, f, s, etc)
*/
#define trla(fmt, args...) tracef("%s:%i %s "fmt, __file__, __LINE__, __func__, ## args)
#define trv(t, v) tracef(#v" = %"t EOL, v)
#define trv_(t, v) tracef(#v" = %"t" ", v)
#define trvd(d) tracef(#d" = %ld"EOL, (long int)d)
#define trvd_(d) tracef(#d" = %ld ", (long int)d)
#define trvx_(x) tracef(#x" = 0x%x ", (int)x)
#define trvx(x) tracef(#x" = 0x%x"EOL, (int)x)
#define trvlx(x) tracef(#x" = %#llx"EOL, (int)x)
#define trvX(x) tracef(#x" = %#X"EOL, (int)x)
#define trvf(f) tracef(#f" = %f"EOL, f)
#define trvf_(f) tracef(#f" = %f ", f)
#define trvtv_(tv) tracef(#tv" = %u.%06u ", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec)
#define trvtv(tv) tracef(#tv" = %u.%06u"EOL, (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec)
#define trvs(s) tracef(#s" = \"%s\""EOL, s)
#define trvs_(s) tracef(#s" = \"%s\" ", s)
#define trvp(p) tracef(#p" = %08x"EOL, (unsigned)p)
#define trvp_(p) tracef(#p" = %08x ", (unsigned)p)
#define trvdn(d, n) {int i; tracef("%s", #d"[]="); for (i = 0; i < n; i++) tracef("%d:%d,", i, (*((int *)d+i))); tracef(EOL); }
#define trvxn(d, n) {int i; tracef("%s", #d"[]="); for (i = 0; i < n; i++) tracef("%04x,", (*((int *)d+i))); tracef(EOL); }
#define trvdr(record) trvdn(&record, sizeof(record)/sizeof(int));
#define trvxr(record) trvxn(&record, sizeof(record)/sizeof(int));
/* trvdnz - TRace Digital Variable, if Not Zero */
#define trvdnz(d) { if (d) tracef(#d" = %d"EOL, (int)d); }
#define trace_call(a) do { trla("calling %s {\n", #a); a; tracef("} done\n"); } while (0)
/* trlm - TRace Location, with Message */
#define trlm(m) tracef(SOL"%s:%i %s %s"EOL, __file__, __LINE__, __func__, m)
#define trlm_(m) tracef(SOL"%s:%i %s %s ", __file__, __LINE__, __func__, m)
#define trl() do { trace_time(); trlm(""); } while (0)
#define trl_() tracef(SOL"%s:%i %s ", __file__, __LINE__, __func__)
#define trln() tracef(EOL)
#define trl_in() do_statement(trace_time(); trlm("{");)
#define trl_out() do_statement(trace_time(); trlm("}");)
#define empty_statement() do { } while (0)
#define trace_mem(P, N) \
IFTRACE({ int i = 0; tracef("%s=", #P); for (; i < (int)(N) ; i++) \
{ if (i && (!(i % 16))) tracef("%i:", i); \
tracef("%02x ", 0xFF & *((char *)((void *)(P))+i)); \
if (!((i+1) % 4)) \
tracef(" "); \
if (!((i+1) % 16)) \
tracef(EOL); \
}; tracef(EOL); })
#define trace_mem_int_list(P, N) \
IFTRACE({ int i = 0; for (; i < (int)(N); i += sizeof(int)) \
{ tracef("%i, ", *(int *)((void *)(P)+i)); \
}; })
#define trace_mem_int(P, N) \
IFTRACE({ int i = 0; for (; i < (int)(N) ; i += sizeof(int)) \
{ if (i && (!(i % 16))) tracef("%i:", i); \
tracef("%x ", *(int *)((void *)(P)+i)); \
if (!((i+1) % 64)) \
tracef(EOL); \
}; tracef(EOL); })
#define trace_ioctl(nr) tracef("ioctl=(%c%c %c #%i %i)\n", \
(_IOC_READ & _IOC_DIR(nr)) ? 'r' : ' ', (_IOC_WRITE & _IOC_DIR(nr)) ? 'w' : ' ', \
_IOC_TYPE(nr), _IOC_NR(nr), _IOC_SIZE(nr))
#define trace_ioctl_(nr) tracef("ioctl=(%i %i %i %i)", _IOC_DIR(nr), _IOC_TYPE(nr), _IOC_NR(nr), _IOC_SIZE(nr))
#define chkz(a) \
(p = a,\
((!p) ? tracef("%s %i %s FAIL %i = %s\n", __FILE__, __LINE__, __func__, p, #a) : 0),\
p)
#define chkn(a) \
(ret = a,\
((ret < 0) ? tracef("%s:%i %s FAIL\n\t%i=%s\n", __FILE__, __LINE__, __func__, ret, #a)\
: 0), ret)
#define chkne(a) \
(/* tracef("calling %s\n",#a), */ \
ret = a,\
((ret < 0) ? tracef("%s:%i %s FAIL errno = %i \"%s\" %i = %s\n", __FILE__, __LINE__, __func__, errno, strerror(errno), ret, #a)\
: 0), ret)
#define chkn2(a) \
(ret = a,\
((ret < 0) ? tracef("%s %i %s FAIL %i = %s\n", __FILE__, __LINE__, __func__, ret, #a)\
: tracef("%s %i %s %i = %s\n", __FILE__, __LINE__, __func__, ret, #a)),\
ret)
#define once(exp) do_statement( \
static int _passed; if (!_passed) {exp; }; _passed = 1;)
#ifdef CTRACER_OFF /* force no tracing */
#undef CTRACER_ON
#endif
#ifdef CTRACER_ON
#define IFTRACE(x) x
#ifdef __KERNEL__
#undef TRACE_TIME
#include <linux/kernel.h>
#include <linux/printk.h>
#ifdef TRACE_LINUX_MEMORY_ON
#include <linux/mmzone.h>
extern int free_pages_prev;
#define trace_linux_mem() do { \
extern zone_t *zone_table[MAX_NR_ZONES*MAX_NR_NODES]; \
int mem_change = zone_table[0]->free_pages - free_pages_prev; \
if (mem_change) { \
trl_(); trvi_(mem_change); trvi(zone_table[0]->free_pages); } \
free_pages_prev = zone_table[0]->free_pages; \
} while (0)
#endif
#define SOL KERN_DEBUG
#define tracef(fmt, args...) printk(fmt, ##args)
#else /* !__KERNEL__ */
/* CTRACER_ON and not __KERNEL__ */
#include <stdio.h>
#define tracef(args...) fprintf(stderr, ##args)
#if 0
#include <signal.h>
#define BP {trl(); kill(0, SIGTRAP); }
#define BP kill(0, SIGTRAP)
#endif
#ifndef tracef
#define tracef printf
#endif
#endif /* !__KERNEL__ */
#ifndef _hweight32
static inline unsigned int _hweight32(unsigned int w)
{ /* from kernel */
w -= (w >> 1) & 0x55555555;
w = (w & 0x33333333) + ((w >> 2) & 0x33333333);
w = (w + (w >> 4)) & 0x0f0f0f0f;
return (w * 0x01010101) >> 24;
}
#define _hweight32 _hweight32
#endif
#define trllog(args ...) \
do { \
static int num; \
if (_hweight32(num) < 2) { \
trla("#%d\n", (int)num); \
} num++; \
} while (0)
#define trlnum(n, args ...) \
do { \
static int num; \
if (num < n) { \
trl_(); \
tracef("#0x%x", (int)num); \
args; \
trln(); \
} num++; \
} while (0)
#define trleach(n, args ...) \
do { \
static int num; \
if (!(num % n)) { \
trl_(); \
trvi_(num); \
args; \
trln(); \
} num++; \
} while (0)
#else /* !CTRACER_ON */
#define trllog(args ...)
static inline int empty_function(void)
{
return 0;
}
#define IFTRACE(x) empty_statement()
#define trace_linux_mem() empty_statement()
#define tracef(fmt, args...) empty_function()
#define stack_trace() empty_statement()
#endif /* _TARCE */
#ifndef SOL
#define SOL ""
#endif
#define EOL "\n" /* for console */
#ifdef MODULE
/* omit full absolute path for modules */
extern char *strrchr(const char *s, int c);
#define ctracer_cut_path(fn) (fn[0] != '/' ? fn : (strrchr(fn, '/') + 1))
#define __file__ ctracer_cut_path(__FILE__)
#else
#define __file__ __FILE__
#endif
#ifdef TRACE_MALLOC
static int malloc_count;
static void *malloc_trace;
#endif
#ifdef TRACE_MALLOC
#define malloc(s) \
(trla("malloc #%i %p %i\n", ++malloc_count, malloc_trace = malloc(s), s),\
malloc_trace)
#define free(p) { free(p); trla("free #%i %p\n", malloc_count--, (void *)p); }
#define strdup(s) \
(trla("strdup #%i %p\n", ++malloc_count, malloc_trace = (void *)strdup(s)),\
(char *)malloc_trace)
#endif
#ifdef TRACE_TIME
#include <time.h>
#include <sys/time.h>
#ifndef trace_time_defined
#define trace_time_defined
void trace_time();
/*
extern double time_prev_f;
void static inline trace_time()
{
time_t time_cur;
double time_cur_f;
time(&time_cur);
struct timeval tv;
struct timezone tz;
struct tm* time_tm;
gettimeofday(&tv, &tz);
time_tm = localtime(&time_cur);
time_cur = tv.tv_sec;
time_cur_f = 0.000001 * tv.tv_usec + time_cur;
double passed = time_cur_f - time_prev_f;
if (passed > 0.001)
{
tracef("time=%04d-%02d-%02d %02d:%02d:%02d %02d +%1.4f s\n",
time_tm->tm_year+1900, time_tm->tm_mon+1, time_tm->tm_mday,
time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec, (int)tv.tv_usec,
passed);
time_prev_f = time_cur_f;
}
}
*/
#endif
#else
#define trace_time() empty_statement()
#endif
#ifdef __GLIBC__XX
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef stack_trace
#undef stack_trace
#endif
#ifndef stack_trace_difined
#define stack_trace_difined
/* only once */
static inline void stack_trace(void)
{
void *array[5];
size_t size;
char **strings;
size_t i;
size = backtrace(array, sizeof(array) / sizeof(array[0]));
strings = backtrace_symbols(array, size);
tracef("Stack:\n");
for (i = 0; i < size; i++) {
if (!array[i])
break;
tracef("%i %p %s\n", i, array[i], strings[i]);
}
free(strings);
}
#endif
#endif /* __GLIBC__ */
/* see also nr_free_pages */
#define freeram() { \
static unsigned int last; struct sysinfo i; si_meminfo(&i); trl_(); \
int d = last-i.freeram; int used = i.totalram-i.freeram; \
trvi_(i.freeram); trvi_(used); trvi(d); \
last = i.freeram; }
extern int sprint_symbol_no_offset(char *buffer, unsigned long address);
static inline void __on_cleanup(char *s[])
{
#ifdef __KERNEL__
printk(KERN_DEBUG"%s", *s);
#else
fputs(*s, stderr);
#endif
}
#if !defined(__KERNEL__) || defined(MODULE)
static inline int lookup_symbol_name(unsigned long addr, char *symbol)
{
return sprintf(symbol, "%lx", addr);
}
#else
int lookup_symbol_name(unsigned long addr, char *symname);
#endif
#define _trace_enter_exit_() char _caller[200]; lookup_symbol_name((unsigned long)__builtin_return_address(0), _caller); \
char __attribute__((cleanup(__on_cleanup))) *_s; char _ret_msg[100]; _s = _ret_msg; \
snprintf(_ret_msg, sizeof(_ret_msg), "%s < %s }\n", _caller, __func__); \
tracef(SOL"%s > %s { @ %s:%d", _caller, __func__, __file__, __LINE__);
/*__END_DECLS */
#endif /* CTRACER_H_INCLUDED */
#endif /* __ASSEMBLY__ */