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