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
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/** 디버그 컨텍스트 (Opaque) */
28typedef void * CF_Debug_Ctx;
29
30/** 콜스택 인터페이스 */
31typedef struct cf_debug_callStack {
32 char file[NAME_LENGTH + 1]; /* *< 파일 이름 */
33 char function[NAME_LENGTH + 1]; /* *< 함수 이름 */
34 int line; /* *< 라인 넘버 */
35} CF_Debug_CallStack;
36
37/** 콜스택 컨텍스트 */
38typedef struct __cf_debug_callstack__
39{
40 char file[NAME_LENGTH + 1];
41 char func[NAME_LENGTH + 1];
42 int line;
43
44 int frameIndex;
45
46 struct __cf_debug_callstack__ * caller;
47} CF_DEBUG_CALLSTACK;
48
49/** 디버그 컨텍스트 (CF_Debug_Ctx의 구현) */
50typedef struct __cf_debug_ctx__
51{
52 int fd;
53 CF_Mutex_Ctx mutex;
54
55 CF_DEBUG_CALLSTACK callstack;
56} CF_DEBUG_CTX;
57
58CF_Debug_Ctx gDebugSingleCtx = NULL;
59
60static int
61CF_Debug_Local_Print (FILE * fp,
62 const char * file,
63 const char * func,
64 const int line,
65 const char * fmt,
66 va_list valist)
67{
68 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
69 vfprintf (fp, fmt, valist);
70
71 return CF_OK;
72}
73
74static int
75CF_Debug_Local_PrintBin (FILE * fp,
76 const char * file,
77 const char * func,
78 const int line,
79 const unsigned char * bin,
80 const size_t len)
81{
82 size_t i, j;
83
84 for (i = 0 ; i < len ; i += 16)
85 {
86 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
87 fprintf (fp, "%06x : ", (unsigned int)i);
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)
101 fprintf (fp, "%c", IS_READABLE_CHAR (bin[i+j]) ? bin[i+j] : '.');
102 }
103 fprintf (fp, "\n");
104 }
105
106 return CF_OK;
107}
108
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 */
123int
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
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 */
155int
156CF_Debug_PrintBin (FILE * fp,
157 const char * file,
158 const char * func,
159 const int line,
160 const unsigned char * bin,
161 const size_t len,
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
175/**
176 * 컨텍스트에 콜스택 푸시
177 *
178 * @return 성공 시, CF_OK; 실패 시, 오류 코드
179 *
180 * @param ctx 디버그 컨텍스트
181 * @param file 파일 경로
182 * @param func 함수 이름
183 * @param line 라인 넘버
184 */
185static int
186CF_Debug_CallStackPush (CF_Debug_Ctx ctx,
187 const char * file,
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
194 ASSERT_CTX (ctx);
195
196 push = (CF_DEBUG_CALLSTACK *) calloc (sizeof (CF_DEBUG_CALLSTACK), 1);
197 if (push == NULL)
198 return CF_ERROR_DEBUG_PUSH_CALLSTACK;
199
200 /* push to callstack */
201 snprintf (push->file, NAME_LENGTH, "%s", file);
202 snprintf (push->func, NAME_LENGTH, "%s", func);
203 push->line = line;
204 push->caller = context->callstack.caller;
205 push->frameIndex = (push->caller) ? push->caller->frameIndex + 1 : 0;
206 context->callstack.caller = push;
207
208 return CF_OK;
209}
210
211/**
212 * 컨텍스트에서 콜스택에서 TOP을 제거하지 않고 가져옴
213 *
214 * @return 성공 시, CF_OK; 실패 시, 오류 코드
215 *
216 * @param ctx 디버그 컨텍스트
217 * @param callstack 콜스택 정보를 가져올 콜스택 데이터 구조체 포인터
218 *
219 * @see CF_Debug_CallStack
220 */
221static int
222CF_Debug_CallStackPeek (CF_Debug_Ctx ctx,
223 CF_Debug_CallStack * callstack)
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)
230 return CF_ERROR_DEBUG_PEEK_CALLSTACK;
231
232 if (callstack != NULL)
233 {
234 snprintf (callstack->file , NAME_LENGTH, "%s", pop->file);
235 snprintf (callstack->function, NAME_LENGTH, "%s", pop->func);
236 callstack->line = pop->line;
237 }
238
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
259 ASSERT_CTX (ctx);
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
268 context->callstack.caller = pop->caller;
269 free (pop);
270
271 return CF_OK;
272}
273
274/**
275 * 디버그 컨텍스트를 해제
276 *
277 * @return 성공 시, CF_OK; 실패 시, 오류 코드
278 *
279 * @param ctx 디버그 컨텍스트
280 *
281 * @see CF_DEBUG_DESTROY_CTX
282 */
283static int
284CF_Debug_DestroyCtx (CF_Debug_Ctx ctx)
285{
286 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
287
288 ASSERT_CTX (ctx);
289
290 while (context->callstack.caller)
291 CF_Debug_CallStackPop (ctx, NULL);
292
293 if (context->mutex)
294 CF_Mutex_DestoryCtx (&context->mutex);
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 {
318 result = CF_ERROR_DEBUG_CREATE_CTX;
319 TRY_BREAK;
320 }
321
322 result = CF_Mutex_CreateCtx (&context->mutex);
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
335 return result;
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
353 return result;
354}
355
356/**
357 * 콜스택 매니저 해제 (글로벌 컨텍스트)
358 *
359 * @return 성공 시, CF_OK; 실패 시, 오류 코드
360 */
361int
362CF_Debug_Finalize (void)
363{
364 CF_Debug_Ctx ctx = gDebugSingleCtx;
365
366 gDebugSingleCtx = NULL;
367
368 return CF_Debug_DestroyCtx (ctx);
369}
370
371/**
372 * 함수 진입을 명시 (글로벌 컨텍스트)
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{
387 CF_DEBUG_CTX * ctx = (CF_DEBUG_CTX *)gDebugSingleCtx;
388
389 ASSERT_CTX (ctx);
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/**
399 * 함수 종료를 명시 (글로벌 컨텍스트)
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
410 ASSERT_CTX (ctx);
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}
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 {
440 fprintf (fp, "#%-4d %s <%s:%d>\n",
441 iter++,
442 callstack->func,
443 callstack->file,
444 callstack->line);
445 }
446
447 return CF_OK;
448}
Note: See TracBrowser for help on using the repository browser.