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

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

#1 remove unused symbol from doxygen comment

File size: 9.1 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
9#include <stdlib.h>
10#include <ctype.h>
11#include <stdarg.h>
12#include <string.h>
13
14#ifdef _WIN32
15# include <io.h>
16#else
17# include <unistd.h>
18#endif
19
20#define IS_READABLE_CHAR(__c) (' ' <= __c && __c <= '~')
21
22#define CHECK_INVALID_CTX(__ctx) \
23 if (__ctx == NULL) \
24 return CF_ERROR_DEBUG_INVALID_CTX
25
26#define GET_CTX_OSTREAM(__ctx) \
27 ((((CF_DEBUG_CTX *)__ctx)->fp == NULL) \
28 ? stderr \
29 : ((CF_DEBUG_CTX *)__ctx)->fp)
30
31typedef struct __cf_debug_callstack__
32{
33 char file[NAME_LENGTH + 1];
34 char func[NAME_LENGTH + 1];
35 int line;
36
37 struct __cf_debug_callstack__ * caller;
38} S_CF_DEBUG_CALLSTACK, CF_DEBUG_CALLSTACK;
39
40typedef struct __cf_debug_ctx__
41{
42 char file[NAME_LENGTH + 1];
43 char func[NAME_LENGTH + 1];
44 int line;
45
46 FILE * fp;
47
48 CF_DEBUG_CALLSTACK callstack;
49} S_CF_DEBUG_CTX, CF_DEBUG_CTX;
50
51static int
52CF_Debug_Local_UpdateCtx (CF_Debug_Ctx ctx,
53 const char * file,
54 const char * func,
55 const int line)
56{
57 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
58
59 CHECK_INVALID_CTX (ctx);
60
61 strncpy (context->file, file, strlen (file));
62 strncpy (context->func, func, strlen (func));
63 context->line = line;
64
65 return CF_OK;
66}
67
68static int
69CF_Debug_Local_Print (FILE * fp,
70 const char * file,
71 const char * func,
72 const int line,
73 const char * fmt,
74 va_list valist)
75{
76 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
77 vfprintf (fp, fmt, valist);
78
79 return CF_OK;
80}
81
82static int
83CF_Debug_Local_PrintBin (FILE * fp,
84 const char * file,
85 const char * func,
86 const int line,
87 const unsigned char * bin,
88 const int len)
89{
90 int i, j;
91
92 for (i = 0 ; i < len ; i += 16)
93 {
94 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
95 fprintf (fp, "%06x : ", i);
96
97 for (j = 0 ; j < 16 ; j++)
98 {
99 if (i+j < len)
100 fprintf (fp, "%02x ", bin[i+j]);
101 else
102 fprintf (fp, " ");
103 }
104 fprintf (fp, " ");
105
106 for (j = 0 ; j < 16 ; j++)
107 {
108 if (i+j < len)
109 fprintf (fp, "%c", IS_READABLE_CHAR(bin[i+j]) ? bin[i+j] : '.');
110 }
111 fprintf (fp, "\n");
112 }
113
114 return CF_OK;
115}
116
117/**
118 * 디버그 컨텍스트를 생성
119 *
120 * @return 성공 시, CF_Debug_Ctx 형태의 컨텍스트; 실패 시, NULL
121 * @see CF_DEBUG_CREATE_CTX
122 */
123CF_Debug_Ctx
124CF_Debug_CreateCtx (void)
125{
126 CF_DEBUG_CTX * ctx = NULL;
127
128 ctx = (CF_DEBUG_CTX *) calloc (sizeof (CF_DEBUG_CTX), 1);
129
130 return (CF_Debug_Ctx) ctx;
131}
132
133/**
134 * 디버그 컨텍스트를 해제
135 *
136 * @return 성공 시, CF_OK; 실패 시, 오류 코드
137 *
138 * @param ctx 디버그 컨텍스트
139 *
140 * @see CF_DEBUG_DESTROY_CTX
141 */
142int
143CF_Debug_DestroyCtx (CF_Debug_Ctx ctx)
144{
145 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
146 CF_DEBUG_CALLSTACK * pop = NULL;
147 CF_DEBUG_CALLSTACK * next = NULL;
148
149 CHECK_INVALID_CTX (ctx);
150
151 if (context->fp != NULL)
152 fclose (context->fp);
153
154 for (pop = next = context->callstack.caller ; pop ; pop = next)
155 {
156 next = next->caller;
157 free (pop);
158 }
159
160 free (context);
161
162 return CF_OK;
163}
164
165/**
166 * 디버그 컨텍스트에 출력할 파일 디스크립터를 설정
167 *
168 * @return 성공 시, CF_OK; 실패 시, 오류 코드
169 *
170 * @param ctx 디버그 컨텍스트
171 * @param fd 파일 디스크립터
172 *
173 * @see CF_File_Open, CF_File_Create
174 */
175int
176CF_Debug_SetOutputFD (CF_Debug_Ctx ctx,
177 int fd)
178{
179 int result = 0;
180 int dupfd = 0;
181
182 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
183 FILE * fp = NULL;
184
185 CHECK_INVALID_CTX (ctx);
186
187 TRY
188 {
189 dupfd = dup (fd);
190 if (dupfd < 0)
191 {
192 result = -1;
193 TRY_BREAK;
194 }
195
196 fp = fdopen (dupfd, "a");
197 if (fp == NULL)
198 {
199 close (dupfd);
200 result = -2;
201 TRY_BREAK;
202 }
203
204 context->fp = fp;
205 }
206 CATCH_IF (result < 0)
207 {
208 return CF_ERROR_DEBUG_SET_OUTPUT_FD;
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 * @param fmt 포맷 스트링
290 * @param ... 가변 인자
291 *
292 * @see CF_Debug_Trace
293 */
294int
295CF_Debug_Trace (CF_Debug_Ctx ctx,
296 const char * file,
297 const char * func,
298 const int line,
299 const char * fmt, ...)
300{
301 va_list valist;
302 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
303
304 CHECK_INVALID_CTX (ctx);
305
306 CF_Debug_Local_UpdateCtx (ctx, file, func, line);
307
308 va_start (valist, fmt);
309 CF_Debug_Local_Print (GET_CTX_OSTREAM (context),
310 context->file,
311 context->func,
312 context->line,
313 fmt, valist);
314 va_end (valist);
315
316 return CF_OK;
317}
318
319/**
320 * 컨텍스트를 업데이트하고 바이너리 데이터를 디버그 메시지와 함께 출력
321 *
322 * @return 성공 시, CF_OK; 실패 시, 오류 코드
323 *
324 * @param ctx 디버그 컨텍스트
325 * @param file 파일 경로
326 * @param func 함수 이름
327 * @param line 라인 넘버
328 * @param bin 바이너리 데이터
329 * @param len 바이너리 길이
330 * @param fmt 포맷 스트링
331 * @param ... 가변 인자
332 *
333 * @see CF_DEBUG_TRACE_BIN
334 */
335int
336CF_Debug_TraceBin (CF_Debug_Ctx ctx,
337 const char * file,
338 const char * func,
339 const int line,
340 const unsigned char * bin,
341 const int len,
342 const char * fmt, ...)
343{
344 va_list valist;
345 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
346
347 CHECK_INVALID_CTX (ctx);
348
349 CF_Debug_Local_UpdateCtx (ctx, file, func, line);
350
351 va_start (valist, fmt);
352 CF_Debug_Local_Print (GET_CTX_OSTREAM (context),
353 context->file,
354 context->func,
355 context->line,
356 fmt, valist);
357 va_end (valist);
358
359 CF_Debug_Local_PrintBin (GET_CTX_OSTREAM (context),
360 context->file,
361 context->func,
362 context->line,
363 bin, len);
364
365 return CF_OK;
366}
367
368/**
369 * 컨텍스트에 콜스택 푸시
370 *
371 * @return 성공 시, CF_OK; 실패 시, 오류 코드
372 *
373 * @param ctx 디버그 컨텍스트
374 * @param file 파일 경로
375 * @param func 함수 이름
376 * @param line 라인 넘버
377 *
378 * @see CF_DEBUG_CALLSTACK_PUSH
379 */
380int
381CF_Debug_CallStackPush (CF_Debug_Ctx ctx,
382 const char * file,
383 const char * func,
384 const int line)
385{
386 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
387 CF_DEBUG_CALLSTACK * push = NULL;
388
389 CHECK_INVALID_CTX (ctx);
390
391 push = (CF_DEBUG_CALLSTACK *) calloc (sizeof (CF_DEBUG_CALLSTACK), 1);
392 if (push == NULL)
393 return CF_ERROR_DEBUG_PUSH_CALLSTACK;
394
395 /* push to callstack */
396 sprintf (push->file, "%s", file);
397 sprintf (push->func, "%s", func);
398 push->line = line;
399 push->caller = context->callstack.caller;
400 context->callstack.caller = push;
401
402 CF_Debug_Local_UpdateCtx (ctx, file, func, line);
403
404 return CF_OK;
405}
406
407/**
408 * 컨텍스트에서 콜스택 팝
409 *
410 * @return 성공 시, CF_OK; 실패 시, 오류 코드
411 *
412 * @param ctx 디버그 컨텍스트
413 * @param callstack 콜스택 정보를 가져올 콜스택 데이터 구조체 포인터
414 *
415 * @see CF_Debug_CallStackPop, CF_Debug_CallStack
416 */
417int
418CF_Debug_CallStackPop (CF_Debug_Ctx ctx,
419 CF_Debug_CallStack * callstack)
420{
421 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
422 CF_DEBUG_CALLSTACK * pop = NULL;
423
424 CHECK_INVALID_CTX (ctx);
425
426 pop = context->callstack.caller;
427 if (pop == NULL)
428 return CF_ERROR_DEBUG_POP_CALLSTACK;
429
430 if (callstack != NULL)
431 {
432 sprintf (callstack->file , "%s", pop->file);
433 sprintf (callstack->function, "%s", pop->func);
434 callstack->line = pop->line;
435 }
436
437 memset (context->file, 0x00, sizeof (context->file));
438 memset (context->func, 0x00, sizeof (context->func));
439 context->line = 0;
440
441 /* restore current context */
442 if (pop->caller != NULL)
443 {
444 CF_Debug_Local_UpdateCtx (ctx,
445 pop->caller->file,
446 pop->caller->func,
447 pop->caller->line);
448 }
449
450 context->callstack.caller = pop->caller;
451 free (pop);
452
453 return CF_OK;
454}
Note: See TracBrowser for help on using the repository browser.