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
RevLine 
[6]1/**
[28]2 * @file cf_debug.c
3 * @author myusgun <myusgun@gmail.com>
[6]4 */
5#include "cf_debug.h"
6#include "cf_local.h"
[40]7#include "cf_error.h"
[51]8#include "cf_thread.h"
[6]9
10#include <stdlib.h>
11#include <ctype.h>
12#include <stdarg.h>
[9]13#include <string.h>
[6]14
[50]15#if defined(_WIN32) || defined(_WIN64)
[7]16# include <io.h>
[6]17#else
18# include <unistd.h>
19#endif
20
21#define IS_READABLE_CHAR(__c) (' ' <= __c && __c <= '~')
22
[85]23#define ASSERT_CTX(__ctx) \
24 if (__ctx == NULL) \
[6]25 return CF_ERROR_DEBUG_INVALID_CTX
[10]26
[51]27/**
28 * 디버그 컨텍스트
29 *
30 * @remark change from public to private
31 */
32typedef void * CF_Debug_Ctx;
33
[53]34/* *
[51]35 * 콜스택 데이터
36 *
37 * @remark change from public to private
38 */
39typedef struct cf_debug_callStack {
[53]40 char file[NAME_LENGTH + 1]; /* *< 파일 이름 */
41 char function[NAME_LENGTH + 1]; /* *< 함수 이름 */
42 int line; /* *< 라인 넘버 */
[51]43} CF_Debug_CallStack;
44
[6]45typedef struct __cf_debug_callstack__
46{
[9]47 char file[NAME_LENGTH + 1];
[6]48 char func[NAME_LENGTH + 1];
49 int line;
50
[51]51 int frameIndex;
52
[6]53 struct __cf_debug_callstack__ * caller;
54} S_CF_DEBUG_CALLSTACK, CF_DEBUG_CALLSTACK;
55
[10]56typedef struct __cf_debug_ctx__
[6]57{
[51]58 char file[NAME_LENGTH + 1];
59 char func[NAME_LENGTH + 1];
60 int line;
[6]61
[51]62 CF_Mutex mutex;
[6]63
64 CF_DEBUG_CALLSTACK callstack;
65} S_CF_DEBUG_CTX, CF_DEBUG_CTX;
66
[51]67CF_Debug_Ctx gDebugSingleCtx = NULL;
68
[23]69static int
[26]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
[55]77 ASSERT_CTX (ctx);
[26]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
[16]87CF_Debug_Local_Print (FILE * fp,
88 const char * file,
89 const char * func,
90 const int line,
[12]91 const char * fmt,
92 va_list valist)
[6]93{
[16]94 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
95 vfprintf (fp, fmt, valist);
[14]96
97 return CF_OK;
[6]98}
99
[23]100static int
[16]101CF_Debug_Local_PrintBin (FILE * fp,
102 const char * file,
103 const char * func,
104 const int line,
105 const unsigned char * bin,
[66]106 const size_t len)
[16]107{
[67]108 size_t i, j;
[16]109
110 for (i = 0 ; i < len ; i += 16)
111 {
112 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
[69]113 fprintf (fp, "%06x : ", (unsigned int)i);
[16]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)
[87]127 fprintf (fp, "%c", IS_READABLE_CHAR (bin[i+j]) ? bin[i+j] : '.');
[16]128 }
129 fprintf (fp, "\n");
130 }
131
132 return CF_OK;
133}
134
[35]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 */
[6]149int
[16]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
[35]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 */
[16]181int
182CF_Debug_PrintBin (FILE * fp,
183 const char * file,
184 const char * func,
185 const int line,
186 const unsigned char * bin,
[66]187 const size_t len,
[16]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
[35]201/**
202 * 컨텍스트에 콜스택 푸시
203 *
204 * @return 성공 시, CF_OK; 실패 시, 오류 코드
205 *
206 * @param ctx 디버그 컨텍스트
207 * @param file 파일 경로
208 * @param func 함수 이름
209 * @param line 라인 넘버
210 */
[51]211static int
[6]212CF_Debug_CallStackPush (CF_Debug_Ctx ctx,
[9]213 const char * file,
[6]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
[55]220 ASSERT_CTX (ctx);
[6]221
222 push = (CF_DEBUG_CALLSTACK *) calloc (sizeof (CF_DEBUG_CALLSTACK), 1);
223 if (push == NULL)
224 return CF_ERROR_DEBUG_PUSH_CALLSTACK;
225
[9]226 /* push to callstack */
[107]227 snprintf (push->file, NAME_LENGTH, "%s", file);
228 snprintf (push->func, NAME_LENGTH, "%s", func);
[6]229 push->line = line;
230 push->caller = context->callstack.caller;
[87]231 push->frameIndex = (push->caller) ? push->caller->frameIndex + 1 : 0;
[6]232 context->callstack.caller = push;
233
[26]234 CF_Debug_Local_UpdateCtx (ctx, file, func, line);
[9]235
[6]236 return CF_OK;
237}
238
[35]239/**
[51]240 * 컨텍스트에서 콜스택에서 TOP을 제거하지 않고 가져옴
[35]241 *
242 * @return 성공 시, CF_OK; 실패 시, 오류 코드
243 *
244 * @param ctx 디버그 컨텍스트
245 * @param callstack 콜스택 정보를 가져올 콜스택 데이터 구조체 포인터
246 *
[51]247 * @see CF_Debug_CallStack
[35]248 */
[51]249static int
250CF_Debug_CallStackPeek (CF_Debug_Ctx ctx,
251 CF_Debug_CallStack * callstack)
[6]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)
[51]258 return CF_ERROR_DEBUG_PEEK_CALLSTACK;
[6]259
[9]260 if (callstack != NULL)
261 {
[107]262 snprintf (callstack->file , NAME_LENGTH, "%s", pop->file);
263 snprintf (callstack->function, NAME_LENGTH, "%s", pop->func);
[9]264 callstack->line = pop->line;
265 }
[6]266
[51]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
[55]287 ASSERT_CTX (ctx);
[51]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
[9]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 {
[26]303 CF_Debug_Local_UpdateCtx (ctx,
304 pop->caller->file,
305 pop->caller->func,
306 pop->caller->line);
[9]307 }
308
[14]309 context->callstack.caller = pop->caller;
[6]310 free (pop);
311
312 return CF_OK;
313}
[51]314
315/**
[62]316 * 디버그 컨텍스트를 해제
[51]317 *
318 * @return 성공 시, CF_OK; 실패 시, 오류 코드
319 *
[62]320 * @param ctx 디버그 컨텍스트
321 *
322 * @see CF_DEBUG_DESTROY_CTX
323 */
324static int
325CF_Debug_DestroyCtx (CF_Debug_Ctx ctx)
326{
[71]327 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
[62]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
[80]376 return result;
[62]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
[80]394 return result;
[62]395}
396
397/**
398 * 콜스택 매니저 해제 (글로벌 컨텍스트)
399 *
400 * @return 성공 시, CF_OK; 실패 시, 오류 코드
401 */
402int
403CF_Debug_Finalize (void)
404{
[71]405 CF_Debug_Ctx ctx = gDebugSingleCtx;
406
407 gDebugSingleCtx = NULL;
408
409 return CF_Debug_DestroyCtx (ctx);
[62]410}
411
412/**
413 * 함수 진입을 명시 (글로벌 컨텍스트)
[51]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{
[62]428 CF_DEBUG_CTX * ctx = (CF_DEBUG_CTX *)gDebugSingleCtx;
[51]429
[62]430 ASSERT_CTX (ctx);
[51]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/**
[62]440 * 함수 종료를 명시 (글로벌 컨텍스트)
[51]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
[62]451 ASSERT_CTX (ctx);
[51]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}
[63]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 {
[87]481 fprintf (fp, "#%-4d %s <%s:%d>\n",
482 iter++,
483 callstack->func,
484 callstack->file,
485 callstack->line);
[63]486 }
487
488 return CF_OK;
489}
Note: See TracBrowser for help on using the repository browser.