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,
61 JsonArrayAppend(Ret, NewJsonString(NULL, 0, Msg, NEWJSONSTRING_COPYBUF));
65 JsonValue *WildFireMessagePlain(const char *Filename, long fnlen,
67 const char *Message, long len,
71 Val = NewJsonArray(NULL, 0);
73 JsonArrayAppend(Val, WFInfo(Filename, fnlen,
76 NewJsonPlainString(NULL, 0, Message, len));
80 void WildFireAddArray(JsonValue *ReportBase, JsonValue *Array, WF_MessageType Type)
83 Val = NewJsonArray(NULL, 0);
85 NewJsonPlainString(NULL, 0,
87 WF_MsgStrs[Type].len));
89 JsonArrayAppend(Val, Array);
92 int addr2line_write_pipe[2];
93 int addr2line_read_pipe[2];
98 * Start up the addr2line daemon so we can decode function pointers
100 static void start_addr2line_daemon(const char *binary)
102 struct stat filestats;
104 const char *addr2line = "/usr/bin/addr2line";
105 const char minuse[] = "-e";
107 printf("Starting addr2line daemon for decoding of backtraces\n");
109 if ((stat(addr2line, &filestats)==-1) ||
110 (filestats.st_size==0)){
111 printf("didn't find addr2line daemon in %s: %s\n", addr2line, strerror(errno));
114 if (pipe(addr2line_write_pipe) != 0) {
115 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
118 if (pipe(addr2line_read_pipe) != 0) {
119 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
123 addr2line_pid = fork();
124 if (addr2line_pid < 0) {
125 printf("Unable to fork addr2line daemon: %s\n", strerror(errno));
128 if (addr2line_pid == 0) {
129 dup2(addr2line_write_pipe[0], 0);
130 dup2(addr2line_read_pipe[1], 1);
131 for (i=2; i<256; ++i) close(i);
132 execl(addr2line, addr2line, minuse, binary, NULL);
133 printf("Unable to exec addr2line daemon: %s\n", strerror(errno));
139 static int addr2lineBacktrace(StrBuf *Function,
143 unsigned int *FunctionLine)
147 const char *pch, *pche;
149 write(addr2line_write_pipe[1], SKEY(Pointer));
150 if (StrBufTCP_read_line(Buf, &addr2line_read_pipe[0], 0, &err) <= 0)
152 StrBufAppendBufPlain(Buf, err, -1, 0);
156 pche = strchr(pch, ':');
157 FlushStrBuf(FileName);
158 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
162 *FunctionLine = atoi(pche);
169 static int ParseBacktrace(char *Line,
172 unsigned int *FunctionLine)
177 pche = strchr(pch, '(');
178 if (pche == NULL) return 0;
179 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
181 pche = strchr(pch, '+');
182 if (pche == NULL) return 0;
183 StrBufAppendBufPlain(Function, pch, pche - pch, 0);
185 pche = strchr(pch, ')');
186 if (pche == NULL) return 0;
188 sscanf(pch, "%x", FunctionLine);
189 StrBufAppendBufPlain(Function, pche + 1, -1, 0);
194 StrBuf *FullBinaryName = NULL;
196 void WildFireShutdown(void)
198 close(addr2line_write_pipe[0]);
199 close(addr2line_read_pipe[0]);
201 FreeStrBuf(&FullBinaryName);
204 void WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip)
207 #ifdef HAVE_BACKTRACE
208 void *stack_frames[100];
216 unsigned int FunctionLine;
217 struct stat filestats;
219 FileName = NewStrBuf();
220 Function = NewStrBuf();
221 Pointer = NewStrBuf();
224 BaseFrames = size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
226 BaseFrames += AddBaseFrameSkip;
227 strings = backtrace_symbols(stack_frames, size);
228 for (i = 1; i < size; i++) {
229 if (strings != NULL){
230 ParseBacktrace(strings[i], Function,
233 FullBinaryName = NewStrBufDup(FileName);
238 getcwd(path, sizeof(path));
239 FullBinaryName = NewStrBufPlain(path, -1);
240 StrBufAppendBufPlain(FullBinaryName, HKEY("/"), 0);
241 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
245 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
246 (filestats.st_size==0)){
247 FlushStrBuf(FullBinaryName);
248 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
249 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
250 (filestats.st_size==0)){
251 FlushStrBuf(FullBinaryName);
252 fprintf(stderr, "unable to open my binary for addr2line checking, verbose backtraces won't work.\n");
256 FreeStrBuf(&FileName);
257 FreeStrBuf(&Function);
258 FreeStrBuf(&Pointer);
260 if (StrLength(FullBinaryName) > 0)
261 start_addr2line_daemon(ChrPtr(FullBinaryName));
268 JsonValue *WildFireException(const char *Filename, long FileLen,
275 Val = NewJsonArray(NULL, 0);
277 JsonArrayAppend(Val, WFInfo(Filename, FileLen, LineNo, eEXCEPTION));
278 ExcClass = NewJsonObject(WF_MsgStrs[eTRACE].Key, WF_MsgStrs[eTRACE].len);
279 JsonArrayAppend(Val, ExcClass);
280 JsonObjectAppend(ExcClass, NewJsonPlainString(HKEY("Class"), HKEY("Exception")));
281 JsonObjectAppend(ExcClass, NewJsonString(HKEY("Message"), Message, NEWJSONSTRING_COPYBUF));
282 JsonObjectAppend(ExcClass, NewJsonPlainString(HKEY("File"), Filename, FileLen));
284 JsonObjectAppend(ExcClass, NewJsonPlainString(HKEY("Type"), HKEY("throw")));
286 JsonObjectAppend(ExcClass, NewJsonNumber(HKEY("Line"), LineNo));
288 #ifdef HAVE_BACKTRACE
290 void *stack_frames[100];
300 unsigned int FunctionLine;
302 Trace = NewJsonArray(HKEY("Trace"));
303 JsonObjectAppend(ExcClass, Trace);
304 FileName = NewStrBuf();
305 Function = NewStrBuf();
306 Pointer = NewStrBuf();
309 size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
310 strings = backtrace_symbols(stack_frames, size);
311 for (i = StackOffset + 1; i < size; i++) {
312 if (strings != NULL){
313 ParseBacktrace(strings[i], Function,
318 StrBufPrintf(Pointer, "%p\n", stack_frames[i]);
320 addr2lineBacktrace(Function,
326 Frame = NewJsonObject(NULL, 0);
327 JsonArrayAppend(Trace, Frame);
328 JsonObjectAppend(Frame, NewJsonString(HKEY("function"), Function, NEWJSONSTRING_COPYBUF));
329 JsonObjectAppend(Frame, NewJsonString(HKEY("file"), FileName, NEWJSONSTRING_COPYBUF));
330 JsonObjectAppend(Frame, NewJsonNumber(HKEY("line"), FunctionLine));
331 JsonObjectAppend(Frame, NewJsonArray(HKEY("args"))); // not supported
334 FlushStrBuf(FileName);
335 FlushStrBuf(Function);
336 FlushStrBuf(Pointer);
339 FreeStrBuf(&FileName);
340 FreeStrBuf(&Function);
341 FreeStrBuf(&Pointer);
348 void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr)
354 const char Concatenate[] = "\\";
355 const char empty[] = "";
360 Header = NewStrBuf();
361 if (*MsgCount == 0) {
362 if (OutBuf != NULL) {
363 StrBufAppendBufPlain(OutBuf,
367 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2\r\n"), 0);
368 StrBufAppendBufPlain(OutBuf,
372 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0\r\n"), 0);
373 StrBufAppendBufPlain(OutBuf,
377 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1\r\n"), 0);
380 AddHdr("X-Wf-Protocol-1",
381 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2");
382 AddHdr("X-Wf-1-Plugin-1",
383 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0");
384 AddHdr("X-Wf-1-Structure-1",
385 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1");
390 StrBufPrintf(N, "%d", StrLength(JsonBuffer));
391 Buf = NewStrBufPlain(NULL, 1024);
392 HeaderName = NewStrBuf();
394 while (StrLength(JsonBuffer) > 0) {
396 StrBufPrintf(HeaderName, "X-Wf-"WF_MAJOR"-"WF_STRUCTINDEX"-"WF_SUB"-%d", n);
397 if (StrLength(JsonBuffer) > 800) {
398 StrBufAppendBufPlain(Buf, ChrPtr(JsonBuffer), 800, 0);
399 StrBufCutLeft(JsonBuffer, 800);
403 StrBufAppendBuf(Buf, JsonBuffer, 0);
404 FlushStrBuf(JsonBuffer);
407 if (OutBuf != NULL) {
408 StrBufAppendPrintf(OutBuf,
416 StrBufAppendPrintf(Header,
421 AddHdr(ChrPtr(HeaderName), ChrPtr(Header));
429 if (OutBuf == NULL) {
434 FreeStrBuf(&HeaderName);
442 /* this is how we do it...
443 void CreateWildfireSampleMessage(void)
452 Header = NewStrBuf();
455 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
456 SerializeJson(Json, Error);
457 WildFireSerializePayload(Json, Header, &n, NULL);
458 StrBufAppendBuf(WC->HBuf, Header, 0);
459 DeleteJSONValue(Error);
463 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Warn message"), eWARN);
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("Error message"), eERROR);
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("Info message"), eINFO);
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);
496 Buf = NewStrBufPlain(HKEY("test error message"));
497 Error = WildFireException(Buf, HKEY(__FILE__), __LINE__, 1);
498 SerializeJson(Json, Error);
499 WildFireSerializePayload(Json, Header, &n, NULL);
500 StrBufAppendBuf(WC->HBuf, Header, 0);
501 DeleteJSONValue(Error);