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

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

#1 change the debugging utiltity to support single context with mutex

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