17 #include "libcitadel.h"
18 #include "libcitadellocal.h"
21 ConstStr WF_MsgStrs[] = {
30 static JsonValue *WFInfo(const char *Filename, long fnlen,
36 Val = NewJsonObject(NULL, 0);
38 NewJsonPlainString(HKEY("Type"),
40 WF_MsgStrs[Type].len));
42 NewJsonPlainString(HKEY("File"),
45 NewJsonNumber(HKEY("Line"), LineNo));
50 JsonValue *WildFireMessage(const char *Filename, long fnlen,
57 Ret = NewJsonArray(NULL, 0);
58 JsonArrayAppend(Ret, WFInfo(Filename, fnlen,
62 NewJsonString(NULL, 0, Msg));
66 JsonValue *WildFireMessagePlain(const char *Filename, long fnlen,
68 const char *Message, long len,
72 Val = NewJsonArray(NULL, 0);
74 JsonArrayAppend(Val, WFInfo(Filename, fnlen,
77 NewJsonPlainString(NULL, 0, Message, len));
81 void WildFireAddArray(JsonValue *ReportBase, JsonValue *Array, WF_MessageType Type)
84 Val = NewJsonArray(NULL, 0);
86 NewJsonPlainString(NULL, 0,
88 WF_MsgStrs[Type].len));
90 JsonArrayAppend(Val, Array);
93 int addr2line_write_pipe[2];
94 int addr2line_read_pipe[2];
99 * Start up the addr2line daemon so we can decode function pointers
101 static void start_addr2line_daemon(const char *binary)
103 struct stat filestats;
105 const char *addr2line = "/usr/bin/addr2line";
106 const char minuse[] = "-e";
108 printf("Starting addr2line daemon for decoding of backtraces\n");
110 if ((stat(addr2line, &filestats)==-1) ||
111 (filestats.st_size==0)){
112 printf("didn't find addr2line daemon in %s: %s\n", addr2line, strerror(errno));
115 if (pipe(addr2line_write_pipe) != 0) {
116 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
119 if (pipe(addr2line_read_pipe) != 0) {
120 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
124 addr2line_pid = fork();
125 if (addr2line_pid < 0) {
126 printf("Unable to fork addr2line daemon: %s\n", strerror(errno));
129 if (addr2line_pid == 0) {
130 dup2(addr2line_write_pipe[0], 0);
131 dup2(addr2line_read_pipe[1], 1);
132 for (i=2; i<256; ++i) close(i);
133 execl(addr2line, addr2line, minuse, binary, NULL);
134 printf("Unable to exec addr2line daemon: %s\n", strerror(errno));
140 static int addr2lineBacktrace(StrBuf *Function,
144 unsigned int *FunctionLine)
148 const char *pch, *pche;
150 write(addr2line_write_pipe[1], SKEY(Pointer));
151 if (StrBufTCP_read_line(Buf, &addr2line_read_pipe[0], 0, &err) <= 0)
153 StrBufAppendBufPlain(Buf, err, -1, 0);
157 pche = strchr(pch, ':');
158 FlushStrBuf(FileName);
159 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
161 *FunctionLine = atoi(pche);
166 static int ParseBacktrace(char *Line,
169 unsigned int *FunctionLine)
174 pche = strchr(pch, '(');
175 if (pche == NULL) return 0;
176 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
178 pche = strchr(pch, '+');
179 if (pche == NULL) return 0;
180 StrBufAppendBufPlain(Function, pch, pche - pch, 0);
182 pche = strchr(pch, ')');
183 if (pche == NULL) return 0;
185 sscanf(pch, "%x", FunctionLine);
186 StrBufAppendBufPlain(Function, pche + 1, -1, 0);
191 StrBuf *FullBinaryName = NULL;
193 void WildFireShutdown(void)
195 close(addr2line_write_pipe[0]);
196 close(addr2line_read_pipe[0]);
198 FreeStrBuf(&FullBinaryName);
201 void WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip)
204 #ifdef HAVE_BACKTRACE
205 void *stack_frames[100];
213 unsigned int FunctionLine;
214 struct stat filestats;
216 FileName = NewStrBuf();
217 Function = NewStrBuf();
218 Pointer = NewStrBuf();
221 BaseFrames = size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
223 BaseFrames += AddBaseFrameSkip;
224 strings = backtrace_symbols(stack_frames, size);
225 for (i = 1; i < size; i++) {
226 if (strings != NULL){
227 ParseBacktrace(strings[i], Function,
230 FullBinaryName = NewStrBufDup(FileName);
235 getcwd(path, sizeof(path));
236 FullBinaryName = NewStrBufPlain(path, -1);
237 StrBufAppendBufPlain(FullBinaryName, HKEY("/"), 0);
238 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
242 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
243 (filestats.st_size==0)){
244 FlushStrBuf(FullBinaryName);
245 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
246 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
247 (filestats.st_size==0)){
248 FlushStrBuf(FullBinaryName);
249 fprintf(stderr, "unable to open my binary for addr2line checking, verbose backtraces won't work.\n");
253 FreeStrBuf(&FileName);
254 FreeStrBuf(&Function);
255 FreeStrBuf(&Pointer);
257 if (StrLength(FullBinaryName) > 0)
258 start_addr2line_daemon(ChrPtr(FullBinaryName));
265 JsonValue *WildFireException(const char *Filename, long FileLen,
272 Val = NewJsonArray(NULL, 0);
274 JsonArrayAppend(Val, WFInfo(Filename, FileLen,
275 LineNo, eEXCEPTION));
277 ExcClass = NewJsonObject(WF_MsgStrs[eTRACE].Key,
278 WF_MsgStrs[eTRACE].len);
280 JsonArrayAppend(Val, ExcClass);
281 JsonObjectAppend(ExcClass,
282 NewJsonPlainString(HKEY("Class"),
284 JsonObjectAppend(ExcClass,
285 NewJsonString(HKEY("Message"), Message));
286 JsonObjectAppend(ExcClass,
287 NewJsonPlainString(HKEY("File"),
290 JsonObjectAppend(ExcClass,
291 NewJsonPlainString(HKEY("Type"),
294 JsonObjectAppend(ExcClass,
295 NewJsonNumber(HKEY("Line"), LineNo));
297 #ifdef HAVE_BACKTRACE
299 void *stack_frames[100];
309 unsigned int FunctionLine;
311 Trace = NewJsonArray(HKEY("Trace"));
312 JsonObjectAppend(ExcClass, Trace);
313 FileName = NewStrBuf();
314 Function = NewStrBuf();
315 Pointer = NewStrBuf();
318 size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
319 strings = backtrace_symbols(stack_frames, size);
320 for (i = StackOffset + 1; i < size; i++) {
321 if (strings != NULL){
322 ParseBacktrace(strings[i], Function,
327 StrBufPrintf(Pointer, "%p\n", stack_frames[i]);
329 addr2lineBacktrace(Function,
335 Frame = NewJsonObject(NULL, 0);
336 JsonArrayAppend(Trace, Frame);
337 JsonObjectAppend(Frame,
338 NewJsonString(HKEY("function"), Function));
339 JsonObjectAppend(Frame,
340 NewJsonString(HKEY("file"), FileName));
341 JsonObjectAppend(Frame,
342 NewJsonNumber(HKEY("line"), FunctionLine));
343 JsonObjectAppend(Frame,
344 NewJsonArray(HKEY("args")));/* not supportet... */
347 FlushStrBuf(FileName);
348 FlushStrBuf(Function);
349 FlushStrBuf(Pointer);
352 FreeStrBuf(&FileName);
353 FreeStrBuf(&Function);
354 FreeStrBuf(&Pointer);
361 void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr)
367 const char Concatenate[] = "\\";
368 const char empty[] = "";
372 if (*MsgCount == 0) {
373 if (OutBuf != NULL) {
374 StrBufAppendBufPlain(OutBuf,
378 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2\r\n"), 0);
379 StrBufAppendBufPlain(OutBuf,
383 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0\r\n"), 0);
384 StrBufAppendBufPlain(OutBuf,
388 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1\r\n"), 0);
391 Header = NewStrBuf();
392 AddHdr("X-Wf-Protocol-1",
393 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2");
394 AddHdr("X-Wf-1-Plugin-1",
395 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0");
396 AddHdr("X-Wf-1-Structure-1",
397 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1");
402 StrBufPrintf(N, "%d", StrLength(JsonBuffer));
403 Buf = NewStrBufPlain(NULL, 1024);
404 HeaderName = NewStrBuf();
406 while (StrLength(JsonBuffer) > 0) {
408 StrBufPrintf(HeaderName, "X-Wf-"WF_MAJOR"-"WF_STRUCTINDEX"-"WF_SUB"-%d", n);
409 if (StrLength(JsonBuffer) > 800) {
410 StrBufAppendBufPlain(Buf, ChrPtr(JsonBuffer), 800, 0);
411 StrBufCutLeft(JsonBuffer, 800);
415 StrBufAppendBuf(Buf, JsonBuffer, 0);
416 FlushStrBuf(JsonBuffer);
419 if (OutBuf != NULL) {
420 StrBufAppendPrintf(OutBuf,
428 StrBufAppendPrintf(Header,
433 AddHdr(ChrPtr(HeaderName), ChrPtr(Header));
441 if (OutBuf == NULL) {
446 FreeStrBuf(&HeaderName);
454 /* this is how we do it...
455 void CreateWildfireSampleMessage(void)
464 Header = NewStrBuf();
467 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
468 SerializeJson(Json, Error);
469 WildFireSerializePayload(Json, Header, &n, NULL);
470 StrBufAppendBuf(WC->HBuf, Header, 0);
471 DeleteJSONValue(Error);
475 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Warn message"), eWARN);
476 SerializeJson(Json, Error);
477 WildFireSerializePayload(Json, Header, &n, NULL);
478 StrBufAppendBuf(WC->HBuf, Header, 0);
479 DeleteJSONValue(Error);
483 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Error message"), eERROR);
484 SerializeJson(Json, Error);
485 WildFireSerializePayload(Json, Header, &n, NULL);
486 StrBufAppendBuf(WC->HBuf, Header, 0);
487 DeleteJSONValue(Error);
491 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
492 SerializeJson(Json, Error);
493 WildFireSerializePayload(Json, Header, &n, NULL);
494 StrBufAppendBuf(WC->HBuf, Header, 0);
495 DeleteJSONValue(Error);
499 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
500 SerializeJson(Json, Error);
501 WildFireSerializePayload(Json, Header, &n, NULL);
502 StrBufAppendBuf(WC->HBuf, Header, 0);
503 DeleteJSONValue(Error);
508 Buf = NewStrBufPlain(HKEY("test error message"));
509 Error = WildFireException(Buf, HKEY(__FILE__), __LINE__, 1);
510 SerializeJson(Json, Error);
511 WildFireSerializePayload(Json, Header, &n, NULL);
512 StrBufAppendBuf(WC->HBuf, Header, 0);
513 DeleteJSONValue(Error);