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

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

#1 fix preprocessor definition for windows

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