2 * $Id: wildfire.c 6962 2009-01-18 19:33:45Z dothebart $
21 #include "libcitadel.h"
25 ConstStr WF_MsgStrs[] = {
34 static JsonValue *WFInfo(const char *Filename, long fnlen,
40 Val = NewJsonObject(NULL, 0);
42 NewJsonPlainString(HKEY("Type"),
44 WF_MsgStrs[Type].len));
46 NewJsonPlainString(HKEY("File"),
49 NewJsonNumber(HKEY("Line"), LineNo));
54 JsonValue *WildFireMessage(const char *Filename, long fnlen,
61 Ret = NewJsonArray(NULL, 0);
62 JsonArrayAppend(Ret, WFInfo(Filename, fnlen,
66 NewJsonString(NULL, 0, Msg));
70 JsonValue *WildFireMessagePlain(const char *Filename, long fnlen,
72 const char *Message, long len,
76 Val = NewJsonArray(NULL, 0);
78 JsonArrayAppend(Val, WFInfo(Filename, fnlen,
81 NewJsonPlainString(NULL, 0, Message, len));
85 void WildFireAddArray(JsonValue *ReportBase, JsonValue *Array, WF_MessageType Type)
88 Val = NewJsonArray(NULL, 0);
90 NewJsonPlainString(NULL, 0,
92 WF_MsgStrs[Type].len));
94 JsonArrayAppend(Val, Array);
97 int addr2line_write_pipe[2];
98 int addr2line_read_pipe[2];
101 #ifdef HAVE_BACKTRACE
103 * Start up the addr2line daemon so we can decode function pointers
105 static void start_addr2line_daemon(const char *binary)
107 struct stat filestats;
109 const char *addr2line = "/usr/bin/addr2line";
110 const char minuse[] = "-e";
112 printf("Starting addr2line daemon for decoding of backtraces\n");
114 if ((stat(addr2line, &filestats)==-1) ||
115 (filestats.st_size==0)){
116 printf("didn't find addr2line daemon in %s: %s\n", addr2line, strerror(errno));
119 if (pipe(addr2line_write_pipe) != 0) {
120 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
123 if (pipe(addr2line_read_pipe) != 0) {
124 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
128 addr2line_pid = fork();
129 if (addr2line_pid < 0) {
130 printf("Unable to fork addr2line daemon: %s\n", strerror(errno));
133 if (addr2line_pid == 0) {
134 dup2(addr2line_write_pipe[0], 0);
135 dup2(addr2line_read_pipe[1], 1);
136 for (i=2; i<256; ++i) close(i);
137 execl(addr2line, addr2line, minuse, binary, NULL);
138 printf("Unable to exec addr2line daemon: %s\n", strerror(errno));
144 static int addr2lineBacktrace(StrBuf *Function,
148 unsigned int *FunctionLine)
152 const char *pch, *pche;
154 write(addr2line_write_pipe[1], SKEY(Pointer));
155 if (StrBufTCP_read_line(Buf, &addr2line_read_pipe[0], 0, &err) <= 0)
157 StrBufAppendBufPlain(Buf, err, -1, 0);
161 pche = strchr(pch, ':');
162 FlushStrBuf(FileName);
163 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
165 *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 WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip)
200 #ifdef HAVE_BACKTRACE
201 void *stack_frames[100];
209 unsigned int FunctionLine;
210 struct stat filestats;
212 FileName = NewStrBuf();
213 Function = NewStrBuf();
214 Pointer = NewStrBuf();
217 BaseFrames = size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
219 BaseFrames += AddBaseFrameSkip;
220 strings = backtrace_symbols(stack_frames, size);
221 for (i = 1; i < size; i++) {
222 if (strings != NULL){
223 ParseBacktrace(strings[i], Function,
226 FullBinaryName = NewStrBufDup(FileName);
231 getcwd(path, sizeof(path));
232 FullBinaryName = NewStrBufPlain(path, -1);
233 StrBufAppendBufPlain(FullBinaryName, HKEY("/"), 0);
234 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
238 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
239 (filestats.st_size==0)){
240 FlushStrBuf(FullBinaryName);
241 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
242 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
243 (filestats.st_size==0)){
244 FlushStrBuf(FullBinaryName);
245 fprintf(stderr, "unable to open my binary for addr2line checking, verbose backtraces won't work.\n");
249 FreeStrBuf(&FileName);
250 FreeStrBuf(&Function);
251 FreeStrBuf(&Pointer);
253 if (StrLength(FullBinaryName) > 0)
254 start_addr2line_daemon(ChrPtr(FullBinaryName));
261 JsonValue *WildFireException(const char *Filename, long FileLen,
268 Val = NewJsonArray(NULL, 0);
270 JsonArrayAppend(Val, WFInfo(Filename, FileLen,
271 LineNo, eEXCEPTION));
273 ExcClass = NewJsonObject(WF_MsgStrs[eTRACE].Key,
274 WF_MsgStrs[eTRACE].len);
276 JsonArrayAppend(Val, ExcClass);
277 JsonObjectAppend(ExcClass,
278 NewJsonPlainString(HKEY("Class"),
280 JsonObjectAppend(ExcClass,
281 NewJsonString(HKEY("Message"), Message));
282 JsonObjectAppend(ExcClass,
283 NewJsonPlainString(HKEY("File"),
286 JsonObjectAppend(ExcClass,
287 NewJsonPlainString(HKEY("Type"),
290 JsonObjectAppend(ExcClass,
291 NewJsonNumber(HKEY("Line"), LineNo));
293 #ifdef HAVE_BACKTRACE
295 void *stack_frames[100];
305 unsigned int FunctionLine;
307 Trace = NewJsonArray(HKEY("Trace"));
308 JsonObjectAppend(ExcClass, Trace);
309 FileName = NewStrBuf();
310 Function = NewStrBuf();
311 Pointer = NewStrBuf();
314 size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
315 strings = backtrace_symbols(stack_frames, size);
316 for (i = StackOffset + 1; i < size; i++) {
317 if (strings != NULL){
318 ParseBacktrace(strings[i], Function,
323 StrBufPrintf(Pointer, "%p\n", stack_frames[i]);
325 addr2lineBacktrace(Function,
331 Frame = NewJsonObject(NULL, 0);
332 JsonArrayAppend(Trace, Frame);
333 JsonObjectAppend(Frame,
334 NewJsonString(HKEY("function"), Function));
335 JsonObjectAppend(Frame,
336 NewJsonString(HKEY("file"), FileName));
337 JsonObjectAppend(Frame,
338 NewJsonNumber(HKEY("line"), FunctionLine));
339 JsonObjectAppend(Frame,
340 NewJsonArray(HKEY("args")));/* not supportet... */
343 FlushStrBuf(FileName);
344 FlushStrBuf(Function);
345 FlushStrBuf(Pointer);
348 FreeStrBuf(&FileName);
349 FreeStrBuf(&Function);
350 FreeStrBuf(&Pointer);
357 void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr)
363 const char Concatenate[] = "\\";
364 const char empty[] = "";
368 if (*MsgCount == 0) {
369 if (OutBuf != NULL) {
370 StrBufAppendBufPlain(OutBuf,
374 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2\r\n"), 0);
375 StrBufAppendBufPlain(OutBuf,
379 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0\r\n"), 0);
380 StrBufAppendBufPlain(OutBuf,
384 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1\r\n"), 0);
387 Header = NewStrBuf();
388 AddHdr("X-Wf-Protocol-1",
389 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2");
390 AddHdr("X-Wf-1-Plugin-1",
391 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0");
392 AddHdr("X-Wf-1-Structure-1",
393 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1");
398 StrBufPrintf(N, "%d", StrLength(JsonBuffer));
399 Buf = NewStrBufPlain(NULL, 1024);
400 HeaderName = NewStrBuf();
402 while (StrLength(JsonBuffer) > 0) {
404 StrBufPrintf(HeaderName, "X-Wf-"WF_MAJOR"-"WF_STRUCTINDEX"-"WF_SUB"-%d", n);
405 if (StrLength(JsonBuffer) > 800) {
406 StrBufAppendBufPlain(Buf, ChrPtr(JsonBuffer), 800, 0);
407 StrBufCutLeft(JsonBuffer, 800);
411 StrBufAppendBuf(Buf, JsonBuffer, 0);
412 FlushStrBuf(JsonBuffer);
415 if (OutBuf != NULL) {
416 StrBufAppendPrintf(OutBuf,
424 StrBufAppendPrintf(Header,
429 AddHdr(ChrPtr(HeaderName), ChrPtr(Header));
437 if (OutBuf == NULL) {
442 FreeStrBuf(&HeaderName);
450 /* this is how we do it...
451 void CreateWildfireSampleMessage(void)
460 Header = NewStrBuf();
463 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
464 SerializeJson(Json, Error);
465 WildFireSerializePayload(Json, Header, &n, NULL);
466 StrBufAppendBuf(WC->HBuf, Header, 0);
467 DeleteJSONValue(Error);
471 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Warn message"), eWARN);
472 SerializeJson(Json, Error);
473 WildFireSerializePayload(Json, Header, &n, NULL);
474 StrBufAppendBuf(WC->HBuf, Header, 0);
475 DeleteJSONValue(Error);
479 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Error message"), eERROR);
480 SerializeJson(Json, Error);
481 WildFireSerializePayload(Json, Header, &n, NULL);
482 StrBufAppendBuf(WC->HBuf, Header, 0);
483 DeleteJSONValue(Error);
487 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
488 SerializeJson(Json, Error);
489 WildFireSerializePayload(Json, Header, &n, NULL);
490 StrBufAppendBuf(WC->HBuf, Header, 0);
491 DeleteJSONValue(Error);
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);
504 Buf = NewStrBufPlain(HKEY("test error message"));
505 Error = WildFireException(Buf, HKEY(__FILE__), __LINE__, 1);
506 SerializeJson(Json, Error);
507 WildFireSerializePayload(Json, Header, &n, NULL);
508 StrBufAppendBuf(WC->HBuf, Header, 0);
509 DeleteJSONValue(Error);