Back to index

libcitadel  8.12
wildfire.c
Go to the documentation of this file.
00001 
00003 #include "sysdep.h"
00004 #include <sys/types.h>
00005 #include <sys/stat.h>
00006 #include <unistd.h>
00007 #include <dirent.h>
00008 #include <errno.h>
00009 #include <stdio.h>
00010 #include <stdarg.h>
00011 #include <string.h>
00012 
00013 #if HAVE_BACKTRACE
00014 #include <execinfo.h>
00015 #endif
00016 
00017 #include "libcitadel.h"
00018 #include "libcitadellocal.h"
00019 
00020 
00021 ConstStr WF_MsgStrs[] = {
00022        {HKEY("LOG")},
00023        {HKEY("INFO")},
00024        {HKEY("WARN")},
00025        {HKEY("ERROR")},
00026        {HKEY("TRACE")},
00027        {HKEY("EXCEPTION")}
00028 };
00029 
00030 static JsonValue *WFInfo(const char *Filename, long fnlen,
00031                       long LineNo, 
00032                       WF_MessageType Type)
00033 {
00034        JsonValue *Val;
00035 
00036        Val = NewJsonObject(NULL, 0);
00037        JsonObjectAppend(Val, 
00038                       NewJsonPlainString(HKEY("Type"),
00039                                        WF_MsgStrs[Type].Key, 
00040                                        WF_MsgStrs[Type].len));
00041        JsonObjectAppend(Val, 
00042                       NewJsonPlainString(HKEY("File"), 
00043                                        Filename, fnlen));
00044        JsonObjectAppend(Val, 
00045                       NewJsonNumber(HKEY("Line"), LineNo));
00046        return Val;
00047 }
00048                          
00049 
00050 JsonValue *WildFireMessage(const char *Filename, long fnlen,
00051                         long LineNo,
00052                         StrBuf *Msg, 
00053                         WF_MessageType Type)
00054 {
00055        JsonValue *Ret;
00056 
00057        Ret = NewJsonArray(NULL, 0);
00058        JsonArrayAppend(Ret, WFInfo(Filename, fnlen,
00059                                 LineNo, Type));
00060 
00061        JsonArrayAppend(Ret, 
00062                      NewJsonString(NULL, 0, Msg));
00063        return Ret;
00064 }
00065 
00066 JsonValue *WildFireMessagePlain(const char *Filename, long fnlen,
00067                             long LineNo,
00068                             const char *Message, long len, 
00069                             WF_MessageType Type)
00070 {
00071        JsonValue *Val;
00072        Val = NewJsonArray(NULL, 0);
00073 
00074        JsonArrayAppend(Val, WFInfo(Filename, fnlen,
00075                                 LineNo, Type));
00076        JsonArrayAppend(Val, 
00077                      NewJsonPlainString(NULL, 0, Message, len));
00078        return Val;
00079 }
00080 
00081 void WildFireAddArray(JsonValue *ReportBase, JsonValue *Array, WF_MessageType Type)
00082 {
00083        JsonValue *Val;
00084        Val = NewJsonArray(NULL, 0);
00085        JsonArrayAppend(Val, 
00086                      NewJsonPlainString(NULL, 0, 
00087                                       WF_MsgStrs[Type].Key, 
00088                                       WF_MsgStrs[Type].len));
00089 
00090        JsonArrayAppend(Val, Array);
00091 }
00092 
00093 int addr2line_write_pipe[2];
00094 int addr2line_read_pipe[2];
00095 pid_t addr2line_pid;
00096 
00097 #ifdef HAVE_BACKTRACE
00098 /* 
00099  * Start up the addr2line daemon so we can decode function pointers
00100  */
00101 static void start_addr2line_daemon(const char *binary) 
00102 {
00103        struct stat filestats;
00104        int i;
00105        const char *addr2line = "/usr/bin/addr2line";
00106        const char minuse[] = "-e";
00107 
00108        printf("Starting addr2line daemon for decoding of backtraces\n");
00109 
00110        if ((stat(addr2line, &filestats)==-1) ||
00111            (filestats.st_size==0)){
00112               printf("didn't find addr2line daemon in %s: %s\n", addr2line, strerror(errno));
00113               abort();
00114        }
00115        if (pipe(addr2line_write_pipe) != 0) {
00116               printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
00117               abort();
00118        }
00119        if (pipe(addr2line_read_pipe) != 0) {
00120               printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
00121               abort();
00122        }
00123 
00124        addr2line_pid = fork();
00125        if (addr2line_pid < 0) {
00126               printf("Unable to fork addr2line daemon: %s\n", strerror(errno));
00127               abort();
00128        }
00129        if (addr2line_pid == 0) {
00130               dup2(addr2line_write_pipe[0], 0);
00131               dup2(addr2line_read_pipe[1], 1);
00132               for (i=2; i<256; ++i) close(i);
00133               execl(addr2line, addr2line, minuse, binary, NULL);
00134               printf("Unable to exec addr2line daemon: %s\n", strerror(errno));
00135               abort();
00136               exit(errno);
00137        }
00138 }
00139 
00140 static int addr2lineBacktrace(StrBuf *Function, 
00141                            StrBuf *FileName, 
00142                            StrBuf *Pointer, 
00143                            StrBuf *Buf,
00144                            unsigned int *FunctionLine)
00145 
00146 {
00147        const char *err;
00148        const char *pch, *pche;
00149 
00150        write(addr2line_write_pipe[1], SKEY(Pointer));
00151        if (StrBufTCP_read_line(Buf, &addr2line_read_pipe[0], 0, &err) <= 0)
00152        {
00153               StrBufAppendBufPlain(Buf, err, -1, 0);
00154               return 0;
00155        }
00156        pch = ChrPtr(Buf);
00157        pche = strchr(pch, ':');
00158        FlushStrBuf(FileName);
00159        StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
00160        if (pche != NULL)
00161        {
00162               pche++;
00163               *FunctionLine = atoi(pche);
00164        }
00165        else 
00166               *FunctionLine = 0;
00167        return 1;
00168 }
00169 
00170 static int ParseBacktrace(char *Line, 
00171                        StrBuf *Function, 
00172                        StrBuf *FileName, 
00173                        unsigned int *FunctionLine)
00174 {
00175        char *pch, *pche;
00176 
00177        pch = Line;
00178        pche = strchr(pch, '(');
00179        if (pche == NULL) return 0;
00180        StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
00181        pch = pche + 1;
00182        pche = strchr(pch, '+');
00183        if (pche == NULL) return 0;
00184        StrBufAppendBufPlain(Function, pch, pche - pch, 0);
00185        pch = pche + 1;
00186        pche = strchr(pch, ')');
00187        if (pche == NULL) return 0;
00188        *pche = '\0';
00189        sscanf(pch, "%x", FunctionLine);
00190        StrBufAppendBufPlain(Function, pche + 1, -1, 0);
00191        return 1;
00192 }
00193 #endif
00194 long BaseFrames = 0;
00195 StrBuf *FullBinaryName = NULL;
00196 
00197 void WildFireShutdown(void)
00198 {
00199        close(addr2line_write_pipe[0]);
00200        close(addr2line_read_pipe[0]);
00201 
00202        FreeStrBuf(&FullBinaryName);
00203 }
00204 
00205 void WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip)
00206 {
00207 
00208 #ifdef HAVE_BACKTRACE
00209        void *stack_frames[100];
00210        size_t size;
00211        long i;
00212        char **strings;
00213        StrBuf *FileName;
00214        StrBuf *Function;
00215        StrBuf *Pointer;
00216        StrBuf *Buf;
00217        unsigned int FunctionLine;
00218        struct stat filestats;
00219 
00220        FileName = NewStrBuf();
00221        Function = NewStrBuf();
00222        Pointer = NewStrBuf();
00223        Buf = NewStrBuf();
00224 
00225        BaseFrames = size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
00226        BaseFrames --;
00227        BaseFrames += AddBaseFrameSkip;
00228        strings = backtrace_symbols(stack_frames, size);
00229        for (i = 1; i < size; i++) {
00230               if (strings != NULL){
00231                      ParseBacktrace(strings[i], Function, 
00232                                    FileName, 
00233                                    &FunctionLine);
00234                      FullBinaryName = NewStrBufDup(FileName);
00235                      size = i;
00236               }
00237               else {
00238                      char path[256];
00239                      getcwd(path, sizeof(path));
00240                      FullBinaryName = NewStrBufPlain(path, -1);
00241                      StrBufAppendBufPlain(FullBinaryName, HKEY("/"), 0);
00242                      StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
00243                      i = size;
00244                }
00245        }
00246        if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
00247            (filestats.st_size==0)){
00248               FlushStrBuf(FullBinaryName);
00249               StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
00250               if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
00251                   (filestats.st_size==0)){
00252                      FlushStrBuf(FullBinaryName);
00253                      fprintf(stderr, "unable to open my binary for addr2line checking, verbose backtraces won't work.\n");
00254               }
00255        }
00256        free(strings);
00257        FreeStrBuf(&FileName);
00258        FreeStrBuf(&Function);
00259        FreeStrBuf(&Pointer);
00260        FreeStrBuf(&Buf);
00261        if (StrLength(FullBinaryName) > 0)
00262               start_addr2line_daemon(ChrPtr(FullBinaryName));
00263 #endif
00264 
00265 
00266 }
00267 
00268 
00269 JsonValue *WildFireException(const char *Filename, long FileLen,
00270                           long LineNo,
00271                           StrBuf *Message,
00272                           int StackOffset)
00273 {
00274        JsonValue *ExcClass;
00275        JsonValue *Val;
00276        Val = NewJsonArray(NULL, 0);
00277 
00278        JsonArrayAppend(Val, WFInfo(Filename, FileLen,
00279                                 LineNo, eEXCEPTION));
00280 
00281        ExcClass = NewJsonObject(WF_MsgStrs[eTRACE].Key, 
00282                              WF_MsgStrs[eTRACE].len);
00283        
00284        JsonArrayAppend(Val, ExcClass);
00285        JsonObjectAppend(ExcClass, 
00286                       NewJsonPlainString(HKEY("Class"), 
00287                                        HKEY("Exception")));
00288        JsonObjectAppend(ExcClass, 
00289                       NewJsonString(HKEY("Message"), Message));
00290        JsonObjectAppend(ExcClass, 
00291                       NewJsonPlainString(HKEY("File"), 
00292                                        Filename, FileLen));
00293 /*
00294        JsonObjectAppend(ExcClass, 
00295                       NewJsonPlainString(HKEY("Type"), 
00296                                        HKEY("throw")));
00297 */
00298        JsonObjectAppend(ExcClass, 
00299                       NewJsonNumber(HKEY("Line"), LineNo));
00300 
00301 #ifdef HAVE_BACKTRACE
00302        {
00303               void *stack_frames[100];
00304               size_t size;
00305               long i;
00306               char **strings;
00307               JsonValue *Trace;
00308               JsonValue *Frame;
00309               StrBuf *FileName;
00310               StrBuf *Function;
00311               StrBuf *Pointer;
00312               StrBuf *Buf;
00313               unsigned int FunctionLine;
00314 
00315               Trace = NewJsonArray(HKEY("Trace"));
00316               JsonObjectAppend(ExcClass, Trace);
00317               FileName = NewStrBuf();
00318               Function = NewStrBuf();
00319               Pointer = NewStrBuf();
00320               Buf = NewStrBuf();
00321 
00322               size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
00323               strings = backtrace_symbols(stack_frames, size);
00324               for (i = StackOffset + 1; i < size; i++) {
00325                      if (strings != NULL){
00326                             ParseBacktrace(strings[i], Function, 
00327                                           FileName,
00328                                           &FunctionLine);
00329                             
00330                      }
00331                      StrBufPrintf(Pointer, "%p\n", stack_frames[i]);
00332                      
00333                      addr2lineBacktrace(Function, 
00334                                       FileName, 
00335                                       Pointer, 
00336                                       Buf, 
00337                                       &FunctionLine);
00338 
00339                      Frame = NewJsonObject(NULL, 0);
00340                      JsonArrayAppend(Trace, Frame);
00341                      JsonObjectAppend(Frame, 
00342                                     NewJsonString(HKEY("function"), Function));
00343                      JsonObjectAppend(Frame, 
00344                                     NewJsonString(HKEY("file"), FileName));
00345                      JsonObjectAppend(Frame, 
00346                                     NewJsonNumber(HKEY("line"), FunctionLine));
00347                      JsonObjectAppend(Frame, 
00348                                     NewJsonArray(HKEY("args")));/* not supportet... */
00349 
00350                      FunctionLine = 0;
00351                      FlushStrBuf(FileName);
00352                      FlushStrBuf(Function);
00353                      FlushStrBuf(Pointer);
00354               }
00355               free(strings);
00356               FreeStrBuf(&FileName);
00357               FreeStrBuf(&Function);
00358               FreeStrBuf(&Pointer);
00359               FreeStrBuf(&Buf);
00360        }
00361 #endif
00362        return Val;
00363 }
00364 
00365 void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr)
00366 {
00367        int n = *MsgCount;
00368        StrBuf *Buf;
00369        StrBuf *HeaderName;
00370        StrBuf *N; 
00371        const char Concatenate[] = "\\";
00372        const char empty[] = "";
00373        const char *Cat;
00374        StrBuf *Header;
00375 
00376        Header = NewStrBuf();
00377        if (*MsgCount == 0) {
00378               if (OutBuf != NULL) {
00379                      StrBufAppendBufPlain(OutBuf, 
00380                                         HKEY( 
00381                                                "X-Wf-Protocol-1" 
00382                                                ": "
00383                                                "http://meta.wildfirehq.org/Protocol/JsonStream/0.2\r\n"), 0);
00384                      StrBufAppendBufPlain(OutBuf, 
00385                                         HKEY( 
00386                                                "X-Wf-1-Plugin-1" 
00387                                                ": " 
00388                                                "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0\r\n"), 0);
00389                      StrBufAppendBufPlain(OutBuf, 
00390                                         HKEY(
00391                                                "X-Wf-1-Structure-1"
00392                                                ": "
00393                                                "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1\r\n"), 0);
00394               }
00395               else {
00396                      AddHdr("X-Wf-Protocol-1", 
00397                             "http://meta.wildfirehq.org/Protocol/JsonStream/0.2");
00398                      AddHdr("X-Wf-1-Plugin-1",
00399                             "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0");
00400                      AddHdr("X-Wf-1-Structure-1",
00401                             "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1");
00402               }
00403        }
00404 
00405        N = NewStrBuf();
00406        StrBufPrintf(N, "%d", StrLength(JsonBuffer));
00407        Buf = NewStrBufPlain(NULL, 1024);
00408        HeaderName = NewStrBuf();
00409 
00410        while (StrLength(JsonBuffer) > 0) {
00411               FlushStrBuf(Buf);
00412               StrBufPrintf(HeaderName, "X-Wf-"WF_MAJOR"-"WF_STRUCTINDEX"-"WF_SUB"-%d", n);
00413               if (StrLength(JsonBuffer) > 800) {
00414                      StrBufAppendBufPlain(Buf, ChrPtr(JsonBuffer), 800, 0);
00415                      StrBufCutLeft(JsonBuffer, 800);
00416                      Cat = Concatenate;
00417               }
00418               else {
00419                      StrBufAppendBuf(Buf, JsonBuffer, 0);
00420                      FlushStrBuf(JsonBuffer);
00421                      Cat = empty;
00422               }
00423               if (OutBuf != NULL) {
00424                      StrBufAppendPrintf(OutBuf, 
00425                                       "%s: %s|%s|%s\r\n", 
00426                                       ChrPtr(HeaderName), 
00427                                       ChrPtr(N),
00428                                       ChrPtr(Buf), 
00429                                       Cat);
00430               }
00431               else {
00432                      StrBufAppendPrintf(Header, 
00433                                       "%s|%s|%s", 
00434                                       ChrPtr(N),
00435                                       ChrPtr(Buf), 
00436                                       Cat);
00437                      AddHdr(ChrPtr(HeaderName), ChrPtr(Header));
00438                      
00439               }
00440 
00441               FlushStrBuf(N);
00442               n++;
00443        }
00444        *MsgCount = n;
00445        if (OutBuf == NULL) {
00446               FreeStrBuf(&Header);
00447        }
00448        FreeStrBuf(&N);
00449        FreeStrBuf(&Buf);
00450        FreeStrBuf(&HeaderName);
00451 }
00452 
00453 
00454 
00455 
00456 
00457 
00458 /* this is how we do it...
00459 void CreateWildfireSampleMessage(void)
00460 {
00461        JsonValue *Error;
00462               
00463        StrBuf *Buf;
00464        StrBuf *Header;
00465        StrBuf *Json;
00466        int n = 1;
00467 
00468        Header = NewStrBuf();
00469        Json = NewStrBuf();
00470 
00471        Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
00472        SerializeJson(Json, Error);
00473        WildFireSerializePayload(Json, Header, &n, NULL);
00474        StrBufAppendBuf(WC->HBuf, Header, 0);
00475        DeleteJSONValue(Error);
00476        FlushStrBuf(Json);
00477        FlushStrBuf(Header);
00478 
00479        Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__,  HKEY("Warn message"), eWARN);
00480        SerializeJson(Json, Error);
00481        WildFireSerializePayload(Json, Header, &n, NULL);
00482        StrBufAppendBuf(WC->HBuf, Header, 0);
00483        DeleteJSONValue(Error);
00484        FlushStrBuf(Json);
00485        FlushStrBuf(Header);
00486 
00487        Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Error message"), eERROR);
00488        SerializeJson(Json, Error);
00489        WildFireSerializePayload(Json, Header, &n, NULL);
00490        StrBufAppendBuf(WC->HBuf, Header, 0);
00491        DeleteJSONValue(Error);
00492        FlushStrBuf(Json);
00493        FlushStrBuf(Header);
00494 
00495        Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
00496        SerializeJson(Json, Error);
00497        WildFireSerializePayload(Json, Header, &n, NULL);
00498        StrBufAppendBuf(WC->HBuf, Header, 0);
00499        DeleteJSONValue(Error);
00500        FlushStrBuf(Json);
00501        FlushStrBuf(Header);
00502 
00503        Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
00504        SerializeJson(Json, Error);
00505        WildFireSerializePayload(Json, Header, &n, NULL);
00506        StrBufAppendBuf(WC->HBuf, Header, 0);
00507        DeleteJSONValue(Error);
00508        FlushStrBuf(Json);
00509        FlushStrBuf(Header);
00510 
00511 
00512        Buf = NewStrBufPlain(HKEY("test error message"));
00513        Error = WildFireException(Buf, HKEY(__FILE__), __LINE__, 1);
00514        SerializeJson(Json, Error);
00515        WildFireSerializePayload(Json, Header, &n, NULL);
00516        StrBufAppendBuf(WC->HBuf, Header, 0);
00517        DeleteJSONValue(Error);
00518 
00519        FlushStrBuf(Json);
00520        FlushStrBuf(Header);
00521 
00522 }
00523 
00524 */