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

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

#1 refactoring log writing functions

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