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.
18 #include "libcitadel.h"
19 #include "libcitadellocal.h"
22 ConstStr WF_MsgStrs[] = {
31 static JsonValue *WFInfo(const char *Filename, long fnlen, long LineNo, WF_MessageType Type) {
34 Val = NewJsonObject(NULL, 0);
35 JsonObjectAppend(Val, NewJsonPlainString(HKEY("Type"), WF_MsgStrs[Type].Key, WF_MsgStrs[Type].len));
36 JsonObjectAppend(Val, NewJsonPlainString(HKEY("File"), Filename, fnlen));
37 JsonObjectAppend(Val, NewJsonNumber(HKEY("Line"), LineNo));
42 JsonValue *WildFireMessage(const char *Filename, long fnlen, long LineNo, StrBuf *Msg, WF_MessageType Type) {
45 Ret = NewJsonArray(NULL, 0);
46 JsonArrayAppend(Ret, WFInfo(Filename, fnlen, LineNo, Type));
48 JsonArrayAppend(Ret, NewJsonString(NULL, 0, Msg, NEWJSONSTRING_COPYBUF));
52 JsonValue *WildFireMessagePlain(const char *Filename, long fnlen, long LineNo, const char *Message, long len, WF_MessageType Type) {
54 Val = NewJsonArray(NULL, 0);
56 JsonArrayAppend(Val, WFInfo(Filename, fnlen, LineNo, Type));
57 JsonArrayAppend(Val, NewJsonPlainString(NULL, 0, Message, len));
61 void WildFireAddArray(JsonValue *ReportBase, JsonValue *Array, WF_MessageType Type) {
63 Val = NewJsonArray(NULL, 0);
64 JsonArrayAppend(Val, NewJsonPlainString(NULL, 0, WF_MsgStrs[Type].Key, WF_MsgStrs[Type].len));
65 JsonArrayAppend(Val, Array);
68 int addr2line_write_pipe[2];
69 int addr2line_read_pipe[2];
74 * Start up the addr2line daemon so we can decode function pointers
76 static void start_addr2line_daemon(const char *binary)
78 struct stat filestats;
80 const char *addr2line = "/usr/bin/addr2line";
81 const char minuse[] = "-e";
83 printf("Starting addr2line daemon for decoding of backtraces\n");
85 if ((stat(addr2line, &filestats)==-1) ||
86 (filestats.st_size==0)){
87 printf("didn't find addr2line daemon in %s: %s\n", addr2line, strerror(errno));
90 if (pipe(addr2line_write_pipe) != 0) {
91 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
94 if (pipe(addr2line_read_pipe) != 0) {
95 printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
99 addr2line_pid = fork();
100 if (addr2line_pid < 0) {
101 printf("Unable to fork addr2line daemon: %s\n", strerror(errno));
104 if (addr2line_pid == 0) {
105 dup2(addr2line_write_pipe[0], 0);
106 dup2(addr2line_read_pipe[1], 1);
107 for (i=2; i<256; ++i) close(i);
108 execl(addr2line, addr2line, minuse, binary, NULL);
109 printf("Unable to exec addr2line daemon: %s\n", strerror(errno));
115 static int addr2lineBacktrace(StrBuf *Function, StrBuf *FileName, StrBuf *Pointer, StrBuf *Buf, unsigned int *FunctionLine) {
117 const char *pch, *pche;
119 write(addr2line_write_pipe[1], SKEY(Pointer));
120 if (StrBufTCP_read_line(Buf, &addr2line_read_pipe[0], 0, &err) <= 0) {
121 StrBufAppendBufPlain(Buf, err, -1, 0);
125 pche = strchr(pch, ':');
126 FlushStrBuf(FileName);
127 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
130 *FunctionLine = atoi(pche);
137 static int ParseBacktrace(char *Line, StrBuf *Function, StrBuf *FileName, unsigned int *FunctionLine) {
141 pche = strchr(pch, '(');
142 if (pche == NULL) return 0;
143 StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
145 pche = strchr(pch, '+');
146 if (pche == NULL) return 0;
147 StrBufAppendBufPlain(Function, pch, pche - pch, 0);
149 pche = strchr(pch, ')');
150 if (pche == NULL) return 0;
152 sscanf(pch, "%x", FunctionLine);
153 StrBufAppendBufPlain(Function, pche + 1, -1, 0);
158 StrBuf *FullBinaryName = NULL;
160 void WildFireShutdown(void) {
161 close(addr2line_write_pipe[0]);
162 close(addr2line_read_pipe[0]);
164 FreeStrBuf(&FullBinaryName);
167 void WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip) {
169 #ifdef HAVE_BACKTRACE
170 void *stack_frames[100];
178 unsigned int FunctionLine;
179 struct stat filestats;
181 FileName = NewStrBuf();
182 Function = NewStrBuf();
183 Pointer = NewStrBuf();
186 BaseFrames = size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
188 BaseFrames += AddBaseFrameSkip;
189 strings = backtrace_symbols(stack_frames, size);
190 for (i = 1; i < size; i++) {
191 if (strings != NULL){
192 ParseBacktrace(strings[i], Function, FileName, &FunctionLine);
193 FullBinaryName = NewStrBufDup(FileName);
198 getcwd(path, sizeof(path));
199 FullBinaryName = NewStrBufPlain(path, -1);
200 StrBufAppendBufPlain(FullBinaryName, HKEY("/"), 0);
201 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
205 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) || (filestats.st_size==0)) {
206 FlushStrBuf(FullBinaryName);
207 StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
208 if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) || (filestats.st_size==0)) {
209 FlushStrBuf(FullBinaryName);
210 fprintf(stderr, "unable to open my binary for addr2line checking, verbose backtraces won't work.\n");
214 FreeStrBuf(&FileName);
215 FreeStrBuf(&Function);
216 FreeStrBuf(&Pointer);
218 if (StrLength(FullBinaryName) > 0)
219 start_addr2line_daemon(ChrPtr(FullBinaryName));
224 JsonValue *WildFireException(const char *Filename, long FileLen, long LineNo, StrBuf *Message, int StackOffset) {
227 Val = NewJsonArray(NULL, 0);
229 JsonArrayAppend(Val, WFInfo(Filename, FileLen, LineNo, eEXCEPTION));
230 ExcClass = NewJsonObject(WF_MsgStrs[eTRACE].Key, WF_MsgStrs[eTRACE].len);
231 JsonArrayAppend(Val, ExcClass);
232 JsonObjectAppend(ExcClass, NewJsonPlainString(HKEY("Class"), HKEY("Exception")));
233 JsonObjectAppend(ExcClass, NewJsonString(HKEY("Message"), Message, NEWJSONSTRING_COPYBUF));
234 JsonObjectAppend(ExcClass, NewJsonPlainString(HKEY("File"), Filename, FileLen));
236 JsonObjectAppend(ExcClass, NewJsonPlainString(HKEY("Type"), HKEY("throw")));
238 JsonObjectAppend(ExcClass, NewJsonNumber(HKEY("Line"), LineNo));
240 #ifdef HAVE_BACKTRACE
242 void *stack_frames[100];
252 unsigned int FunctionLine;
254 Trace = NewJsonArray(HKEY("Trace"));
255 JsonObjectAppend(ExcClass, Trace);
256 FileName = NewStrBuf();
257 Function = NewStrBuf();
258 Pointer = NewStrBuf();
261 size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
262 strings = backtrace_symbols(stack_frames, size);
263 for (i = StackOffset + 1; i < size; i++) {
264 if (strings != NULL){
265 ParseBacktrace(strings[i], Function, FileName, &FunctionLine);
267 StrBufPrintf(Pointer, "%p\n", stack_frames[i]);
268 addr2lineBacktrace(Function, FileName, Pointer, Buf, &FunctionLine);
269 Frame = NewJsonObject(NULL, 0);
270 JsonArrayAppend(Trace, Frame);
271 JsonObjectAppend(Frame, NewJsonString(HKEY("function"), Function, NEWJSONSTRING_COPYBUF));
272 JsonObjectAppend(Frame, NewJsonString(HKEY("file"), FileName, NEWJSONSTRING_COPYBUF));
273 JsonObjectAppend(Frame, NewJsonNumber(HKEY("line"), FunctionLine));
274 JsonObjectAppend(Frame, NewJsonArray(HKEY("args"))); // not supported
276 FlushStrBuf(FileName);
277 FlushStrBuf(Function);
278 FlushStrBuf(Pointer);
281 FreeStrBuf(&FileName);
282 FreeStrBuf(&Function);
283 FreeStrBuf(&Pointer);
290 void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr) {
295 const char Concatenate[] = "\\";
296 const char empty[] = "";
301 Header = NewStrBuf();
302 if (*MsgCount == 0) {
303 if (OutBuf != NULL) {
304 StrBufAppendBufPlain(OutBuf,
308 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2\r\n"), 0);
309 StrBufAppendBufPlain(OutBuf,
313 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0\r\n"), 0);
314 StrBufAppendBufPlain(OutBuf,
318 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1\r\n"), 0);
321 AddHdr("X-Wf-Protocol-1",
322 "http://meta.wildfirehq.org/Protocol/JsonStream/0.2");
323 AddHdr("X-Wf-1-Plugin-1",
324 "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0");
325 AddHdr("X-Wf-1-Structure-1",
326 "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1");
331 StrBufPrintf(N, "%d", StrLength(JsonBuffer));
332 Buf = NewStrBufPlain(NULL, 1024);
333 HeaderName = NewStrBuf();
335 while (StrLength(JsonBuffer) > 0) {
337 StrBufPrintf(HeaderName, "X-Wf-"WF_MAJOR"-"WF_STRUCTINDEX"-"WF_SUB"-%d", n);
338 if (StrLength(JsonBuffer) > 800) {
339 StrBufAppendBufPlain(Buf, ChrPtr(JsonBuffer), 800, 0);
340 StrBufCutLeft(JsonBuffer, 800);
344 StrBufAppendBuf(Buf, JsonBuffer, 0);
345 FlushStrBuf(JsonBuffer);
348 if (OutBuf != NULL) {
349 StrBufAppendPrintf(OutBuf, "%s: %s|%s|%s\r\n", ChrPtr(HeaderName), ChrPtr(N), ChrPtr(Buf), Cat);
352 StrBufAppendPrintf(Header, "%s|%s|%s", ChrPtr(N), ChrPtr(Buf), Cat);
353 AddHdr(ChrPtr(HeaderName), ChrPtr(Header));
360 if (OutBuf == NULL) {
365 FreeStrBuf(&HeaderName);