00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llappviewerlinux.h"
00035
00036 #include "llcommandlineparser.h"
00037
00038 #include "llmemtype.h"
00039 #include "llviewernetwork.h"
00040 #include "llviewercontrol.h"
00041 #include "llmd5.h"
00042 #include "llfindlocale.h"
00043
00044 #include <exception>
00045
00046 #if LL_LINUX
00047 # include <dlfcn.h>
00048 # include <execinfo.h>
00049 # ifndef LL_ELFBIN
00050 # define LL_ELFBIN 1
00051 # endif // LL_ELFBIN
00052 # if LL_ELFBIN
00053 # include <cxxabi.h>
00054 # include "ELFIO.h"
00055 # endif // LL_ELFBIN
00056 #elif LL_SOLARIS
00057 # include <sys/types.h>
00058 # include <unistd.h>
00059 # include <fcntl.h>
00060 # include <ucontext.h>
00061 #endif
00062
00063 namespace
00064 {
00065 int gArgC = 0;
00066 char **gArgV = NULL;
00067 void (*gOldTerminateHandler)() = NULL;
00068 }
00069
00070 static void exceptionTerminateHandler()
00071 {
00072
00073 if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler);
00074
00075 LLAppViewer::handleSyncViewerCrash();
00076 LLAppViewer::handleViewerCrash();
00077
00078 gOldTerminateHandler();
00079 }
00080
00081 int main( int argc, char **argv )
00082 {
00083 LLMemType mt1(LLMemType::MTYPE_STARTUP);
00084
00085 #if LL_SOLARIS && defined(__sparc)
00086 asm ("ta\t6");
00087 #endif
00088
00089 gArgC = argc;
00090 gArgV = argv;
00091
00092 LLAppViewer* viewer_app_ptr = new LLAppViewerLinux();
00093
00094
00095 gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
00096
00097 viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
00098 viewer_app_ptr->setSyncErrorHandler(LLAppViewer::handleSyncViewerCrash);
00099
00100 bool ok = viewer_app_ptr->init();
00101 if(!ok)
00102 {
00103 llwarns << "Application init failed." << llendl;
00104 return -1;
00105 }
00106
00107
00108 if(!LLApp::isQuitting())
00109 {
00110 viewer_app_ptr->mainLoop();
00111 }
00112
00113 if (!LLApp::isError())
00114 {
00115
00116
00117
00118
00119
00120 viewer_app_ptr->cleanup();
00121 }
00122 delete viewer_app_ptr;
00123 viewer_app_ptr = NULL;
00124 return 0;
00125 }
00126
00127 #ifdef LL_SOLARIS
00128 static inline BOOL do_basic_glibc_backtrace()
00129 {
00130 BOOL success = FALSE;
00131
00132 std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
00133 llinfos << "Opening stack trace file " << strace_filename << llendl;
00134 LLFILE* StraceFile = LLFile::fopen(strace_filename.c_str(), "w");
00135 if (!StraceFile)
00136 {
00137 llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
00138 StraceFile = stderr;
00139 }
00140
00141 printstack(fileno(StraceFile));
00142
00143 if (StraceFile != stderr)
00144 fclose(StraceFile);
00145
00146 return success;
00147 }
00148 #else
00149 #define MAX_STACK_TRACE_DEPTH 40
00150
00151
00152 static inline BOOL do_basic_glibc_backtrace()
00153 {
00154 void *array[MAX_STACK_TRACE_DEPTH];
00155 size_t size;
00156 char **strings;
00157 size_t i;
00158 BOOL success = FALSE;
00159
00160 size = backtrace(array, MAX_STACK_TRACE_DEPTH);
00161 strings = backtrace_symbols(array, size);
00162
00163 std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
00164 llinfos << "Opening stack trace file " << strace_filename << llendl;
00165 LLFILE* StraceFile = LLFile::fopen(strace_filename.c_str(), "w");
00166 if (!StraceFile)
00167 {
00168 llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
00169 StraceFile = stderr;
00170 }
00171
00172 if (size)
00173 {
00174 for (i = 0; i < size; i++)
00175 fputs((std::string(strings[i])+"\n").c_str(),
00176 StraceFile);
00177
00178 success = TRUE;
00179 }
00180
00181 if (StraceFile != stderr)
00182 fclose(StraceFile);
00183
00184 free (strings);
00185 return success;
00186 }
00187
00188 #if LL_ELFBIN
00189
00190
00191
00192 static inline BOOL do_elfio_glibc_backtrace()
00193 {
00194 void *array[MAX_STACK_TRACE_DEPTH];
00195 size_t btsize;
00196 char **strings;
00197 BOOL success = FALSE;
00198
00199 std::string appfilename = gDirUtilp->getExecutablePathAndName();
00200
00201 std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
00202 llinfos << "Opening stack trace file " << strace_filename << llendl;
00203 LLFILE* StraceFile = LLFile::fopen(strace_filename.c_str(), "w");
00204 if (!StraceFile)
00205 {
00206 llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
00207 StraceFile = stderr;
00208 }
00209
00210
00211 btsize = backtrace(array, MAX_STACK_TRACE_DEPTH);
00212 strings = backtrace_symbols(array, btsize);
00213
00214
00215 IELFI* pReader;
00216 const IELFISection* pSec = NULL;
00217 IELFISymbolTable* pSymTbl = 0;
00218 if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) ||
00219 ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) ||
00220
00221 NULL == (pSec = pReader->GetSection( ".symtab" )) ||
00222 ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) )
00223 {
00224
00225 llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl;
00226 if (StraceFile != stderr)
00227 fclose(StraceFile);
00228
00229
00230
00231
00232 return do_basic_glibc_backtrace();
00233 }
00234
00235
00236 std::string name;
00237 Elf32_Addr value;
00238 Elf32_Word ssize;
00239 unsigned char bind;
00240 unsigned char type;
00241 Elf32_Half section;
00242 int nSymNo = pSymTbl->GetSymbolNum();
00243 size_t btpos;
00244 for (btpos = 0; btpos < btsize; ++btpos)
00245 {
00246 fprintf(StraceFile, "%d:\t", btpos);
00247 int symidx;
00248 for (symidx = 0; symidx < nSymNo; ++symidx)
00249 {
00250 if (ERR_ELFIO_NO_ERROR ==
00251 pSymTbl->GetSymbol(symidx, name, value, ssize,
00252 bind, type, section))
00253 {
00254
00255 if (uintptr_t(array[btpos]) >= value &&
00256 uintptr_t(array[btpos]) < value+ssize)
00257 {
00258 char *demangled_str = NULL;
00259 int demangle_result = 1;
00260 demangled_str =
00261 abi::__cxa_demangle
00262 (name.c_str(), NULL, NULL,
00263 &demangle_result);
00264 if (0 == demangle_result &&
00265 NULL != demangled_str) {
00266 fprintf(StraceFile,
00267 "ELF(%s", demangled_str);
00268 free(demangled_str);
00269 }
00270 else
00271 {
00272 fprintf(StraceFile,
00273 "ELF(%s", name.c_str());
00274 }
00275
00276 fprintf(StraceFile,
00277 "+0x%lx) [%p]\n",
00278 uintptr_t(array[btpos]) -
00279 value,
00280 array[btpos]);
00281 goto got_sym;
00282 }
00283 }
00284 }
00285
00286
00287
00288 fprintf(StraceFile, "%s\n", strings[btpos]);
00289 got_sym:;
00290 }
00291
00292 if (StraceFile != stderr)
00293 fclose(StraceFile);
00294
00295 pSymTbl->Release();
00296 pSec->Release();
00297 pReader->Release();
00298
00299 free(strings);
00300
00301 llinfos << "Finished generating stack trace." << llendl;
00302
00303 success = TRUE;
00304 return success;
00305 }
00306 #endif // LL_ELFBIN
00307
00308 #endif // LL_SOLARIS
00309
00310
00311 LLAppViewerLinux::LLAppViewerLinux()
00312 {
00313 }
00314
00315 LLAppViewerLinux::~LLAppViewerLinux()
00316 {
00317 }
00318
00319 bool LLAppViewerLinux::init()
00320 {
00321 return LLAppViewer::init();
00322 }
00323
00324 void LLAppViewerLinux::handleSyncCrashTrace()
00325 {
00326
00327 # if LL_ELFBIN
00328 do_elfio_glibc_backtrace();
00329 # else
00330 do_basic_glibc_backtrace();
00331 # endif // LL_ELFBIN
00332 }
00333
00334 void LLAppViewerLinux::handleCrashReporting()
00335 {
00336
00337
00338 if (CRASH_BEHAVIOR_NEVER_SEND != LLAppViewer::instance()->getCrashBehavior())
00339 {
00340
00341 char* ask_dialog = "-dialog";
00342 if (CRASH_BEHAVIOR_ASK != LLAppViewer::instance()->getCrashBehavior())
00343 ask_dialog = "";
00344 std::string cmd =gDirUtilp->getAppRODataDir();
00345 cmd += gDirUtilp->getDirDelimiter();
00346 cmd += "linux-crash-logger.bin";
00347 char* const cmdargv[] =
00348 {(char*)cmd.c_str(),
00349 ask_dialog,
00350 (char*)"-user",
00351 (char*)gGridName.c_str(),
00352 (char*)"-name",
00353 (char*)LLAppViewer::instance()->getSecondLifeTitle().c_str(),
00354 NULL};
00355 fflush(NULL);
00356 pid_t pid = fork();
00357 if (pid == 0)
00358 {
00359 execv(cmd.c_str(), cmdargv);
00360 llwarns << "execv failure when trying to start " << cmd << llendl;
00361 _exit(1);
00362 }
00363 else
00364 {
00365 if (pid > 0)
00366 {
00367
00368
00369
00372 }
00373 else
00374 {
00375 llwarns << "fork failure." << llendl;
00376 }
00377 }
00378 }
00379
00380
00381
00382 _exit(1);
00383 }
00384
00385 bool LLAppViewerLinux::beingDebugged()
00386 {
00387 static enum {unknown, no, yes} debugged = unknown;
00388
00389 if (debugged == unknown)
00390 {
00391 pid_t ppid = getppid();
00392 char *name;
00393 int ret;
00394
00395 ret = asprintf(&name, "/proc/%d/exe", ppid);
00396 if (ret != -1)
00397 {
00398 char buf[1024];
00399 ssize_t n;
00400
00401 n = readlink(name, buf, sizeof(buf) - 1);
00402 if (n != -1)
00403 {
00404 char *base = strrchr(buf, '/');
00405 buf[n + 1] = '\0';
00406 if (base == NULL)
00407 {
00408 base = buf;
00409 } else {
00410 base += 1;
00411 }
00412
00413 if (strcmp(base, "gdb") == 0)
00414 {
00415 debugged = yes;
00416 }
00417 }
00418 free(name);
00419 }
00420 }
00421
00422 return debugged == yes;
00423 }
00424
00425 bool LLAppViewerLinux::initLogging()
00426 {
00427
00428 std::string old_stack_file =
00429 gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
00430 LLFile::remove(old_stack_file.c_str());
00431
00432 return LLAppViewer::initLogging();
00433 }
00434
00435 bool LLAppViewerLinux::initParseCommandLine(LLCommandLineParser& clp)
00436 {
00437 if (!clp.parseCommandLine(gArgC, gArgV))
00438 {
00439 return false;
00440 }
00441
00442
00443 FL_Locale *locale = NULL;
00444 FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
00445 if (success != 0)
00446 {
00447 if (success >= 2 && locale->lang)
00448 {
00449 LLControlVariable* c = gSavedSettings.getControl("SystemLanguage");
00450 if(c)
00451 {
00452 c->setValue(std::string(locale->lang), false);
00453 }
00454 }
00455 FL_FreeLocale(&locale);
00456 }
00457
00458 return true;
00459 }
00460
00461 std::string LLAppViewerLinux::generateSerialNumber()
00462 {
00463 char serial_md5[MD5HEX_STR_SIZE];
00464 serial_md5[0] = 0;
00465
00466
00467
00468 return serial_md5;
00469 }