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

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

#1 fix dependencies for thread/mutex

File size: 9.0 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/** 디버그 컨텍스트 (Opaque) */
31typedef void * CF_Debug_Ctx;
32
33/** 콜스택 인터페이스 */
34typedef struct cf_debug_callStack {
35 char file[NAME_LENGTH + 1]; /* *< 파일 이름 */
36 char function[NAME_LENGTH + 1]; /* *< 함수 이름 */
37 int line; /* *< 라인 넘버 */
38} CF_Debug_CallStack;
39
40/** 콜스택 컨텍스트 */
41typedef struct __cf_debug_callstack__
42{
43 char file[NAME_LENGTH + 1];
44 char func[NAME_LENGTH + 1];
45 int line;
46
47 int frameIndex;
48
49 struct __cf_debug_callstack__ * caller;
50} CF_DEBUG_CALLSTACK;
51
52/** 디버그 컨텍스트 (CF_Debug_Ctx의 구현) */
53typedef struct __cf_debug_ctx__
54{
55 int fd;
56 CF_Mutex_Ctx mutex;
57
58 CF_DEBUG_CALLSTACK callstack;
59} CF_DEBUG_CTX;
60
61static CF_Debug_Ctx gDebugSingleCtx = NULL;
62
63static int
64CF_Debug_Local_Print (FILE * fp,
65 const char * file,
66 const char * func,
67 const int line,
68 const char * fmt,
69 va_list valist)
70{
71 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
72 vfprintf (fp, fmt, valist);
73
74 return CF_OK;
75}
76
77static int
78CF_Debug_Local_PrintBin (FILE * fp,
79 const char * file,
80 const char * func,
81 const int line,
82 const cf_byte * bin,
83 const size_t len)
84{
85 size_t i, j;
86
87 for (i = 0 ; i < len ; i += 16)
88 {
89 fprintf (fp, "[DEBUG][%s:%d][%s] ", file, line, func);
90 fprintf (fp, "%06x : ", (unsigned int)i);
91
92 for (j = 0 ; j < 16 ; j++)
93 {
94 if (i+j < len)
95 fprintf (fp, "%02x ", bin[i+j]);
96 else
97 fprintf (fp, " ");
98 }
99 fprintf (fp, " ");
100
101 for (j = 0 ; j < 16 ; j++)
102 {
103 if (i+j < len)
104 fprintf (fp, "%c", IS_READABLE_CHAR (bin[i+j]) ? bin[i+j] : '.');
105 }
106 fprintf (fp, "\n");
107 }
108
109 return CF_OK;
110}
111
112/**
113 * 디버그 메시지를 지정된 파일 포인터로 출력
114 *
115 * \return 성공 시, CF_OK; 실패 시, 오류 코드
116 *
117 * \param fp 파일 포인터. 표준출력(stdout) 및 표준오류(stderr) 사용 가능
118 * \param file 파일 경로
119 * \param func 함수 이름
120 * \param line 라인 넘버
121 * \param fmt 포맷 스트링
122 * \param ... 가변 인자
123 *
124 * \see CF_DEBUG_PRINT
125 */
126int
127CF_Debug_Print (FILE * fp,
128 const char * file,
129 const char * func,
130 const int line,
131 const char * fmt, ...)
132{
133 va_list valist;
134
135 va_start (valist, fmt);
136 CF_Debug_Local_Print (fp, file, func, line, fmt, valist);
137 va_end (valist);
138
139 return CF_OK;
140}
141
142/**
143 * 바이너리 데이터를 디버그 메시지와 함께 지정된 파일 포인터로 출력
144 *
145 * \return CF_OK 반환
146 *
147 * \param fp 파일 포인터. 표준출력(stdout) 및 표준오류(stderr) 사용 가능
148 * \param file 파일 경로
149 * \param func 함수 이름
150 * \param line 라인 넘버
151 * \param bin 라인 넘버
152 * \param len 바이너리 길이
153 * \param fmt 포맷 스트링
154 * \param ... 가변 인자
155 *
156 * \see CF_DEBUG_PRINT_BIN
157 */
158int
159CF_Debug_PrintBin (FILE * fp,
160 const char * file,
161 const char * func,
162 const int line,
163 const cf_byte * bin,
164 const size_t len,
165 const char * fmt, ...)
166{
167 va_list valist;
168
169 va_start (valist, fmt);
170 CF_Debug_Local_Print (fp, file, func, line, fmt, valist);
171 va_end (valist);
172
173 CF_Debug_Local_PrintBin (fp, file, func, line, bin, len);
174
175 return CF_OK;
176}
177
178/**
179 * 컨텍스트에 콜스택 푸시
180 *
181 * \return 성공 시, CF_OK; 실패 시, 오류 코드
182 *
183 * \param ctx 디버그 컨텍스트
184 * \param file 파일 경로
185 * \param func 함수 이름
186 * \param line 라인 넘버
187 */
188static int
189CF_Debug_CallStackPush (CF_Debug_Ctx ctx,
190 const char * file,
191 const char * func,
192 const int line)
193{
194 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
195 CF_DEBUG_CALLSTACK * push = NULL;
196
197 ASSERT_CTX (ctx);
198
199 push = (CF_DEBUG_CALLSTACK *) calloc (sizeof (CF_DEBUG_CALLSTACK), 1);
200 if (push == NULL)
201 return CF_ERROR_DEBUG_PUSH_CALLSTACK;
202
203 /* push to callstack */
204 snprintf (push->file, NAME_LENGTH, "%s", file);
205 snprintf (push->func, NAME_LENGTH, "%s", func);
206 push->line = line;
207 push->caller = context->callstack.caller;
208 push->frameIndex = (push->caller) ? push->caller->frameIndex + 1 : 0;
209 context->callstack.caller = push;
210
211 return CF_OK;
212}
213
214/**
215 * 컨텍스트에서 콜스택에서 TOP을 제거하지 않고 가져옴
216 *
217 * \return 성공 시, CF_OK; 실패 시, 오류 코드
218 *
219 * \param ctx 디버그 컨텍스트
220 * \param callstack 콜스택 정보를 가져올 콜스택 데이터 구조체 포인터
221 *
222 * \see CF_Debug_CallStack
223 */
224static int
225CF_Debug_CallStackPeek (CF_Debug_Ctx ctx,
226 CF_Debug_CallStack * callstack)
227{
228 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
229 CF_DEBUG_CALLSTACK * pop = NULL;
230
231 pop = context->callstack.caller;
232 if (pop == NULL)
233 return CF_ERROR_DEBUG_PEEK_CALLSTACK;
234
235 if (callstack != NULL)
236 {
237 snprintf (callstack->file , NAME_LENGTH, "%s", pop->file);
238 snprintf (callstack->function, NAME_LENGTH, "%s", pop->func);
239 callstack->line = pop->line;
240 }
241
242 return CF_OK;
243}
244
245/**
246 * 컨텍스트에서 콜스택 팝
247 *
248 * \return 성공 시, CF_OK; 실패 시, 오류 코드
249 *
250 * \param ctx 디버그 컨텍스트
251 * \param callstack 콜스택 정보를 가져올 콜스택 데이터 구조체 포인터
252 *
253 * \see CF_Debug_CallStack
254 */
255static int
256CF_Debug_CallStackPop (CF_Debug_Ctx ctx,
257 CF_Debug_CallStack * callstack)
258{
259 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
260 CF_DEBUG_CALLSTACK * pop = NULL;
261
262 ASSERT_CTX (ctx);
263
264 pop = context->callstack.caller;
265 if (pop == NULL)
266 return CF_ERROR_DEBUG_POP_CALLSTACK;
267
268 if (CF_Debug_CallStackPeek (ctx, callstack) < 0)
269 return CF_ERROR_DEBUG_PEEK_CALLSTACK;
270
271 context->callstack.caller = pop->caller;
272 free (pop);
273
274 return CF_OK;
275}
276
277/**
278 * 디버그 컨텍스트를 해제
279 *
280 * \return 성공 시, CF_OK; 실패 시, 오류 코드
281 *
282 * \param ctx 디버그 컨텍스트
283 */
284static int
285CF_Debug_DestroyCtx (CF_Debug_Ctx ctx)
286{
287 CF_DEBUG_CTX * context = (CF_DEBUG_CTX *) ctx;
288
289 ASSERT_CTX (ctx);
290
291 while (context->callstack.caller)
292 CF_Debug_CallStackPop (ctx, NULL);
293
294 if (context->mutex)
295 CF_Mutex_DestoryCtx (context->mutex);
296
297 free (context);
298
299 return CF_OK;
300}
301
302/**
303 * 디버그 컨텍스트를 생성
304 *
305 * \return 성공 시, CF_Debug_Ctx 형태의 컨텍스트; 실패 시, NULL
306 *
307 * \param 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 */
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 */
380int
381CF_Debug_EnterFunction (const char * file,
382 const char * func,
383 const int line)
384{
385 CF_DEBUG_CTX * ctx = (CF_DEBUG_CTX *)gDebugSingleCtx;
386
387 ASSERT_CTX (ctx);
388
389 CF_Mutex_Lock (ctx->mutex);
390 CF_Debug_CallStackPush (gDebugSingleCtx, file, func, line);
391 CF_Mutex_Unlock (ctx->mutex);
392
393 return CF_OK;
394}
395
396/**
397 * 함수 종료를 명시 (글로벌 컨텍스트)
398 *
399 * \return 성공 시, CF_OK; 실패 시, 오류 코드
400 */
401int
402CF_Debug_LeaveFunction (void)
403{
404 CF_DEBUG_CTX * ctx = (CF_DEBUG_CTX *)gDebugSingleCtx;
405
406 ASSERT_CTX (ctx);
407
408 CF_Mutex_Lock (ctx->mutex);
409 CF_Debug_CallStackPop (gDebugSingleCtx, NULL);
410 CF_Mutex_Unlock (ctx->mutex);
411
412 return CF_OK;
413}
414
415/**
416 * 현재 콜스택을 출력 (글로벌 컨텍스트)
417 *
418 * \return 성공 시, CF_OK; 실패 시, 오류 코드
419 *
420 * \param fp 출력 할 파일 포인터
421 */
422int
423CF_Debug_PrintCallStack (FILE * fp)
424{
425 int iter = 0;
426
427 CF_DEBUG_CTX * ctx = gDebugSingleCtx;
428 CF_DEBUG_CALLSTACK * callstack = NULL;
429
430 ASSERT_CTX (ctx);
431
432 for ( callstack = ctx->callstack.caller
433 ; callstack
434 ; callstack = callstack->caller)
435 {
436 fprintf (fp, "#%-4d %s <%s:%d>\n",
437 iter++,
438 callstack->func,
439 callstack->file,
440 callstack->line);
441 }
442
443 return CF_OK;
444}
Note: See TracBrowser for help on using the repository browser.