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

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

#1 fix typecasting warning

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