aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llappviewerlinux.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:45:19 -0500
committerJacek Antonelli2008-08-15 23:45:19 -0500
commitb235c59d60472f818a9142c0886b95a0ff4191d7 (patch)
treed323c55587584b19cc43a03f58a178823f12d3cd /linden/indra/newview/llappviewerlinux.cpp
parentSecond Life viewer sources 1.18.5.3 (diff)
downloadmeta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.zip
meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.tar.gz
meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.tar.bz2
meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.tar.xz
Second Life viewer sources 1.18.6.0-RC
Diffstat (limited to 'linden/indra/newview/llappviewerlinux.cpp')
-rw-r--r--linden/indra/newview/llappviewerlinux.cpp414
1 files changed, 414 insertions, 0 deletions
diff --git a/linden/indra/newview/llappviewerlinux.cpp b/linden/indra/newview/llappviewerlinux.cpp
new file mode 100644
index 0000000..1993fd0
--- /dev/null
+++ b/linden/indra/newview/llappviewerlinux.cpp
@@ -0,0 +1,414 @@
1/**
2 * @file llappviewerlinux.cpp
3 * @brief The LLAppViewerWin32 class definitions
4 *
5 * $LicenseInfo:firstyear=2007&license=viewergpl$
6 *
7 * Copyright (c) 2007, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlife.com/developers/opensource/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlife.com/developers/opensource/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31
32#include "llviewerprecompiledheaders.h"
33
34#include "llmemtype.h"
35#include "llappviewerlinux.h"
36
37#include "llviewernetwork.h"
38#include "llmd5.h"
39
40 #if LL_LINUX
41 # include <dlfcn.h> // RTLD_LAZY
42 # include <execinfo.h> // backtrace - glibc only
43 # ifndef LL_ELFBIN
44 #define LL_ELFBIN 1
45 # endif // LL_ELFBIN
46 # if LL_ELFBIN
47 # include <cxxabi.h> // for symbol demangling
48 # include "ELFIO.h" // for better backtraces
49 # endif // LL_ELFBIN
50 #elif LL_SOLARIS
51 # include <sys/types.h>
52 # include <unistd.h>
53 # include <fcntl.h>
54 # include <ucontext.h>
55 #endif
56
57int main( int argc, char **argv )
58{
59 LLMemType mt1(LLMemType::MTYPE_STARTUP);
60
61#if LL_SOLARIS && defined(__sparc)
62 asm ("ta\t6"); // NOTE: Make sure memory alignment is enforced on SPARC
63#endif
64
65 LLAppViewer* viewer_app_ptr = new LLAppViewerLinux();
66
67 viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
68
69 bool ok = viewer_app_ptr->tempStoreCommandOptions(argc, argv);
70 if(!ok)
71 {
72 llwarns << "Unable to parse command line." << llendl;
73 return -1;
74 }
75
76 ok = viewer_app_ptr->init();
77 if(!ok)
78 {
79 llwarns << "Application init failed." << llendl;
80 return -1;
81 }
82
83 // Run the application main loop
84 if(!LLApp::isQuitting())
85 {
86 viewer_app_ptr->mainLoop();
87 }
88
89 if (!LLApp::isError())
90 {
91 //
92 // We don't want to do cleanup here if the error handler got called -
93 // the assumption is that the error handler is responsible for doing
94 // app cleanup if there was a problem.
95 //
96 viewer_app_ptr->cleanup();
97 }
98 delete viewer_app_ptr;
99 viewer_app_ptr = NULL;
100 return 0;
101}
102
103#ifdef LL_SOLARIS
104static inline BOOL do_basic_glibc_backtrace()
105{
106 BOOL success = FALSE;
107
108 std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
109 llinfos << "Opening stack trace file " << strace_filename << llendl;
110 FILE* StraceFile = LLFile::fopen(strace_filename.c_str(), "w");
111 if (!StraceFile)
112 {
113 llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
114 StraceFile = stderr;
115 }
116
117 printstack(fileno(StraceFile));
118
119 if (StraceFile != stderr)
120 fclose(StraceFile);
121
122 return success;
123}
124#else
125#define MAX_STACK_TRACE_DEPTH 40
126// This uses glibc's basic built-in stack-trace functions for a not very
127// amazing backtrace.
128static inline BOOL do_basic_glibc_backtrace()
129{
130 void *array[MAX_STACK_TRACE_DEPTH];
131 size_t size;
132 char **strings;
133 size_t i;
134 BOOL success = FALSE;
135
136 size = backtrace(array, MAX_STACK_TRACE_DEPTH);
137 strings = backtrace_symbols(array, size);
138
139 std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
140 llinfos << "Opening stack trace file " << strace_filename << llendl;
141 FILE* StraceFile = LLFile::fopen(strace_filename.c_str(), "w"); // Flawfinder: ignore
142 if (!StraceFile)
143 {
144 llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
145 StraceFile = stderr;
146 }
147
148 if (size)
149 {
150 for (i = 0; i < size; i++)
151 fputs((std::string(strings[i])+"\n").c_str(),
152 StraceFile);
153
154 success = TRUE;
155 }
156
157 if (StraceFile != stderr)
158 fclose(StraceFile);
159
160 free (strings);
161 return success;
162}
163
164#if LL_ELFBIN
165// This uses glibc's basic built-in stack-trace functions together with
166// ELFIO's ability to parse the .symtab ELF section for better symbol
167// extraction without exporting symbols (which'd cause subtle, fatal bugs).
168static inline BOOL do_elfio_glibc_backtrace()
169{
170 void *array[MAX_STACK_TRACE_DEPTH];
171 size_t btsize;
172 char **strings;
173 BOOL success = FALSE;
174
175 std::string appfilename = gDirUtilp->getExecutablePathAndName();
176
177 std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
178 llinfos << "Opening stack trace file " << strace_filename << llendl;
179 FILE* StraceFile = LLFile::fopen(strace_filename.c_str(), "w"); // Flawfinder: ignore
180 if (!StraceFile)
181 {
182 llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
183 StraceFile = stderr;
184 }
185
186 // get backtrace address list and basic symbol info
187 btsize = backtrace(array, MAX_STACK_TRACE_DEPTH);
188 strings = backtrace_symbols(array, btsize);
189
190 // create ELF reader for our app binary
191 IELFI* pReader;
192 const IELFISection* pSec = NULL;
193 IELFISymbolTable* pSymTbl = 0;
194 if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) ||
195 ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) ||
196 // find symbol table, create reader-object
197 NULL == (pSec = pReader->GetSection( ".symtab" )) ||
198 ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) )
199 {
200 // Failed to open our binary and read its symbol table somehow
201 llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl;
202 if (StraceFile != stderr)
203 fclose(StraceFile);
204 // note that we may be leaking some of the above ELFIO
205 // objects now, but it's expected that we'll be dead soon
206 // and we want to tread delicately until we get *some* kind
207 // of useful backtrace.
208 return do_basic_glibc_backtrace();
209 }
210
211 // iterate over trace and symtab, looking for plausible symbols
212 std::string name;
213 Elf32_Addr value;
214 Elf32_Word ssize;
215 unsigned char bind;
216 unsigned char type;
217 Elf32_Half section;
218 int nSymNo = pSymTbl->GetSymbolNum();
219 size_t btpos;
220 for (btpos = 0; btpos < btsize; ++btpos)
221 {
222 fprintf(StraceFile, "%d:\t", btpos);
223 int symidx;
224 for (symidx = 0; symidx < nSymNo; ++symidx)
225 {
226 if (ERR_ELFIO_NO_ERROR ==
227 pSymTbl->GetSymbol(symidx, name, value, ssize,
228 bind, type, section))
229 {
230 // check if trace address within symbol range
231 if (uintptr_t(array[btpos]) >= value &&
232 uintptr_t(array[btpos]) < value+ssize)
233 {
234 char *demangled_str = NULL;
235 int demangle_result = 1;
236 demangled_str =
237 abi::__cxa_demangle
238 (name.c_str(), NULL, NULL,
239 &demangle_result);
240 if (0 == demangle_result &&
241 NULL != demangled_str) {
242 fprintf(StraceFile,
243 "ELF(%s", demangled_str);
244 free(demangled_str);
245 }
246 else // failed demangle; print it raw
247 {
248 fprintf(StraceFile,
249 "ELF(%s", name.c_str());
250 }
251 // print offset from symbol start
252 fprintf(StraceFile,
253 "+0x%lx) [%p]\n",
254 uintptr_t(array[btpos]) -
255 value,
256 array[btpos]);
257 goto got_sym; // early escape
258 }
259 }
260 }
261 // Fallback:
262 // Didn't find a suitable symbol in the binary - it's probably
263 // a symbol in a DSO; use glibc's idea of what it should be.
264 fprintf(StraceFile, "%s\n", strings[btpos]);
265 got_sym:;
266 }
267
268 if (StraceFile != stderr)
269 fclose(StraceFile);
270
271 pSymTbl->Release();
272 pSec->Release();
273 pReader->Release();
274
275 free(strings);
276
277 llinfos << "Finished generating stack trace." << llendl;
278
279 success = TRUE;
280 return success;
281}
282#endif // LL_ELFBIN
283
284#endif // LL_SOLARIS
285
286
287LLAppViewerLinux::LLAppViewerLinux()
288{
289}
290
291LLAppViewerLinux::~LLAppViewerLinux()
292{
293}
294
295bool LLAppViewerLinux::init()
296{
297 return LLAppViewer::init();
298}
299
300void LLAppViewerLinux::handleCrashReporting()
301{
302
303 // Always generate the report, have the logger do the asking, and
304 // don't wait for the logger before exiting (-> total cleanup).
305 if (CRASH_BEHAVIOR_NEVER_SEND != LLAppViewer::instance()->getCrashBehavior())
306 {
307 // This backtrace writes into stack_trace.log
308# if LL_ELFBIN
309 do_elfio_glibc_backtrace(); // more useful backtrace
310# else
311 do_basic_glibc_backtrace(); // only slightly useful backtrace
312# endif // LL_ELFBIN
313 // launch the actual crash logger
314 char* ask_dialog = "-dialog";
315 if (CRASH_BEHAVIOR_ASK != LLAppViewer::instance()->getCrashBehavior())
316 ask_dialog = ""; // omit '-dialog' option
317 std::string cmd =gDirUtilp->getAppRODataDir();
318 cmd += gDirUtilp->getDirDelimiter();
319 cmd += "linux-crash-logger.bin";
320 char* const cmdargv[] =
321 {(char*)cmd.c_str(),
322 ask_dialog,
323 (char*)"-user",
324 (char*)gGridName,
325 (char*)"-name",
326 (char*)LLAppViewer::instance()->getSecondLifeTitle().c_str(),
327 NULL};
328 pid_t pid = fork();
329 if (pid == 0)
330 { // child
331 execv(cmd.c_str(), cmdargv); /* Flawfinder: ignore */
332 llwarns << "execv failure when trying to start " << cmd << llendl;
333 _exit(1); // avoid atexit()
334 }
335 else
336 {
337 if (pid > 0)
338 {
339 // DO NOT wait for child proc to die; we want
340 // the logger to outlive us while we quit to
341 // free up the screen/keyboard/etc.
342 ////int childExitStatus;
343 ////waitpid(pid, &childExitStatus, 0);
344 }
345 else
346 {
347 llwarns << "fork failure." << llendl;
348 }
349 }
350 }
351 // Sometimes signals don't seem to quit the viewer.
352 // Make sure we exit so as to not totally confuse the user.
353 exit(1);
354}
355
356bool LLAppViewerLinux::beingDebugged()
357{
358 static enum {unknown, no, yes} debugged = unknown;
359
360 if (debugged == unknown)
361 {
362 pid_t ppid = getppid();
363 char *name;
364 int ret;
365
366 ret = asprintf(&name, "/proc/%d/exe", ppid);
367 if (ret != -1)
368 {
369 char buf[1024];
370 ssize_t n;
371
372 n = readlink(name, buf, sizeof(buf) - 1);
373 if (n != -1)
374 {
375 char *base = strrchr(buf, '/');
376 buf[n + 1] = '\0';
377 if (base == NULL)
378 {
379 base = buf;
380 } else {
381 base += 1;
382 }
383
384 if (strcmp(base, "gdb") == 0)
385 {
386 debugged = yes;
387 }
388 }
389 free(name);
390 }
391 }
392
393 return debugged == yes;
394}
395
396bool LLAppViewerLinux::initLogging()
397{
398 // Remove the last stack trace, if any
399 std::string old_stack_file =
400 gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
401 LLFile::remove(old_stack_file.c_str());
402
403 return LLAppViewer::initLogging();
404}
405
406std::string LLAppViewerLinux::generateSerialNumber()
407{
408 char serial_md5[MD5HEX_STR_SIZE];
409 serial_md5[0] = 0;
410
411 // TODO
412
413 return serial_md5;
414}