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

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

#1 fix interface and add util module

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