Branch data Line data Source code
1 : : /*@{*/
2 : :
3 : : #include "sysdep.h"
4 : : #include <sys/types.h>
5 : : #include <sys/stat.h>
6 : : #include <unistd.h>
7 : : #include <dirent.h>
8 : : #include <errno.h>
9 : : #include <stdio.h>
10 : : #include <stdarg.h>
11 : : #include <string.h>
12 : :
13 : : #if HAVE_BACKTRACE
14 : : #include <execinfo.h>
15 : : #endif
16 : :
17 : : #include "libcitadel.h"
18 : : #include "libcitadellocal.h"
19 : :
20 : :
21 : : ConstStr WF_MsgStrs[] = {
22 : : {HKEY("LOG")},
23 : : {HKEY("INFO")},
24 : : {HKEY("WARN")},
25 : : {HKEY("ERROR")},
26 : : {HKEY("TRACE")},
27 : : {HKEY("EXCEPTION")}
28 : : };
29 : :
30 : 13 : static JsonValue *WFInfo(const char *Filename, long fnlen,
31 : : long LineNo,
32 : : WF_MessageType Type)
33 : : {
34 : : JsonValue *Val;
35 : :
36 : 13 : Val = NewJsonObject(NULL, 0);
37 : 13 : JsonObjectAppend(Val,
38 : : NewJsonPlainString(HKEY("Type"),
39 : : WF_MsgStrs[Type].Key,
40 : : WF_MsgStrs[Type].len));
41 : 13 : JsonObjectAppend(Val,
42 : : NewJsonPlainString(HKEY("File"),
43 : : Filename, fnlen));
44 : 13 : JsonObjectAppend(Val,
45 : : NewJsonNumber(HKEY("Line"), LineNo));
46 : 13 : return Val;
47 : : }
48 : :
49 : :
50 : 0 : JsonValue *WildFireMessage(const char *Filename, long fnlen,
51 : : long LineNo,
52 : : StrBuf *Msg,
53 : : WF_MessageType Type)
54 : : {
55 : : JsonValue *Ret;
56 : :
57 : 0 : Ret = NewJsonArray(NULL, 0);
58 : 0 : JsonArrayAppend(Ret, WFInfo(Filename, fnlen,
59 : : LineNo, Type));
60 : :
61 : 0 : JsonArrayAppend(Ret,
62 : : NewJsonString(NULL, 0, Msg));
63 : 0 : return Ret;
64 : : }
65 : :
66 : 5 : JsonValue *WildFireMessagePlain(const char *Filename, long fnlen,
67 : : long LineNo,
68 : : const char *Message, long len,
69 : : WF_MessageType Type)
70 : : {
71 : : JsonValue *Val;
72 : 5 : Val = NewJsonArray(NULL, 0);
73 : :
74 : 5 : JsonArrayAppend(Val, WFInfo(Filename, fnlen,
75 : : LineNo, Type));
76 : 5 : JsonArrayAppend(Val,
77 : : NewJsonPlainString(NULL, 0, Message, len));
78 : 5 : return Val;
79 : : }
80 : :
81 : 0 : void WildFireAddArray(JsonValue *ReportBase, JsonValue *Array, WF_MessageType Type)
82 : : {
83 : : JsonValue *Val;
84 : 0 : Val = NewJsonArray(NULL, 0);
85 : 0 : JsonArrayAppend(Val,
86 : : NewJsonPlainString(NULL, 0,
87 : : WF_MsgStrs[Type].Key,
88 : : WF_MsgStrs[Type].len));
89 : :
90 : 0 : JsonArrayAppend(Val, Array);
91 : 0 : }
92 : :
93 : : int addr2line_write_pipe[2];
94 : : int addr2line_read_pipe[2];
95 : : pid_t addr2line_pid;
96 : :
97 : : #ifdef HAVE_BACKTRACE
98 : : /*
99 : : * Start up the addr2line daemon so we can decode function pointers
100 : : */
101 : 1 : static void start_addr2line_daemon(const char *binary)
102 : : {
103 : : struct stat filestats;
104 : : int i;
105 : 1 : const char *addr2line = "/usr/bin/addr2line";
106 : 1 : const char minuse[] = "-e";
107 : :
108 : 1 : printf("Starting addr2line daemon for decoding of backtraces\n");
109 : :
110 [ + - - + ]: 1 : if ((stat(addr2line, &filestats)==-1) ||
111 : 1 : (filestats.st_size==0)){
112 : 0 : printf("didn't find addr2line daemon in %s: %s\n", addr2line, strerror(errno));
113 : 0 : abort();
114 : : }
115 [ - + ]: 1 : if (pipe(addr2line_write_pipe) != 0) {
116 : 0 : printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
117 : 0 : abort();
118 : : }
119 [ - + ]: 1 : if (pipe(addr2line_read_pipe) != 0) {
120 : 0 : printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
121 : 0 : abort();
122 : : }
123 : :
124 : 1 : addr2line_pid = fork();
125 [ - + ]: 2 : if (addr2line_pid < 0) {
126 : 0 : printf("Unable to fork addr2line daemon: %s\n", strerror(errno));
127 : 0 : abort();
128 : : }
129 [ + + ]: 2 : if (addr2line_pid == 0) {
130 : 1 : dup2(addr2line_write_pipe[0], 0);
131 : 1 : dup2(addr2line_read_pipe[1], 1);
132 [ + + ]: 255 : for (i=2; i<256; ++i) close(i);
133 : 1 : execl(addr2line, addr2line, minuse, binary, NULL);
134 : 1 : printf("Unable to exec addr2line daemon: %s\n", strerror(errno));
135 : 0 : abort();
136 : : exit(errno);
137 : : }
138 : 1 : }
139 : :
140 : 17 : static int addr2lineBacktrace(StrBuf *Function,
141 : : StrBuf *FileName,
142 : : StrBuf *Pointer,
143 : : StrBuf *Buf,
144 : : unsigned int *FunctionLine)
145 : :
146 : : {
147 : : const char *err;
148 : : const char *pch, *pche;
149 : :
150 : 17 : write(addr2line_write_pipe[1], SKEY(Pointer));
151 [ - + ]: 17 : if (StrBufTCP_read_line(Buf, &addr2line_read_pipe[0], 0, &err) <= 0)
152 : : {
153 : 0 : StrBufAppendBufPlain(Buf, err, -1, 0);
154 : 0 : return 0;
155 : : }
156 : 17 : pch = ChrPtr(Buf);
157 : 17 : pche = strchr(pch, ':');
158 : 17 : FlushStrBuf(FileName);
159 : 17 : StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
160 [ + - ]: 17 : if (pche != NULL)
161 : : {
162 : 17 : pche++;
163 : 17 : *FunctionLine = atoi(pche);
164 : : }
165 : : else
166 : 0 : *FunctionLine = 0;
167 : 17 : return 1;
168 : : }
169 : :
170 : 18 : static int ParseBacktrace(char *Line,
171 : : StrBuf *Function,
172 : : StrBuf *FileName,
173 : : unsigned int *FunctionLine)
174 : : {
175 : : char *pch, *pche;
176 : :
177 : 18 : pch = Line;
178 : 18 : pche = strchr(pch, '(');
179 [ - + ]: 18 : if (pche == NULL) return 0;
180 : 18 : StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
181 : 18 : pch = pche + 1;
182 : 18 : pche = strchr(pch, '+');
183 [ + + ]: 18 : if (pche == NULL) return 0;
184 : 10 : StrBufAppendBufPlain(Function, pch, pche - pch, 0);
185 : 10 : pch = pche + 1;
186 : 10 : pche = strchr(pch, ')');
187 [ - + ]: 10 : if (pche == NULL) return 0;
188 : 10 : *pche = '\0';
189 : 10 : sscanf(pch, "%x", FunctionLine);
190 : 10 : StrBufAppendBufPlain(Function, pche + 1, -1, 0);
191 : 18 : return 1;
192 : : }
193 : : #endif
194 : : long BaseFrames = 0;
195 : : StrBuf *FullBinaryName = NULL;
196 : :
197 : 26 : void WildFireShutdown(void)
198 : : {
199 : 26 : close(addr2line_write_pipe[0]);
200 : 26 : close(addr2line_read_pipe[0]);
201 : :
202 : 26 : FreeStrBuf(&FullBinaryName);
203 : 26 : }
204 : :
205 : 1 : void WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip)
206 : : {
207 : :
208 : : #ifdef HAVE_BACKTRACE
209 : : void *stack_frames[100];
210 : : size_t size;
211 : : long i;
212 : : char **strings;
213 : : StrBuf *FileName;
214 : : StrBuf *Function;
215 : : StrBuf *Pointer;
216 : : StrBuf *Buf;
217 : : unsigned int FunctionLine;
218 : : struct stat filestats;
219 : :
220 : 1 : FileName = NewStrBuf();
221 : 1 : Function = NewStrBuf();
222 : 1 : Pointer = NewStrBuf();
223 : 1 : Buf = NewStrBuf();
224 : :
225 : 1 : BaseFrames = size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
226 : 1 : BaseFrames --;
227 : 1 : BaseFrames += AddBaseFrameSkip;
228 : 1 : strings = backtrace_symbols(stack_frames, size);
229 [ + + ]: 2 : for (i = 1; i < size; i++) {
230 [ + - ]: 1 : if (strings != NULL){
231 : 1 : ParseBacktrace(strings[i], Function,
232 : : FileName,
233 : : &FunctionLine);
234 : 1 : FullBinaryName = NewStrBufDup(FileName);
235 : 1 : size = i;
236 : : }
237 : : else {
238 : : char path[256];
239 : 0 : getcwd(path, sizeof(path));
240 : 0 : FullBinaryName = NewStrBufPlain(path, -1);
241 : 0 : StrBufAppendBufPlain(FullBinaryName, HKEY("/"), 0);
242 : 0 : StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
243 : 0 : i = size;
244 : : }
245 : : }
246 [ + - ][ - + ]: 1 : if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
247 : 1 : (filestats.st_size==0)){
248 : 0 : FlushStrBuf(FullBinaryName);
249 : 0 : StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
250 [ # # # # ]: 0 : if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
251 : 0 : (filestats.st_size==0)){
252 : 0 : FlushStrBuf(FullBinaryName);
253 : 0 : fprintf(stderr, "unable to open my binary for addr2line checking, verbose backtraces won't work.\n");
254 : : }
255 : : }
256 : 1 : free(strings);
257 : 1 : FreeStrBuf(&FileName);
258 : 1 : FreeStrBuf(&Function);
259 : 1 : FreeStrBuf(&Pointer);
260 : 1 : FreeStrBuf(&Buf);
261 [ + - ]: 1 : if (StrLength(FullBinaryName) > 0)
262 : 1 : start_addr2line_daemon(ChrPtr(FullBinaryName));
263 : : #endif
264 : :
265 : :
266 : 1 : }
267 : :
268 : :
269 : 8 : JsonValue *WildFireException(const char *Filename, long FileLen,
270 : : long LineNo,
271 : : StrBuf *Message,
272 : : int StackOffset)
273 : : {
274 : : JsonValue *ExcClass;
275 : : JsonValue *Val;
276 : 8 : Val = NewJsonArray(NULL, 0);
277 : :
278 : 8 : JsonArrayAppend(Val, WFInfo(Filename, FileLen,
279 : : LineNo, eEXCEPTION));
280 : :
281 : 8 : ExcClass = NewJsonObject(WF_MsgStrs[eTRACE].Key,
282 : : WF_MsgStrs[eTRACE].len);
283 : :
284 : 8 : JsonArrayAppend(Val, ExcClass);
285 : 8 : JsonObjectAppend(ExcClass,
286 : : NewJsonPlainString(HKEY("Class"),
287 : : HKEY("Exception")));
288 : 8 : JsonObjectAppend(ExcClass,
289 : : NewJsonString(HKEY("Message"), Message));
290 : 8 : JsonObjectAppend(ExcClass,
291 : : NewJsonPlainString(HKEY("File"),
292 : : Filename, FileLen));
293 : : /*
294 : : JsonObjectAppend(ExcClass,
295 : : NewJsonPlainString(HKEY("Type"),
296 : : HKEY("throw")));
297 : : */
298 : 8 : JsonObjectAppend(ExcClass,
299 : : NewJsonNumber(HKEY("Line"), LineNo));
300 : :
301 : : #ifdef HAVE_BACKTRACE
302 : : {
303 : : void *stack_frames[100];
304 : : size_t size;
305 : : long i;
306 : : char **strings;
307 : : JsonValue *Trace;
308 : : JsonValue *Frame;
309 : : StrBuf *FileName;
310 : : StrBuf *Function;
311 : : StrBuf *Pointer;
312 : : StrBuf *Buf;
313 : : unsigned int FunctionLine;
314 : :
315 : 8 : Trace = NewJsonArray(HKEY("Trace"));
316 : 8 : JsonObjectAppend(ExcClass, Trace);
317 : 8 : FileName = NewStrBuf();
318 : 8 : Function = NewStrBuf();
319 : 8 : Pointer = NewStrBuf();
320 : 8 : Buf = NewStrBuf();
321 : :
322 : 8 : size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
323 : 8 : strings = backtrace_symbols(stack_frames, size);
324 [ + + ]: 25 : for (i = StackOffset + 1; i < size; i++) {
325 [ + - ]: 17 : if (strings != NULL){
326 : 17 : ParseBacktrace(strings[i], Function,
327 : : FileName,
328 : : &FunctionLine);
329 : :
330 : : }
331 : 17 : StrBufPrintf(Pointer, "%p\n", stack_frames[i]);
332 : :
333 : 17 : addr2lineBacktrace(Function,
334 : : FileName,
335 : : Pointer,
336 : : Buf,
337 : : &FunctionLine);
338 : :
339 : 17 : Frame = NewJsonObject(NULL, 0);
340 : 17 : JsonArrayAppend(Trace, Frame);
341 : 17 : JsonObjectAppend(Frame,
342 : : NewJsonString(HKEY("function"), Function));
343 : 17 : JsonObjectAppend(Frame,
344 : : NewJsonString(HKEY("file"), FileName));
345 : 17 : JsonObjectAppend(Frame,
346 : : NewJsonNumber(HKEY("line"), FunctionLine));
347 : 17 : JsonObjectAppend(Frame,
348 : : NewJsonArray(HKEY("args")));/* not supportet... */
349 : :
350 : 17 : FunctionLine = 0;
351 : 17 : FlushStrBuf(FileName);
352 : 17 : FlushStrBuf(Function);
353 : 17 : FlushStrBuf(Pointer);
354 : : }
355 : 8 : free(strings);
356 : 8 : FreeStrBuf(&FileName);
357 : 8 : FreeStrBuf(&Function);
358 : 8 : FreeStrBuf(&Pointer);
359 : 8 : FreeStrBuf(&Buf);
360 : : }
361 : : #endif
362 : 8 : return Val;
363 : : }
364 : :
365 : 7 : void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr)
366 : : {
367 : 7 : int n = *MsgCount;
368 : : StrBuf *Buf;
369 : : StrBuf *HeaderName;
370 : : StrBuf *N;
371 : 7 : const char Concatenate[] = "\\";
372 : 7 : const char empty[] = "";
373 : : const char *Cat;
374 : : StrBuf *Header;
375 : :
376 [ - + ]: 7 : if (*MsgCount == 0) {
377 [ # # ]: 0 : if (OutBuf != NULL) {
378 : 0 : StrBufAppendBufPlain(OutBuf,
379 : : HKEY(
380 : : "X-Wf-Protocol-1"
381 : : ": "
382 : : "http://meta.wildfirehq.org/Protocol/JsonStream/0.2\r\n"), 0);
383 : 0 : StrBufAppendBufPlain(OutBuf,
384 : : HKEY(
385 : : "X-Wf-1-Plugin-1"
386 : : ": "
387 : : "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0\r\n"), 0);
388 : 0 : StrBufAppendBufPlain(OutBuf,
389 : : HKEY(
390 : : "X-Wf-1-Structure-1"
391 : : ": "
392 : : "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1\r\n"), 0);
393 : : }
394 : : else {
395 : 0 : Header = NewStrBuf();
396 : 0 : AddHdr("X-Wf-Protocol-1",
397 : : "http://meta.wildfirehq.org/Protocol/JsonStream/0.2");
398 : 0 : AddHdr("X-Wf-1-Plugin-1",
399 : : "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0");
400 : 0 : AddHdr("X-Wf-1-Structure-1",
401 : : "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1");
402 : : }
403 : : }
404 : :
405 : 7 : N = NewStrBuf();
406 : 7 : StrBufPrintf(N, "%d", StrLength(JsonBuffer));
407 : 7 : Buf = NewStrBufPlain(NULL, 1024);
408 : 7 : HeaderName = NewStrBuf();
409 : :
410 [ + + ]: 16 : while (StrLength(JsonBuffer) > 0) {
411 : 9 : FlushStrBuf(Buf);
412 : 9 : StrBufPrintf(HeaderName, "X-Wf-"WF_MAJOR"-"WF_STRUCTINDEX"-"WF_SUB"-%d", n);
413 [ + + ]: 9 : if (StrLength(JsonBuffer) > 800) {
414 : 2 : StrBufAppendBufPlain(Buf, ChrPtr(JsonBuffer), 800, 0);
415 : 2 : StrBufCutLeft(JsonBuffer, 800);
416 : 2 : Cat = Concatenate;
417 : : }
418 : : else {
419 : 7 : StrBufAppendBuf(Buf, JsonBuffer, 0);
420 : 7 : FlushStrBuf(JsonBuffer);
421 : 7 : Cat = empty;
422 : : }
423 [ + - ]: 9 : if (OutBuf != NULL) {
424 : 9 : StrBufAppendPrintf(OutBuf,
425 : : "%s: %s|%s|%s\r\n",
426 : : ChrPtr(HeaderName),
427 : : ChrPtr(N),
428 : : ChrPtr(Buf),
429 : : Cat);
430 : : }
431 : : else {
432 : 0 : StrBufAppendPrintf(Header,
433 : : "%s|%s|%s",
434 : : ChrPtr(N),
435 : : ChrPtr(Buf),
436 : : Cat);
437 : 0 : AddHdr(ChrPtr(HeaderName), ChrPtr(Header));
438 : :
439 : : }
440 : :
441 : 9 : FlushStrBuf(N);
442 : 9 : n++;
443 : : }
444 : 7 : *MsgCount = n;
445 [ - + ]: 7 : if (OutBuf == NULL) {
446 : 0 : FreeStrBuf(&Header);
447 : : }
448 : 7 : FreeStrBuf(&N);
449 : 7 : FreeStrBuf(&Buf);
450 : 7 : FreeStrBuf(&HeaderName);
451 : 7 : }
452 : :
453 : :
454 : :
455 : :
456 : :
457 : :
458 : : /* this is how we do it...
459 : : void CreateWildfireSampleMessage(void)
460 : : {
461 : : JsonValue *Error;
462 : :
463 : : StrBuf *Buf;
464 : : StrBuf *Header;
465 : : StrBuf *Json;
466 : : int n = 1;
467 : :
468 : : Header = NewStrBuf();
469 : : Json = NewStrBuf();
470 : :
471 : : Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
472 : : SerializeJson(Json, Error);
473 : : WildFireSerializePayload(Json, Header, &n, NULL);
474 : : StrBufAppendBuf(WC->HBuf, Header, 0);
475 : : DeleteJSONValue(Error);
476 : : FlushStrBuf(Json);
477 : : FlushStrBuf(Header);
478 : :
479 : : Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Warn message"), eWARN);
480 : : SerializeJson(Json, Error);
481 : : WildFireSerializePayload(Json, Header, &n, NULL);
482 : : StrBufAppendBuf(WC->HBuf, Header, 0);
483 : : DeleteJSONValue(Error);
484 : : FlushStrBuf(Json);
485 : : FlushStrBuf(Header);
486 : :
487 : : Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Error message"), eERROR);
488 : : SerializeJson(Json, Error);
489 : : WildFireSerializePayload(Json, Header, &n, NULL);
490 : : StrBufAppendBuf(WC->HBuf, Header, 0);
491 : : DeleteJSONValue(Error);
492 : : FlushStrBuf(Json);
493 : : FlushStrBuf(Header);
494 : :
495 : : Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
496 : : SerializeJson(Json, Error);
497 : : WildFireSerializePayload(Json, Header, &n, NULL);
498 : : StrBufAppendBuf(WC->HBuf, Header, 0);
499 : : DeleteJSONValue(Error);
500 : : FlushStrBuf(Json);
501 : : FlushStrBuf(Header);
502 : :
503 : : Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
504 : : SerializeJson(Json, Error);
505 : : WildFireSerializePayload(Json, Header, &n, NULL);
506 : : StrBufAppendBuf(WC->HBuf, Header, 0);
507 : : DeleteJSONValue(Error);
508 : : FlushStrBuf(Json);
509 : : FlushStrBuf(Header);
510 : :
511 : :
512 : : Buf = NewStrBufPlain(HKEY("test error message"));
513 : : Error = WildFireException(Buf, HKEY(__FILE__), __LINE__, 1);
514 : : SerializeJson(Json, Error);
515 : : WildFireSerializePayload(Json, Header, &n, NULL);
516 : : StrBufAppendBuf(WC->HBuf, Header, 0);
517 : : DeleteJSONValue(Error);
518 : :
519 : : FlushStrBuf(Json);
520 : : FlushStrBuf(Header);
521 : :
522 : : }
523 : :
524 : : */
|