1 // This doesn't belong in the build but WebCit-classic depends on it.
2 // When we move to WebCit-NG we will axe this.
20 #include "libcitadel.h"
21 #include "libcitadellocal.h"
24 ConstStr WF_MsgStrs[] = {
33 static JsonValue *WFInfo(const char *Filename, long fnlen, long LineNo, WF_MessageType Type) {
36 Val = NewJsonObject(NULL, 0);
37 JsonObjectAppend(Val, NewJsonPlainString(HKEY("Type"), WF_MsgStrs[Type].Key, WF_MsgStrs[Type].len));
39 NewJsonPlainString(HKEY("File"),
42 NewJsonNumber(HKEY("Line"), LineNo));
47 JsonValue *WildFireMessage(const char *Filename, long fnlen, long LineNo, StrBuf *Msg, WF_MessageType Type) {
50 Ret = NewJsonArray(NULL, 0);
51 JsonArrayAppend(Ret, WFInfo(Filename, fnlen,
54 JsonArrayAppend(Ret, NewJsonString(NULL, 0, Msg, NEWJSONSTRING_COPYBUF));
58 JsonValue *WildFireMessagePlain(const char *Filename, long fnlen, long LineNo, const char *Message, long len, WF_MessageType Type) {
60 Val = NewJsonArray(NULL, 0);
62 JsonArrayAppend(Val, WFInfo(Filename, fnlen, LineNo, Type));
63 JsonArrayAppend(Val, NewJsonPlainString(NULL, 0, Message, len));
67 void WildFireAddArray(JsonValue *ReportBase, JsonValue *Array, WF_MessageType Type) {
69 Val = NewJsonArray(NULL, 0);
70 JsonArrayAppend(Val, NewJsonPlainString(NULL, 0, WF_MsgStrs[Type].Key, WF_MsgStrs[Type].len));
71 JsonArrayAppend(Val, Array);
74 int addr2line_write_pipe[2];
75 int addr2line_read_pipe[2];
80 * Start up the addr2line daemon so we can decode function pointers
82 static void start_addr2line_daemon(const char *binary)
84 struct stat filestats;
86 const char *addr2line = "/usr/bin/addr2line";
87 const char minuse[] = "-e";
89 printf("Starting addr2line daemon for decoding of backtraces\n");
91 if ((stat(addr2line, &filestats)==-1) ||
92 (filestats.st_size==0)){
93 printf("didn't find addr2line daemon in %s: %s\n", addr2line, strerror(errno));
96 if (pipe(addr2line_write_pipe) != 0) {
97 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
100 if (pipe(addr2line_read_pipe) != 0) {
101 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
105 addr2line_pid = fork();
106 if (addr2line_pid < 0) {
107 printf("Unable to fork addr2line daemon: %s\n", strerror(errno));
110 if (addr2line_pid == 0) {
111 dup2(addr2line_write_pipe[0], 0);
112 dup2(addr2line_read_pipe[1], 1);
113 for (i=2; i<256; ++i) close(i);
114 execl(addr2line, addr2line, minuse, binary, NULL);
115 printf("Unable to exec addr2line daemon: %s\n", strerror(errno));
121 static int addr2lineBacktrace(StrBuf *Function, StrBuf *FileName, StrBuf *Pointer, StrBuf *Buf, unsigned int *FunctionLine) {
123 const char *pch, *pche;
125 write(addr2line_write_pipe[1], SKEY(Pointer));
126 if (StrBufTCP_read_line(Buf, &addr2line_read_pipe[0], 0, &err) <= 0) {
127 StrBufAppendBufPlain(Buf, err, -1, 0);
131 pche = strchr(pch, ':');
132 FlushStrBuf(FileName);
133 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
136 *FunctionLine = atoi(pche);
143 static int ParseBacktrace(char *Line, StrBuf *Function, StrBuf *FileName, unsigned int *FunctionLine) {
147 pche = strchr(pch, '(');
148 if (pche == NULL) return 0;
149 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
151 pche = strchr(pch, '+');
152 if (pche == NULL) return 0;
153 StrBufAppendBufPlain(Function, pch, pche - pch, 0);
155 pche = strchr(pch, ')');
156 if (pche == NULL) return 0;
158 sscanf(pch, "%x", FunctionLine);
159 StrBufAppendBufPlain(Function, pche + 1, -1, 0);
164 StrBuf *FullBinaryName = NULL;
166 void WildFireShutdown(void) {
167 close(addr2line_write_pipe[0]);
168 close(addr2line_read_pipe[0]);
170 FreeStrBuf(&FullBinaryName);
173 void WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip) {
175 #ifdef HAVE_BACKTRACE
176 void *stack_frames[100];
184 unsigned int FunctionLine;
185 struct stat filestats;
187 FileName = NewStrBuf();
188 Function = NewStrBuf();
189 Pointer = NewStrBuf();
192 BaseFrames = size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
194 BaseFrames += AddBaseFrameSkip;
195 strings = backtrace_symbols(stack_frames, size);
196 for (i = 1; i < size; i++) {
197 if (strings != NULL){
198 ParseBacktrace(strings[i], Function,
201 FullBinaryName = NewStrBufDup(FileName);
206 getcwd(path, sizeof(path));
207 FullBinaryName = NewStrBufPlain(path, -1);
208 StrBufAppendBufPlain(FullBinaryName, HKEY("/"), 0);
209 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
213 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) || (filestats.st_size==0)) {
214 FlushStrBuf(FullBinaryName);
215 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
216 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) || (filestats.st_size==0)) {
217 FlushStrBuf(FullBinaryName);
218 fprintf(stderr, "unable to open my binary for addr2line checking, verbose backtraces won't work.\n");
222 FreeStrBuf(&FileName);
223 FreeStrBuf(&Function);
224 FreeStrBuf(&Pointer);
226 if (StrLength(FullBinaryName) > 0)
227 start_addr2line_daemon(ChrPtr(FullBinaryName));
232 JsonValue *WildFireException(const char *Filename, long FileLen, long LineNo, StrBuf *Message, int StackOffset) {
235 Val = NewJsonArray(NULL, 0);
237 JsonArrayAppend(Val, WFInfo(Filename, FileLen, LineNo, eEXCEPTION));
238 ExcClass = NewJsonObject(WF_MsgStrs[eTRACE].Key, WF_MsgStrs[eTRACE].len);
239 JsonArrayAppend(Val, ExcClass);
240 JsonObjectAppend(ExcClass, NewJsonPlainString(HKEY("Class"), HKEY("Exception")));
241 JsonObjectAppend(ExcClass, NewJsonString(HKEY("Message"), Message, NEWJSONSTRING_COPYBUF));
242 JsonObjectAppend(ExcClass, NewJsonPlainString(HKEY("File"), Filename, FileLen));
244 JsonObjectAppend(ExcClass, NewJsonPlainString(HKEY("Type"), HKEY("throw")));
246 JsonObjectAppend(ExcClass, NewJsonNumber(HKEY("Line"), LineNo));
248 #ifdef HAVE_BACKTRACE
250 void *stack_frames[100];
260 unsigned int FunctionLine;
262 Trace = NewJsonArray(HKEY("Trace"));
263 JsonObjectAppend(ExcClass, Trace);
264 FileName = NewStrBuf();
265 Function = NewStrBuf();
266 Pointer = NewStrBuf();
269 size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
270 strings = backtrace_symbols(stack_frames, size);
271 for (i = StackOffset + 1; i < size; i++) {
272 if (strings != NULL){
273 ParseBacktrace(strings[i], Function,
278 StrBufPrintf(Pointer, "%p\n", stack_frames[i]);
280 addr2lineBacktrace(Function,
286 Frame = NewJsonObject(NULL, 0);
287 JsonArrayAppend(Trace, Frame);
288 JsonObjectAppend(Frame, NewJsonString(HKEY("function"), Function, NEWJSONSTRING_COPYBUF));
289 JsonObjectAppend(Frame, NewJsonString(HKEY("file"), FileName, NEWJSONSTRING_COPYBUF));
290 JsonObjectAppend(Frame, NewJsonNumber(HKEY("line"), FunctionLine));
291 JsonObjectAppend(Frame, NewJsonArray(HKEY("args"))); // not supported
294 FlushStrBuf(FileName);
295 FlushStrBuf(Function);
296 FlushStrBuf(Pointer);
299 FreeStrBuf(&FileName);
300 FreeStrBuf(&Function);
301 FreeStrBuf(&Pointer);
308 void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr) {
313 const char Concatenate[] = "\\";
314 const char empty[] = "";
319 Header = NewStrBuf();
320 if (*MsgCount == 0) {
321 if (OutBuf != NULL) {
322 StrBufAppendBufPlain(OutBuf,
326 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2\r\n"), 0);
327 StrBufAppendBufPlain(OutBuf,
331 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0\r\n"), 0);
332 StrBufAppendBufPlain(OutBuf,
336 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1\r\n"), 0);
339 AddHdr("X-Wf-Protocol-1",
340 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2");
341 AddHdr("X-Wf-1-Plugin-1",
342 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0");
343 AddHdr("X-Wf-1-Structure-1",
344 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1");
349 StrBufPrintf(N, "%d", StrLength(JsonBuffer));
350 Buf = NewStrBufPlain(NULL, 1024);
351 HeaderName = NewStrBuf();
353 while (StrLength(JsonBuffer) > 0) {
355 StrBufPrintf(HeaderName, "X-Wf-"WF_MAJOR"-"WF_STRUCTINDEX"-"WF_SUB"-%d", n);
356 if (StrLength(JsonBuffer) > 800) {
357 StrBufAppendBufPlain(Buf, ChrPtr(JsonBuffer), 800, 0);
358 StrBufCutLeft(JsonBuffer, 800);
362 StrBufAppendBuf(Buf, JsonBuffer, 0);
363 FlushStrBuf(JsonBuffer);
366 if (OutBuf != NULL) {
367 StrBufAppendPrintf(OutBuf,
375 StrBufAppendPrintf(Header,
380 AddHdr(ChrPtr(HeaderName), ChrPtr(Header));
388 if (OutBuf == NULL) {
393 FreeStrBuf(&HeaderName);
401 /* this is how we do it...
402 void CreateWildfireSampleMessage(void)
411 Header = NewStrBuf();
414 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
415 SerializeJson(Json, Error);
416 WildFireSerializePayload(Json, Header, &n, NULL);
417 StrBufAppendBuf(WC->HBuf, Header, 0);
418 DeleteJSONValue(Error);
422 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Warn message"), eWARN);
423 SerializeJson(Json, Error);
424 WildFireSerializePayload(Json, Header, &n, NULL);
425 StrBufAppendBuf(WC->HBuf, Header, 0);
426 DeleteJSONValue(Error);
430 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Error message"), eERROR);
431 SerializeJson(Json, Error);
432 WildFireSerializePayload(Json, Header, &n, NULL);
433 StrBufAppendBuf(WC->HBuf, Header, 0);
434 DeleteJSONValue(Error);
438 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
439 SerializeJson(Json, Error);
440 WildFireSerializePayload(Json, Header, &n, NULL);
441 StrBufAppendBuf(WC->HBuf, Header, 0);
442 DeleteJSONValue(Error);
446 Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
447 SerializeJson(Json, Error);
448 WildFireSerializePayload(Json, Header, &n, NULL);
449 StrBufAppendBuf(WC->HBuf, Header, 0);
450 DeleteJSONValue(Error);
455 Buf = NewStrBufPlain(HKEY("test error message"));
456 Error = WildFireException(Buf, HKEY(__FILE__), __LINE__, 1);
457 SerializeJson(Json, Error);
458 WildFireSerializePayload(Json, Header, &n, NULL);
459 StrBufAppendBuf(WC->HBuf, Header, 0);
460 DeleteJSONValue(Error);