source: libcf/trunk/src/cf_debug.c@ 107

Last change on this file since 107 was 107, checked in by cheese, 11 years ago

#1 change sprintf to snprintf and imporve performance of log

File size: 9.8 KB
Line 
1/**
2 * @file cf_debug.c
3 * @author myusgun <myusgun@gmail.com>
4 */
5#include "cf_debug.h"
6#include "cf_local.h"
7#include "cf_error.h"
8#include "cf_thread.h"
9
10#include <stdlib.h>
11#include <ctype.h>
12#include <stdarg.h>
13#include <string.h>
14
15#if defined(_WIN32) || defined(_WIN64)
16# include <io.h>
17#else
18# include <unistd.h>
19#endif
20
21#define IS_READABLE_CHAR(__c) (' ' <= __c && __c <= '~')
22
23#define ASSERT_CTX(__ctx) \
24 if (__ctx == NULL) \
25 return CF_ERROR_DEBUG_INVALID_CTX
26
27/**
28 * 디버그 컨텍스트
29 *
30 * @remark change from public to private
31 */
32typedef void * CF_Debug_Ctx;
33
34/* *
35 * 콜스택 데이터
36 *
37 * @remark change from public to private
38 */
39typedef struct cf_debug_callStack {
40 char file[NAME_LENGTH + 1]; /* *< 파일 이름 */
41 char function[NAME_LENGTH + 1]; /* *< 함수 이름 */
42 int line; /* *< 라인 넘버 */
43} CF_Debug_CallStack;
44
45typedef struct __cf_debug_callstack__
46{
47 char file[NAME_LENGTH + 1];
48 char func[NAME_LENGTH + 1];
49 int line;
50
51 int frameIndex;
52
53 struct __cf_debug_callstack__ * caller;
54} S_CF_DEBUG_CALLSTACK, CF_DEBUG_CALLSTACK;
55
56typedef struct __cf_debug_ctx__
57{
58 char file[NAME_LENGTH + 1];
59 char func[NAME_LENGTH + 1];
60 int line;
61
62 CF_Mutex mutex;
63
64 CF_DEBUG_CALLSTACK callstack;
65} S_CF_DEBUG_CTX, CF_DEBUG_CTX;
66
67CF_Debug_Ctx gDebugSingleCtx = NULL;
68
69static int
70CF_Debug_Local_UpdateCtx (CF_Debug_Ctx ctx,
71 const char * file,
72 const char * func,
73 const int line)
74{
75 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
76
77 ASSERT_CTX (ctx);
78
79 strncpy (context->file, file, strlen (file));
80 strncpy (context->func, func, strlen (func));
81 context->line = line;
82
83 return CF_OK;
84}
85
86static int
87CF_Debug_Local_Print (FILE * fp,
88 const char * file,
89 const char * func,
90 const int line,
91 const char * fmt,
92 va_list valist)
93{
94 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
95 vfprintf (fp, fmt, valist);
96
97 return CF_OK;
98}
99
100static int
101CF_Debug_Local_PrintBin (FILE * fp,
102 const char * file,
103 const char * func,
104 const int line,
105 const unsigned char * bin,
106 const size_t len)
107{
108 size_t i, j;
109
110 for (i = 0 ; i < len ; i += 16)
111 {
112 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
113 fprintf (fp, "%06x : ", (unsigned int)i);
114
115 for (j = 0 ; j < 16 ; j++)
116 {
117 if (i+j < len)
118 fprintf (fp, "%02x ", bin[i+j]);
119 else
120 fprintf (fp, " ");
121 }
122 fprintf (fp, " ");
123
124 for (j = 0 ; j < 16 ; j++)
125 {
126 if (i+j < len)
127 fprintf (fp, "%c", IS_READABLE_CHAR (bin[i+j]) ? bin[i+j] : '.');
128 }
129 fprintf (fp, "\n");
130 }
131
132 return CF_OK;
133}
134
135/**
136 * 디버그 메시지를 지정된 파일 포인터로 출력
137 *
138 * @return 성공 시, CF_OK; 실패 시, 오류 코드
139 *
140 * @param fp 파일 포인터. 표준출력(stdout) 및 표준오류(stderr) 사용 가능
141 * @param file 파일 경로
142 * @param func 함수 이름
143 * @param line 라인 넘버
144 * @param fmt 포맷 스트링
145 * @param ... 가변 인자
146 *
147 * @see CF_DEBUG_PRINT
148 */
149int
150CF_Debug_Print (FILE * fp,
151 const char * file,
152 const char * func,
153 const int line,
154 const char * fmt, ...)
155{
156 va_list valist;
157
158 va_start (valist, fmt);
159 CF_Debug_Local_Print (fp, file, func, line, fmt, valist);
160 va_end (valist);
161
162 return CF_OK;
163}
164
165/**
166 * 바이너리 데이터를 디버그 메시지와 함께 지정된 파일 포인터로 출력
167 *
168 * @return CF_OK 반환
169 *
170 * @param fp 파일 포인터. 표준출력(stdout) 및 표준오류(stderr) 사용 가능
171 * @param file 파일 경로
172 * @param func 함수 이름
173 * @param line 라인 넘버
174 * @param bin 라인 넘버
175 * @param len 바이너리 길이
176 * @param fmt 포맷 스트링
177 * @param ... 가변 인자
178 *
179 * @see CF_DEBUG_PRINT_BIN
180 */
181int
182CF_Debug_PrintBin (FILE * fp,
183 const char * file,
184 const char * func,
185 const int line,
186 const unsigned char * bin,
187 const size_t len,
188 const char * fmt, ...)
189{
190 va_list valist;
191
192 va_start (valist, fmt);
193 CF_Debug_Local_Print (fp, file, func, line, fmt, valist);
194 va_end (valist);
195
196 CF_Debug_Local_PrintBin (fp, file, func, line, bin, len);
197
198 return CF_OK;
199}
200
201/**
202 * 컨텍스트에 콜스택 푸시
203 *
204 * @return 성공 시, CF_OK; 실패 시, 오류 코드
205 *
206 * @param ctx 디버그 컨텍스트
207 * @param file 파일 경로
208 * @param func 함수 이름
209 * @param line 라인 넘버
210 */
211static int
212CF_Debug_CallStackPush (CF_Debug_Ctx ctx,
213 const char * file,
214 const char * func,
215 const int line)
216{
217 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
218 CF_DEBUG_CALLSTACK * push = NULL;
219
220 ASSERT_CTX (ctx);
221
222 push = (CF_DEBUG_CALLSTACK *) calloc (sizeof (CF_DEBUG_CALLSTACK), 1);
223 if (push == NULL)
224 return CF_ERROR_DEBUG_PUSH_CALLSTACK;
225
226 /* push to callstack */
227 snprintf (push->file, NAME_LENGTH, "%s", file);
228 snprintf (push->func, NAME_LENGTH, "%s", func);
229 push->line = line;
230 push->caller = context->callstack.caller;
231 push->frameIndex = (push->caller) ? push->caller->frameIndex + 1 : 0;
232 context->callstack.caller = push;
233
234 CF_Debug_Local_UpdateCtx (ctx, file, func, line);
235
236 return CF_OK;
237}
238
239/**
240 * 컨텍스트에서 콜스택에서 TOP을 제거하지 않고 가져옴
241 *
242 * @return 성공 시, CF_OK; 실패 시, 오류 코드
243 *
244 * @param ctx 디버그 컨텍스트
245 * @param callstack 콜스택 정보를 가져올 콜스택 데이터 구조체 포인터
246 *
247 * @see CF_Debug_CallStack
248 */
249static int
250CF_Debug_CallStackPeek (CF_Debug_Ctx ctx,
251 CF_Debug_CallStack * callstack)
252{
253 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
254 CF_DEBUG_CALLSTACK * pop = NULL;
255
256 pop = context->callstack.caller;
257 if (pop == NULL)
258 return CF_ERROR_DEBUG_PEEK_CALLSTACK;
259
260 if (callstack != NULL)
261 {
262 snprintf (callstack->file , NAME_LENGTH, "%s", pop->file);
263 snprintf (callstack->function, NAME_LENGTH, "%s", pop->func);
264 callstack->line = pop->line;
265 }
266
267 return CF_OK;
268}
269
270/**
271 * 컨텍스트에서 콜스택 팝
272 *
273 * @return 성공 시, CF_OK; 실패 시, 오류 코드
274 *
275 * @param ctx 디버그 컨텍스트
276 * @param callstack 콜스택 정보를 가져올 콜스택 데이터 구조체 포인터
277 *
278 * @see CF_Debug_CallStack
279 */
280static int
281CF_Debug_CallStackPop (CF_Debug_Ctx ctx,
282 CF_Debug_CallStack * callstack)
283{
284 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
285 CF_DEBUG_CALLSTACK * pop = NULL;
286
287 ASSERT_CTX (ctx);
288
289 pop = context->callstack.caller;
290 if (pop == NULL)
291 return CF_ERROR_DEBUG_POP_CALLSTACK;
292
293 if (CF_Debug_CallStackPeek (ctx, callstack) < 0)
294 return CF_ERROR_DEBUG_PEEK_CALLSTACK;
295
296 memset (context->file, 0x00, sizeof (context->file));
297 memset (context->func, 0x00, sizeof (context->func));
298 context->line = 0;
299
300 /* restore current context */
301 if (pop->caller != NULL)
302 {
303 CF_Debug_Local_UpdateCtx (ctx,
304 pop->caller->file,
305 pop->caller->func,
306 pop->caller->line);
307 }
308
309 context->callstack.caller = pop->caller;
310 free (pop);
311
312 return CF_OK;
313}
314
315/**
316 * 디버그 컨텍스트를 해제
317 *
318 * @return 성공 시, CF_OK; 실패 시, 오류 코드
319 *
320 * @param ctx 디버그 컨텍스트
321 *
322 * @see CF_DEBUG_DESTROY_CTX
323 */
324static int
325CF_Debug_DestroyCtx (CF_Debug_Ctx ctx)
326{
327 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
328
329 ASSERT_CTX (ctx);
330
331 while (context->callstack.caller)
332 CF_Debug_CallStackPop (ctx, NULL);
333
334 if (context->mutex)
335 CF_Mutex_Destory (&context->mutex);
336
337 free (context);
338
339 return CF_OK;
340}
341
342/**
343 * 디버그 컨텍스트를 생성
344 *
345 * @return 성공 시, CF_Debug_Ctx 형태의 컨텍스트; 실패 시, NULL
346 * @see CF_DEBUG_CREATE_CTX
347 */
348static int
349CF_Debug_CreateCtx (CF_Debug_Ctx * ctx)
350{
351 int result = 0;
352 CF_DEBUG_CTX * context = NULL;
353
354 TRY
355 {
356 context = (CF_DEBUG_CTX *) calloc (sizeof (CF_DEBUG_CTX), 1);
357 if (context == NULL)
358 {
359 result = CF_ERROR_DEBUG_ALLOCATE_CTX;
360 TRY_BREAK;
361 }
362
363 result = CF_Mutex_Create (&context->mutex);
364 if (result < 0)
365 {
366 TRY_BREAK;
367 }
368
369 *ctx = (CF_Debug_Ctx) context;
370 }
371 CATCH_IF (result < 0)
372 {
373 CF_Debug_DestroyCtx (context);
374 }
375
376 return result;
377}
378
379/**
380 * 콜스택 매니저 초기화 (글로벌 컨텍스트)
381 *
382 * @return 성공 시, CF_OK; 실패 시, 오류 코드
383 *
384 * @see CF_Debug_Finalize
385 */
386int
387CF_Debug_Initialize (void)
388{
389 int result = 0;
390
391 if (gDebugSingleCtx == NULL)
392 result = CF_Debug_CreateCtx (&gDebugSingleCtx);
393
394 return result;
395}
396
397/**
398 * 콜스택 매니저 해제 (글로벌 컨텍스트)
399 *
400 * @return 성공 시, CF_OK; 실패 시, 오류 코드
401 */
402int
403CF_Debug_Finalize (void)
404{
405 CF_Debug_Ctx ctx = gDebugSingleCtx;
406
407 gDebugSingleCtx = NULL;
408
409 return CF_Debug_DestroyCtx (ctx);
410}
411
412/**
413 * 함수 진입을 명시 (글로벌 컨텍스트)
414 *
415 * @return 성공 시, CF_OK; 실패 시, 오류 코드
416 *
417 * @param file 파일 경로
418 * @param func 함수 이름
419 * @param line 라인 넘버
420 *
421 * @see CF_Debug_LeaveFunction
422 */
423int
424CF_Debug_EnterFunction (const char * file,
425 const char * func,
426 const int line)
427{
428 CF_DEBUG_CTX * ctx = (CF_DEBUG_CTX *)gDebugSingleCtx;
429
430 ASSERT_CTX (ctx);
431
432 CF_Mutex_Lock (&ctx->mutex);
433 CF_Debug_CallStackPush (gDebugSingleCtx, file, func, line);
434 CF_Mutex_Unlock (&ctx->mutex);
435
436 return CF_OK;
437}
438
439/**
440 * 함수 종료를 명시 (글로벌 컨텍스트)
441 *
442 * @return 성공 시, CF_OK; 실패 시, 오류 코드
443 *
444 * @see CF_Debug_EnterFunction
445 */
446int
447CF_Debug_LeaveFunction (void)
448{
449 CF_DEBUG_CTX * ctx = (CF_DEBUG_CTX *)gDebugSingleCtx;
450
451 ASSERT_CTX (ctx);
452
453 CF_Mutex_Lock (&ctx->mutex);
454 CF_Debug_CallStackPop (gDebugSingleCtx, NULL);
455 CF_Mutex_Unlock (&ctx->mutex);
456
457 return CF_OK;
458}
459
460/**
461 * 현재 콜스택을 출력 (글로벌 컨텍스트)
462 *
463 * @return 성공 시, CF_OK; 실패 시, 오류 코드
464 *
465 * @param fp 출력 할 파일 포인터
466 */
467int
468CF_Debug_PrintCallStack (FILE * fp)
469{
470 int iter = 0;
471
472 CF_DEBUG_CTX * ctx = gDebugSingleCtx;
473 CF_DEBUG_CALLSTACK * callstack = NULL;
474
475 ASSERT_CTX (ctx);
476
477 for ( callstack = ctx->callstack.caller
478 ; callstack
479 ; callstack = callstack->caller)
480 {
481 fprintf (fp, "#%-4d %s <%s:%d>\n",
482 iter++,
483 callstack->func,
484 callstack->file,
485 callstack->line);
486 }
487
488 return CF_OK;
489}
Note: See TracBrowser for help on using the repository browser.