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

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

#1 fix and arrange doxygen configuration file and doxygen comments

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