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);
163 *FunctionLine = atoi(pche);
170 static int ParseBacktrace(char *Line,
173 unsigned int *FunctionLine)
178 pche = strchr(pch, '(');
179 if (pche == NULL) return 0;
180 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
182 pche = strchr(pch, '+');
183 if (pche == NULL) return 0;
184 StrBufAppendBufPlain(Function, pch, pche - pch, 0);
186 pche = strchr(pch, ')');
187 if (pche == NULL) return 0;
189 sscanf(pch, "%x", FunctionLine);
190 StrBufAppendBufPlain(Function, pche + 1, -1, 0);
195 StrBuf *FullBinaryName = NULL;
197 void WildFireShutdown(void)
199 close(addr2line_write_pipe[0]);
200 close(addr2line_read_pipe[0]);
202 FreeStrBuf(&FullBinaryName);
205 void WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip)
208 #ifdef HAVE_BACKTRACE
209 void *stack_frames[100];
217 unsigned int FunctionLine;
218 struct stat filestats;
220 FileName = NewStrBuf();
221 Function = NewStrBuf();
222 Pointer = NewStrBuf();
225 BaseFrames = size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
227 BaseFrames += AddBaseFrameSkip;
228 strings = backtrace_symbols(stack_frames, size);
229 for (i = 1; i < size; i++) {
230 if (strings != NULL){
231 ParseBacktrace(strings[i], Function,
234 FullBinaryName = NewStrBufDup(FileName);
239 getcwd(path, sizeof(path));
240 FullBinaryName = NewStrBufPlain(path, -1);
241 StrBufAppendBufPlain(FullBinaryName, HKEY("/"), 0);
242 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
246 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
247 (filestats.st_size==0)){
248 FlushStrBuf(FullBinaryName);
249 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
250 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
251 (filestats.st_size==0)){
252 FlushStrBuf(FullBinaryName);
253 fprintf(stderr, "unable to open my binary for addr2line checking, verbose backtraces won't work.\n");
257 FreeStrBuf(&FileName);
258 FreeStrBuf(&Function);
259 FreeStrBuf(&Pointer);
261 if (StrLength(FullBinaryName) > 0)
262 start_addr2line_daemon(ChrPtr(FullBinaryName));
269 JsonValue *WildFireException(const char *Filename, long FileLen,
276 Val = NewJsonArray(NULL, 0);
278 JsonArrayAppend(Val, WFInfo(Filename, FileLen,
279 LineNo, eEXCEPTION));
281 ExcClass = NewJsonObject(WF_MsgStrs[eTRACE].Key,
282 WF_MsgStrs[eTRACE].len);
284 JsonArrayAppend(Val, ExcClass);
285 JsonObjectAppend(ExcClass,
286 NewJsonPlainString(HKEY("Class"),
288 JsonObjectAppend(ExcClass,
289 NewJsonString(HKEY("Message"), Message));
290 JsonObjectAppend(ExcClass,
291 NewJsonPlainString(HKEY("File"),
294 JsonObjectAppend(ExcClass,
295 NewJsonPlainString(HKEY("Type"),
298 JsonObjectAppend(ExcClass,
299 NewJsonNumber(HKEY("Line"), LineNo));
301 #ifdef HAVE_BACKTRACE
303 void *stack_frames[100];
313 unsigned int FunctionLine;
315 Trace = NewJsonArray(HKEY("Trace"));
316 JsonObjectAppend(ExcClass, Trace);
317 FileName = NewStrBuf();
318 Function = NewStrBuf();
319 Pointer = NewStrBuf();
322 size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
323 strings = backtrace_symbols(stack_frames, size);
324 for (i = StackOffset + 1; i < size; i++) {
325 if (strings != NULL){
326 ParseBacktrace(strings[i], Function,
331 StrBufPrintf(Pointer, "%p\n", stack_frames[i]);
333 addr2lineBacktrace(Function,
339 Frame = NewJsonObject(NULL, 0);
340 JsonArrayAppend(Trace, Frame);
341 JsonObjectAppend(Frame,
342 NewJsonString(HKEY("function"), Function));
343 JsonObjectAppend(Frame,
344 NewJsonString(HKEY("file"), FileName));
345 JsonObjectAppend(Frame,
346 NewJsonNumber(HKEY("line"), FunctionLine));
347 JsonObjectAppend(Frame,
348 NewJsonArray(HKEY("args")));/* not supportet... */
351 FlushStrBuf(FileName);
352 FlushStrBuf(Function);
353 FlushStrBuf(Pointer);
356 FreeStrBuf(&FileName);
357 FreeStrBuf(&Function);
358 FreeStrBuf(&Pointer);
365 void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr)
371 const char Concatenate[] = "\\";
372 const char empty[] = "";
377 Header = NewStrBuf();
378 if (*MsgCount == 0) {
379 if (OutBuf != NULL) {
380 StrBufAppendBufPlain(OutBuf,
384 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2\r\n"), 0);
385 StrBufAppendBufPlain(OutBuf,
389 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0\r\n"), 0);
390 StrBufAppendBufPlain(OutBuf,
394 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1\r\n"), 0);
397 AddHdr("X-Wf-Protocol-1",
398 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2");
399 AddHdr("X-Wf-1-Plugin-1",
400 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0");
401 AddHdr("X-Wf-1-Structure-1",
402 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1");
407 StrBufPrintf(N, "%d", StrLength(JsonBuffer));
408 Buf = NewStrBufPlain(NULL, 1024);
409 HeaderName = NewStrBuf();
411 while (StrLength(JsonBuffer) > 0) {
413 StrBufPrintf(HeaderName, "X-Wf-"WF_MAJOR"-"WF_STRUCTINDEX"-"WF_SUB"-%d", n);
414 if (StrLength(JsonBuffer) > 800) {
415 StrBufAppendBufPlain(Buf, ChrPtr(JsonBuffer), 800, 0);
416 StrBufCutLeft(JsonBuffer, 800);
420 StrBufAppendBuf(Buf, JsonBuffer, 0);
421 FlushStrBuf(JsonBuffer);
424 if (OutBuf != NULL) {
425 StrBufAppendPrintf(OutBuf,
433 StrBufAppendPrintf(Header,
438 AddHdr(ChrPtr(HeaderName), ChrPtr(Header));
446 if (OutBuf == NULL) {
451 FreeStrBuf(&HeaderName);
459 /* this is how we do it...
460 void CreateWildfireSampleMessage(void)
469 Header = NewStrBuf();
472 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
473 SerializeJson(Json, Error);
474 WildFireSerializePayload(Json, Header, &n, NULL);
475 StrBufAppendBuf(WC->HBuf, Header, 0);
476 DeleteJSONValue(Error);
480 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Warn message"), eWARN);
481 SerializeJson(Json, Error);
482 WildFireSerializePayload(Json, Header, &n, NULL);
483 StrBufAppendBuf(WC->HBuf, Header, 0);
484 DeleteJSONValue(Error);
488 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Error message"), eERROR);
489 SerializeJson(Json, Error);
490 WildFireSerializePayload(Json, Header, &n, NULL);
491 StrBufAppendBuf(WC->HBuf, Header, 0);
492 DeleteJSONValue(Error);
496 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
497 SerializeJson(Json, Error);
498 WildFireSerializePayload(Json, Header, &n, NULL);
499 StrBufAppendBuf(WC->HBuf, Header, 0);
500 DeleteJSONValue(Error);
504 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
505 SerializeJson(Json, Error);
506 WildFireSerializePayload(Json, Header, &n, NULL);
507 StrBufAppendBuf(WC->HBuf, Header, 0);
508 DeleteJSONValue(Error);
513 Buf = NewStrBufPlain(HKEY("test error message"));
514 Error = WildFireException(Buf, HKEY(__FILE__), __LINE__, 1);
515 SerializeJson(Json, Error);
516 WildFireSerializePayload(Json, Header, &n, NULL);
517 StrBufAppendBuf(WC->HBuf, Header, 0);
518 DeleteJSONValue(Error);