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

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

#1 fix and arrange doxygen configuration file and doxygen comments

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