Breakpad: untested update to linux/mac specific parts of llappviewer

This commit is contained in:
Latif Khalifa
2013-10-02 00:51:29 +02:00
parent d20b7815df
commit b125ec8d51
4 changed files with 38 additions and 439 deletions

View File

@@ -46,27 +46,6 @@
#include <exception>
#if LL_LINUX
# include <dlfcn.h> // RTLD_LAZY
# include <execinfo.h> // backtrace - glibc only
# include <sys/types.h>
# include <unistd.h>
# include <dirent.h>
# include <boost/algorithm/string.hpp>
#elif LL_SOLARIS
# include <sys/types.h>
# include <unistd.h>
# include <fcntl.h>
# include <ucontext.h>
#endif
#ifdef LL_ELFBIN
# ifdef __GNUC__
# include <cxxabi.h> // for symbol demangling
# endif
# include "ELFIO/ELFIO.h" // for better backtraces
#endif
#if LL_DBUS_ENABLED
# include "llappviewerlinux_api_dbus.h"
@@ -90,8 +69,9 @@ static void exceptionTerminateHandler()
// reinstall default terminate() handler in case we re-terminate.
if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler);
// treat this like a regular viewer crash, with nice stacktrace etc.
LLAppViewer::handleSyncViewerCrash();
LLAppViewer::handleViewerCrash();
long *null_ptr;
null_ptr = 0;
*null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad.
// we've probably been killed-off before now, but...
gOldTerminateHandler(); // call old terminate() handler
}
@@ -114,7 +94,6 @@ int main( int argc, char **argv )
gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
// install crash handlers
viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
viewer_app_ptr->setSyncErrorHandler(LLAppViewer::handleSyncViewerCrash);
bool ok = viewer_app_ptr->init();
if(!ok)
@@ -144,201 +123,6 @@ int main( int argc, char **argv )
return 0;
}
#ifdef LL_SOLARIS
static inline BOOL do_basic_glibc_backtrace()
{
BOOL success = FALSE;
std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
llinfos << "Opening stack trace file " << strace_filename << llendl;
LLFILE* StraceFile = LLFile::fopen(strace_filename, "w");
if (!StraceFile)
{
llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
StraceFile = stderr;
}
printstack(fileno(StraceFile));
if (StraceFile != stderr)
fclose(StraceFile);
return success;
}
#else
#define MAX_STACK_TRACE_DEPTH 40
// This uses glibc's basic built-in stack-trace functions for a not very
// amazing backtrace.
static inline BOOL do_basic_glibc_backtrace()
{
void *stackarray[MAX_STACK_TRACE_DEPTH];
size_t size;
char **strings;
size_t i;
BOOL success = FALSE;
size = backtrace(stackarray, MAX_STACK_TRACE_DEPTH);
strings = backtrace_symbols(stackarray, size);
std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
llinfos << "Opening stack trace file " << strace_filename << llendl;
LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore
if (!StraceFile)
{
llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
StraceFile = stderr;
}
if (size)
{
for (i = 0; i < size; i++)
{
// the format of the StraceFile is very specific, to allow (kludgy) machine-parsing
fprintf(StraceFile, "%-3lu ", (unsigned long)i);
fprintf(StraceFile, "%-32s\t", "unknown");
fprintf(StraceFile, "%p ", stackarray[i]);
fprintf(StraceFile, "%s\n", strings[i]);
}
success = TRUE;
}
if (StraceFile != stderr)
fclose(StraceFile);
free (strings);
return success;
}
#if LL_ELFBIN
// This uses glibc's basic built-in stack-trace functions together with
// ELFIO's ability to parse the .symtab ELF section for better symbol
// extraction without exporting symbols (which'd cause subtle, fatal bugs).
static inline BOOL do_elfio_glibc_backtrace()
{
void *stackarray[MAX_STACK_TRACE_DEPTH];
size_t btsize;
char **strings;
BOOL success = FALSE;
std::string appfilename = gDirUtilp->getExecutablePathAndName();
std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
llinfos << "Opening stack trace file " << strace_filename << llendl;
LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore
if (!StraceFile)
{
llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
StraceFile = stderr;
}
// get backtrace address list and basic symbol info
btsize = backtrace(stackarray, MAX_STACK_TRACE_DEPTH);
strings = backtrace_symbols(stackarray, btsize);
// create ELF reader for our app binary
IELFI* pReader;
const IELFISection* pSec = NULL;
IELFISymbolTable* pSymTbl = 0;
if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) ||
ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) ||
// find symbol table, create reader-object
NULL == (pSec = pReader->GetSection( ".symtab" )) ||
ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) )
{
// Failed to open our binary and read its symbol table somehow
llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl;
if (StraceFile != stderr)
fclose(StraceFile);
// note that we may be leaking some of the above ELFIO
// objects now, but it's expected that we'll be dead soon
// and we want to tread delicately until we get *some* kind
// of useful backtrace.
return do_basic_glibc_backtrace();
}
// iterate over trace and symtab, looking for plausible symbols
std::string name;
Elf32_Addr value;
Elf32_Word ssize;
unsigned char bind;
unsigned char type;
Elf32_Half section;
int nSymNo = pSymTbl->GetSymbolNum();
size_t btpos;
for (btpos = 0; btpos < btsize; ++btpos)
{
// the format of the StraceFile is very specific, to allow (kludgy) machine-parsing
fprintf(StraceFile, "%-3ld ", (long)btpos);
int symidx;
for (symidx = 0; symidx < nSymNo; ++symidx)
{
if (ERR_ELFIO_NO_ERROR ==
pSymTbl->GetSymbol(symidx, name, value, ssize,
bind, type, section))
{
// check if trace address within symbol range
if (uintptr_t(stackarray[btpos]) >= value &&
uintptr_t(stackarray[btpos]) < value+ssize)
{
// symbol is inside viewer
fprintf(StraceFile, "%-32s\t", "com.secondlife.indra.viewer");
fprintf(StraceFile, "%p ", stackarray[btpos]);
char *demangled_str = NULL;
int demangle_result = 1;
demangled_str =
abi::__cxa_demangle
(name.c_str(), NULL, NULL,
&demangle_result);
if (0 == demangle_result &&
NULL != demangled_str) {
fprintf(StraceFile,
"%s", demangled_str);
free(demangled_str);
}
else // failed demangle; print it raw
{
fprintf(StraceFile,
"%s", name.c_str());
}
// print offset from symbol start
fprintf(StraceFile,
" + %lu\n",
uintptr_t(stackarray[btpos]) -
value);
goto got_sym; // early escape
}
}
}
// Fallback:
// Didn't find a suitable symbol in the binary - it's probably
// a symbol in a DSO; use glibc's idea of what it should be.
fprintf(StraceFile, "%-32s\t", "unknown");
fprintf(StraceFile, "%p ", stackarray[btpos]);
fprintf(StraceFile, "%s\n", strings[btpos]);
got_sym:;
}
if (StraceFile != stderr)
fclose(StraceFile);
pSymTbl->Release();
pSec->Release();
pReader->Release();
free(strings);
llinfos << "Finished generating stack trace." << llendl;
success = TRUE;
return success;
}
#endif // LL_ELFBIN
#endif // LL_SOLARIS
LLAppViewerLinux::LLAppViewerLinux()
{
}
@@ -355,7 +139,17 @@ bool LLAppViewerLinux::init()
// really early in app startup!
if (!g_thread_supported ()) g_thread_init (NULL);
return LLAppViewer::init();
bool success = LLAppViewer::init();
#if LL_SEND_CRASH_REPORTS
if (success)
{
LLAppViewer* pApp = LLAppViewer::instance();
pApp->initCrashReporting();
}
#endif
return success;
}
bool LLAppViewerLinux::restoreErrorTrap()
@@ -547,101 +341,10 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
}
#endif // LL_DBUS_ENABLED
void LLAppViewerLinux::handleSyncCrashTrace()
void LLAppViewerLinux::initCrashReporting(bool reportFreeze)
{
// This backtrace writes into stack_trace.log
# if LL_ELFBIN
do_elfio_glibc_backtrace(); // more useful backtrace
# else
do_basic_glibc_backtrace(); // only slightly useful backtrace
# endif // LL_ELFBIN
}
void LLAppViewerLinux::handleCrashReporting(bool reportFreeze)
{
std::string cmd =gDirUtilp->getAppRODataDir();
cmd += gDirUtilp->getDirDelimiter();
#if LL_LINUX
cmd += "linux-crash-logger.bin";
#elif LL_SOLARIS
cmd += "solaris-crash-logger";
#else
# error Unknown platform
#endif
if(reportFreeze)
{
char* const cmdargv[] =
{(char*)cmd.c_str(),
(char*)"-previous",
NULL};
fflush(NULL); // flush all buffers before the child inherits them
pid_t pid = fork();
if (pid == 0)
{ // child
execv(cmd.c_str(), cmdargv); /* Flawfinder: Ignore */
llwarns << "execv failure when trying to start " << cmd << llendl;
_exit(1); // avoid atexit()
} else {
if (pid > 0)
{
// wait for child proc to die
int childExitStatus;
waitpid(pid, &childExitStatus, 0);
} else {
llwarns << "fork failure." << llendl;
}
}
}
else
{
const S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
// Always generate the report, have the logger do the asking, and
// don't wait for the logger before exiting (-> total cleanup).
if (CRASH_BEHAVIOR_NEVER_SEND != cb)
{
// launch the actual crash logger
const char* ask_dialog = "-dialog";
if (CRASH_BEHAVIOR_ASK != cb)
ask_dialog = ""; // omit '-dialog' option
const char * cmdargv[] =
{cmd.c_str(),
ask_dialog,
"-user",
(char*)LLViewerLogin::getInstance()->getGridLabel().c_str(),
"-name",
LLAppViewer::instance()->getSecondLifeTitle().c_str(),
NULL};
fflush(NULL);
pid_t pid = fork();
if (pid == 0)
{ // child
execv(cmd.c_str(), (char* const*) cmdargv); /* Flawfinder: ignore */
llwarns << "execv failure when trying to start " << cmd << llendl;
_exit(1); // avoid atexit()
}
else
{
if (pid > 0)
{
// DO NOT wait for child proc to die; we want
// the logger to outlive us while we quit to
// free up the screen/keyboard/etc.
////int childExitStatus;
////waitpid(pid, &childExitStatus, 0);
}
else
{
llwarns << "fork failure." << llendl;
}
}
}
// Sometimes signals don't seem to quit the viewer. Also, we may
// have been called explicitly instead of from a signal handler.
// Make sure we exit so as to not totally confuse the user.
_exit(1); // avoid atexit(), else we may re-crash in dtors.
// Singu Note: this is where original code forks crash logger process.
// Singularity doesn't need it
}
}
@@ -676,7 +379,6 @@ bool LLAppViewerLinux::beingDebugged()
base += 1;
}
//should valgrind be added here?
if (strcmp(base, "gdb") == 0)
{
debugged = yes;
@@ -693,6 +395,8 @@ bool LLAppViewerLinux::beingDebugged()
bool LLAppViewerLinux::initLogging()
{
// Remove the last stack trace, if any
// This file is no longer created, since the move to Google Breakpad
// The code is left here to clean out any old state in the log dir
std::string old_stack_file =
gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
LLFile::remove(old_stack_file);
@@ -739,6 +443,7 @@ std::string LLAppViewerLinux::generateSerialNumber()
// trawl /dev/disk/by-uuid looking for a good-looking UUID to grab
std::string this_name;
LLDirIterator iter(uuiddir, "*");
while (iter.next(this_name))
{