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

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

#1 add typical data structure algorithms (linked-list / queue / stak) and rename symbol for context of each modules

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