diff options
Diffstat (limited to 'indra')
32 files changed, 1986 insertions, 2296 deletions
| diff --git a/indra/linux_crash_logger/linux_crash_logger.cpp b/indra/linux_crash_logger/linux_crash_logger.cpp index a49dfe1b2b..5310093f69 100644 --- a/indra/linux_crash_logger/linux_crash_logger.cpp +++ b/indra/linux_crash_logger/linux_crash_logger.cpp @@ -29,542 +29,16 @@   * $/LicenseInfo$   */ -#include "linden_common.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <curl/curl.h> - -#if LL_GTK -# include "gtk/gtk.h" -#endif // LL_GTK - -#include "indra_constants.h"	// CRASH_BEHAVIOR_ASK -#include "llerror.h" -#include "lltimer.h" -#include "lldir.h" - -#include "llstring.h" - - -// These need to be localized. -static const char dialog_text[] = -"Second Life appears to have crashed.\n" -"This crash reporter collects information about your computer's hardware, operating system, and some Second Life logs, which are used for debugging purposes only.\n" -"Sending crash reports is the best way to help us improve the quality of Second Life.\n" -"If you continue to experience this problem, please try:\n" -"- Contacting support by visiting http://www.secondlife.com/support\n" -"\n" -"Send crash report?"; - -static const char dialog_title[] = -"Second Life Crash Logger"; - - -class LLFileEncoder -{ -public: -	LLFileEncoder(const char *formname, const char *filename, bool isCrashLog = false); - -	BOOL isValid() const { return mIsValid; } -	LLString encodeURL(const S32 max_length = 0); -public: -	BOOL mIsValid; -	LLString mFilename; -	LLString mFormname; -	LLString mBuf; -}; - -LLString encode_string(const char *formname, const LLString &str); - -LLString gServerResponse; -BOOL gSendReport = FALSE; -LLString gUserserver; -LLString gUserText; -BOOL gCrashInPreviousExec = FALSE; -time_t gLaunchTime; - -static size_t curl_download_callback(void *data, size_t size, size_t nmemb, -				     void *user_data) -{ -	S32 bytes = size * nmemb; -	char *cdata = (char *) data; -	for (int i =0; i < bytes; i += 1) -	{ -		gServerResponse += (cdata[i]); -	} -	return bytes; -} - -#if LL_GTK -static void response_callback (GtkDialog *dialog, -			       gint       arg1, -			       gpointer   user_data) -{ -	gint *response = (gint*)user_data; -	*response = arg1; -	gtk_widget_destroy(GTK_WIDGET(dialog)); -	gtk_main_quit(); -} -#endif // LL_GTK - -static BOOL do_ask_dialog(void) -{ -#if LL_GTK -	gtk_disable_setlocale(); -	if (!gtk_init_check(NULL, NULL)) { -		llinfos << "Could not initialize GTK for 'ask to send crash report' dialog; not sending report." << llendl; -		return FALSE; -	} -	 -	GtkWidget *win = NULL; -	GtkDialogFlags flags = GTK_DIALOG_MODAL; -	GtkMessageType messagetype = GTK_MESSAGE_QUESTION; -	GtkButtonsType buttons = GTK_BUTTONS_YES_NO; -	gint response = GTK_RESPONSE_NONE; - -	win = gtk_message_dialog_new(NULL, -				     flags, messagetype, buttons, -				     dialog_text); -	gtk_window_set_type_hint(GTK_WINDOW(win), -				 GDK_WINDOW_TYPE_HINT_DIALOG); -	gtk_window_set_title(GTK_WINDOW(win), dialog_title); -	g_signal_connect (win, -			  "response",  -			  G_CALLBACK (response_callback), -			  &response); -	gtk_widget_show_all (win); -	gtk_main(); - -	return (GTK_RESPONSE_OK == response || -		GTK_RESPONSE_YES == response || -		GTK_RESPONSE_APPLY == response); -#else -	return FALSE; -#endif // LL_GTK -} - +#include "llcrashloggerlinux.h"  int main(int argc, char **argv)  { -	const S32 BT_MAX_SIZE = 100000;			// Maximum size to transmit of the backtrace file -	const S32 SL_MAX_SIZE = 100000;			// Maximum size of the Second Life log file. -	int i; -	S32 crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND; -	 -	time(&gLaunchTime); -	 -	llinfos << "Starting Second Life Viewer Crash Reporter" << llendl; -	 -	for(i=1; i<argc; i++) -	{ -		if(!strcmp(argv[i], "-dialog")) -		{ -			llinfos << "Show the user dialog" << llendl; -			crash_behavior = CRASH_BEHAVIOR_ASK; -		} -		if(!strcmp(argv[i], "-previous")) -		{ -			gCrashInPreviousExec = TRUE; -		} -		if(!strcmp(argv[i], "-user")) -		{ -			if ((i + 1) < argc) -			{ -				i++; -				gUserserver = argv[i]; -				llinfos << "Got userserver " << gUserserver << llendl; -			} -		} -	} -	 -	if( gCrashInPreviousExec ) -	{ -		llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl; -	} -	 -	if(!gCrashInPreviousExec) -	{ -		// Wait a while to let the crashed client finish exiting, -		// freeing up the screen/etc. -		sleep(5); -	} - -	// *FIX: do some dialog stuff here? -	if (CRASH_BEHAVIOR_ALWAYS_SEND == crash_behavior) -	{ -		gSendReport = TRUE; -	} -	else if (CRASH_BEHAVIOR_ASK == crash_behavior) -	{ -		gSendReport = do_ask_dialog(); -	} -	 -	if(!gSendReport) -	{ -		// Only send the report if the user agreed to it. -		llinfos << "User cancelled, not sending report" << llendl; - -		return(0); -	} - -	// We assume that all the logs we're looking for reside on the current drive -	gDirUtilp->initAppDirs("SecondLife"); - -	// Lots of silly variable, replicated for each log file. -	LLString db_file_name; -	LLString sl_file_name; -	LLString bt_file_name; // stack_trace.log file -	LLString st_file_name; // stats.log file -	LLString si_file_name; // settings.xml file - -	LLFileEncoder *db_filep = NULL; -	LLFileEncoder *sl_filep = NULL; -	LLFileEncoder *st_filep = NULL; -	LLFileEncoder *bt_filep = NULL; -	LLFileEncoder *si_filep = NULL; - -	/////////////////////////////////// -	// -	// We do the parsing for the debug_info file first, as that will -	// give us the location of the SecondLife.log file. -	// - -	// Figure out the filename of the debug log -	db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log").c_str(); -	db_filep = new LLFileEncoder("DB", db_file_name.c_str()); - -	// Get the filename of the SecondLife.log file -	// *NOTE: These buffer sizes are hardcoded into a scanf() below. -	char tmp_sl_name[LL_MAX_PATH]; -	tmp_sl_name[0] = '\0'; -	char tmp_space[256]; -	tmp_space[0] = '\0'; - -	// Look for it in the debug_info.log file -	if (db_filep->isValid()) -	{ -		// This was originally scanning for "SL Log: %[^\r\n]", which happily skipped to the next line -		// on debug logs (which don't have anything after "SL Log:" and tried to open a nonsensical filename. -		sscanf(db_filep->mBuf.c_str(), "SL Log:%255[ ]%1023[^\r\n]", tmp_space, tmp_sl_name); -	} -	else -	{ -		delete db_filep; -		db_filep = NULL; -	} - -	// If we actually have a legitimate file name, use it. -	if (gCrashInPreviousExec) -	{ -		// If we froze, the crash log this time around isn't useful. -		// Use the old one. -		sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); -	} -	else if (tmp_sl_name[0]) -	{ -		sl_file_name = tmp_sl_name; -		llinfos << "Using log file from debug log: " << sl_file_name << llendl; -	} -	else -	{ -		// Figure out the filename of the second life log -		sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log").c_str(); -	} - -	// Now we get the SecondLife.log file if it's there, and recent enough... -	sl_filep = new LLFileEncoder("SL", sl_file_name.c_str()); -	if (!sl_filep->isValid()) -	{ -		delete sl_filep; -		sl_filep = NULL; -	} - -	st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log").c_str(); -	st_filep = new LLFileEncoder("ST", st_file_name.c_str()); -	if (!st_filep->isValid()) -	{ -		delete st_filep; -		st_filep = NULL; -	} - -	si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml").c_str(); -	si_filep = new LLFileEncoder("SI", si_file_name.c_str()); -	if (!si_filep->isValid()) -	{ -		delete si_filep; -		si_filep = NULL; -	} - -	// encode this as if it were a 'Dr Watson' plain-text backtrace -	bt_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log").c_str(); -	bt_filep = new LLFileEncoder("DW", bt_file_name.c_str()); -	if (!bt_filep->isValid()) -	{ -		delete bt_filep; -		bt_filep = NULL; -	} - -	LLString post_data; -	LLString tmp_url_buf; - -	// Append the userserver -	tmp_url_buf = encode_string("USER", gUserserver); -	post_data += tmp_url_buf; -	llinfos << "PostData:" << post_data << llendl; - -	if (gCrashInPreviousExec) -	{ -		post_data.append("&"); -		tmp_url_buf = encode_string("EF", "Y"); -		post_data += tmp_url_buf; -	} - -	if (db_filep) -	{ -		post_data.append("&"); -		tmp_url_buf = db_filep->encodeURL(); -		post_data += tmp_url_buf; -		llinfos << "Sending DB log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending DB log file" << llendl; -	} - -	if (sl_filep) -	{ -		post_data.append("&"); -		tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE); -		post_data += tmp_url_buf; -		llinfos << "Sending SL log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending SL log file" << llendl; -	} - -	if (st_filep) -	{ -		post_data.append("&"); -		tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE); -		post_data += tmp_url_buf; -		llinfos << "Sending stats log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending stats log file" << llendl; -	} - -	if (bt_filep) -	{ -		post_data.append("&"); -		tmp_url_buf = bt_filep->encodeURL(BT_MAX_SIZE); -		post_data += tmp_url_buf; -		llinfos << "Sending crash log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending crash log file" << llendl; -	} - -	if (si_filep) -	{ -		post_data.append("&"); -		tmp_url_buf = si_filep->encodeURL(); -		post_data += tmp_url_buf; -		llinfos << "Sending settings log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending settings.xml file" << llendl; -	} - -	if (gUserText.size()) -	{ -		post_data.append("&"); -		tmp_url_buf = encode_string("UN", gUserText); -		post_data += tmp_url_buf; -	} - -	delete db_filep; -	db_filep = NULL; -	delete sl_filep; -	sl_filep = NULL; -	delete bt_filep; -	bt_filep = NULL; - -	// Debugging spam -#if 0 -	printf("Crash report post data:\n--------\n"); -	printf("%s", post_data.getString()); -	printf("\n--------\n"); -#endif -	 -	// Send the report.  Yes, it's this easy. -	{ -		CURL *curl = curl_easy_init(); - -		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); -		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback); -		curl_easy_setopt(curl, CURLOPT_POST, 1);  -		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str());  -		curl_easy_setopt(curl, CURLOPT_URL,	"http://secondlife.com/cgi-bin/viewer_crash_reporter2"); -		 -		llinfos << "Connecting to crash report server" << llendl; -		CURLcode result = curl_easy_perform(curl); -		 -		curl_easy_cleanup(curl); -		 -		if(result != CURLE_OK) -		{ -			llinfos << "Couldn't talk to crash report server" << llendl; -		} -		else -		{ -			llinfos << "Response from crash report server:" << llendl; -			llinfos << gServerResponse << llendl;			 -		} -	} -	 +	LLCrashLoggerLinux app; +	app.parseCommandOptions(argc, argv); +	app.init(); +	app.mainLoop(); +	app.cleanup();  	return 0;  } -LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename, bool isCrashLog) -{ -	mFormname = form_name; -	mFilename = filename; -	mIsValid = FALSE; - -	int res; -	 -	struct stat stat_data; -	res = stat(mFilename.c_str(), &stat_data); -	if (res) -	{ -		llwarns << "File " << mFilename << " is missing!" << llendl; -		return; -	} -	else -	{ -		// Debugging spam -//		llinfos << "File " << mFilename << " is present..." << llendl; - -		if(!gCrashInPreviousExec && isCrashLog) -		{ -			// Make sure the file isn't too old. -			double age = difftime(gLaunchTime, stat_data.st_mtim.tv_sec); - -//			llinfos << "age is " << age << llendl; -			if(age > 60.0) -			{ -				// The file was last modified more than 60 seconds before the crash reporter was launched.  Assume it's stale. -				llwarns << "File " << mFilename << " is too old!" << llendl; -				return; -			} -		} - -	} - -	S32 buf_size = stat_data.st_size; -	FILE *fp = fopen(mFilename.c_str(), "rb"); -	U8 *buf = new U8[buf_size + 1]; -	size_t nread = fread(buf, 1, buf_size, fp); -	fclose(fp); -	buf[nread] = 0; - -	mBuf = (char *)buf; -	 -	if(isCrashLog) -	{ -		// Crash logs consist of a number of entries, one per crash. -		// Each entry is preceeded by "**********" on a line by itself. -		// We want only the most recent (i.e. last) one. -		const char *sep = "**********"; -		const char *start = mBuf.c_str(); -		const char *cur = start; -		const char *temp = strstr(cur, sep); -		 -		while(temp != NULL) -		{ -			// Skip past the marker we just found -			cur = temp + strlen(sep); -			 -			// and try to find another -			temp = strstr(cur, sep); -		} -		 -		// If there's more than one entry in the log file, strip all but the last one. -		if(cur != start) -		{ -			mBuf.erase(0, cur - start); -		} -	} - -	mIsValid = TRUE; -	delete[] buf; -} - -LLString LLFileEncoder::encodeURL(const S32 max_length) -{ -	LLString result = mFormname; -	result.append("="); - -	S32 i = 0; - -	if (max_length) -	{ -		if ((S32)mBuf.size() > max_length) -		{ -			i = mBuf.size() - max_length; -		} -	} - -#if 0 -	// Plain text version for debugging -	result.append(mBuf); -#else -	// Not using LLString because of bad performance issues -	S32 buf_size = mBuf.size(); -	S32 url_buf_size = 3*mBuf.size() + 1; -	char *url_buf = new char[url_buf_size]; - -	S32 cur_pos = 0; -	for (; i < buf_size; i++) -	{ -		sprintf(url_buf + cur_pos, "%%%02x", mBuf[i]); -		cur_pos += 3; -	} -	url_buf[i*3] = 0; - -	result.append(url_buf); -	delete[] url_buf; -#endif -	return result; -} - -LLString encode_string(const char *formname, const LLString &str) -{ -	LLString result = formname; -	result.append("="); -	// Not using LLString because of bad performance issues -	S32 buf_size = str.size(); -	S32 url_buf_size = 3*str.size() + 1; -	char *url_buf = new char[url_buf_size]; - -	S32 cur_pos = 0; -	S32 i; -	for (i = 0; i < buf_size; i++) -	{ -		sprintf(url_buf + cur_pos, "%%%02x", str[i]); -		cur_pos += 3; -	} -	url_buf[i*3] = 0; - -	result.append(url_buf); -	delete[] url_buf; -	return result; -} diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp new file mode 100644 index 0000000000..26a8f0cb2a --- /dev/null +++ b/indra/linux_crash_logger/llcrashloggerlinux.cpp @@ -0,0 +1,140 @@ +/**  + * @file llcrashloggerlinux.cpp + * @brief Linux crash logger implementation + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + *  + * Copyright (c) 2003-2007, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llcrashloggerlinux.h" + +#include <iostream> + +#include "linden_common.h" + +#include "boost/tokenizer.hpp" + +#include "indra_constants.h"	// CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME +#include "llerror.h" +#include "llfile.h" +#include "lltimer.h" +#include "llstring.h" +#include "lldir.h" +#include "llsdserialize.h" + +#if LL_GTK +# include "gtk/gtk.h" +#endif // LL_GTK + +#define MAX_LOADSTRING 100 + +// These need to be localized. +static const char dialog_text[] = +"Second Life appears to have crashed or frozen last time it ran.\n" +"This crash reporter collects information about your computer's hardware, operating system, and some Second Life logs, all of which are used for debugging purposes only.\n" +"In the space below, please briefly describe what you were doing or trying to do just prior to the crash. Thank you for your help!\n" +"This report is NOT read by Customer Support. If you have billing or other questions, contact support by visiting http://www.secondlife.com/support\n" +"\n" +"Send crash report?"; + +static const char dialog_title[] = +"Second Life Crash Logger"; + +#if LL_GTK +static void response_callback (GtkDialog *dialog, +			       gint       arg1, +			       gpointer   user_data) +{ +	gint *response = (gint*)user_data; +	*response = arg1; +	gtk_widget_destroy(GTK_WIDGET(dialog)); +	gtk_main_quit(); +} +#endif // LL_GTK + +static BOOL do_ask_dialog(void) +{ +#if LL_GTK +	gtk_disable_setlocale(); +	if (!gtk_init_check(NULL, NULL)) { +		llinfos << "Could not initialize GTK for 'ask to send crash report' dialog; not sending report." << llendl; +		return FALSE; +	} +	 +	GtkWidget *win = NULL; +	GtkDialogFlags flags = GTK_DIALOG_MODAL; +	GtkMessageType messagetype = GTK_MESSAGE_QUESTION; +	GtkButtonsType buttons = GTK_BUTTONS_YES_NO; +	gint response = GTK_RESPONSE_NONE; + +	win = gtk_message_dialog_new(NULL, +				     flags, messagetype, buttons, +				     dialog_text); +	gtk_window_set_type_hint(GTK_WINDOW(win), +				 GDK_WINDOW_TYPE_HINT_DIALOG); +	gtk_window_set_title(GTK_WINDOW(win), dialog_title); +	g_signal_connect (win, +			  "response",  +			  G_CALLBACK (response_callback), +			  &response); +	gtk_widget_show_all (win); +	gtk_main(); + +	return (GTK_RESPONSE_OK == response || +		GTK_RESPONSE_YES == response || +		GTK_RESPONSE_APPLY == response); +#else +	return FALSE; +#endif // LL_GTK +} + +LLCrashLoggerLinux::LLCrashLoggerLinux(void) +{ +} + +LLCrashLoggerLinux::~LLCrashLoggerLinux(void) +{ +} + +void LLCrashLoggerLinux::gatherPlatformSpecificFiles() +{ +	mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log").c_str(); +} + +bool LLCrashLoggerLinux::mainLoop() +{ +	if(!do_ask_dialog()) +	{ +		return true; +	} +	sendCrashLogs(); +	return true; +} + +void LLCrashLoggerLinux::updateApplication(LLString message) +{ +	LLCrashLogger::updateApplication(message); +} diff --git a/indra/linux_crash_logger/llcrashloggerlinux.h b/indra/linux_crash_logger/llcrashloggerlinux.h new file mode 100644 index 0000000000..a84ee00e1c --- /dev/null +++ b/indra/linux_crash_logger/llcrashloggerlinux.h @@ -0,0 +1,49 @@ +/**  + * @file llcrashloggerlinux.h + * @brief Linux crash logger definition + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + *  + * Copyright (c) 2003-2007, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLCRASHLOGGERLINUX_H +#define LLCRASHLOGGERLINUX_H + +#include "linden_common.h" +#include "llcrashlogger.h" +#include "llstring.h" + +class LLCrashLoggerLinux : public LLCrashLogger +{ +public: +	LLCrashLoggerLinux(void); +	~LLCrashLoggerLinux(void); +	virtual bool mainLoop(); +	virtual void updateApplication(LLString message = ""); +	virtual void gatherPlatformSpecificFiles(); +}; + +#endif diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp new file mode 100755 index 0000000000..cec2b2e2e9 --- /dev/null +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -0,0 +1,309 @@ +/** 
 +* @file llcrashlogger.cpp
 +* @brief Crash logger implementation
 +*
 +* $LicenseInfo:firstyear=2003&license=viewergpl$
 +* 
 +* Copyright (c) 2003-2007, Linden Research, Inc.
 +* 
 +* Second Life Viewer Source Code
 +* The source code in this file ("Source Code") is provided by Linden Lab
 +* to you under the terms of the GNU General Public License, version 2.0
 +* ("GPL"), unless you have obtained a separate licensing agreement
 +* ("Other License"), formally executed by you and Linden Lab.  Terms of
 +* the GPL can be found in doc/GPL-license.txt in this distribution, or
 +* online at http://secondlife.com/developers/opensource/gplv2
 +* 
 +* There are special exceptions to the terms and conditions of the GPL as
 +* it is applied to this Source Code. View the full text of the exception
 +* in the file doc/FLOSS-exception.txt in this software distribution, or
 +* online at http://secondlife.com/developers/opensource/flossexception
 +* 
 +* By copying, modifying or distributing this software, you acknowledge
 +* that you have read and understood your obligations described above,
 +* and agree to abide by those obligations.
 +* 
 +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 +* COMPLETENESS OR PERFORMANCE.
 +* $/LicenseInfo$
 +*/
 +#include <cstdio>
 +#include <cstdlib>
 +#include <sstream>
 +#include <map>
 +
 +#include "llcrashlogger.h"
 +#include "linden_common.h"
 +#include "llstring.h"
 +#include "indra_constants.h"	// CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
 +#include "llerror.h"
 +#include "lltimer.h"
 +#include "lldir.h"
 +#include "llsdserialize.h"
 +#include "lliopipe.h"
 +#include "llpumpio.h"
 +#include "llhttpclient.h"
 +#include "llsdserialize.h"
 +
 +LLPumpIO* gServicePump;
 +BOOL gBreak = false;
 +BOOL gSent = false;
 +
 +class LLCrashLoggerResponder : public LLHTTPClient::Responder
 +{
 +public:
 +	LLCrashLoggerResponder() 
 +	{
 +	}
 +
 +	virtual void error(U32 status, const std::string& reason)
 +	{
 +		gBreak = true;		
 +	}
 +
 +	virtual void result(const LLSD& content)
 +	{	
 +		gBreak = true;
 +		gSent = true;
 +	}
 +};
 +
 +bool LLCrashLoggerText::mainLoop()
 +{
 +	std::cout << "Entering main loop" << std::endl;
 +	sendCrashLogs();
 +	return true;	
 +}
 +
 +void LLCrashLoggerText::updateApplication(LLString message)
 +{
 +	LLCrashLogger::updateApplication(message);
 +	std::cout << message << std::endl;
 +}
 +
 +LLCrashLogger::LLCrashLogger() :
 +mSentCrashLogs(false)
 +{
 +
 +}
 +
 +LLCrashLogger::~LLCrashLogger()
 +{
 +
 +}
 +
 +void LLCrashLogger::gatherFiles()
 +{
 +
 +	/*
 +	//TODO:This function needs to be reimplemented somewhere in here...
 +	if(!previous_crash && is_crash_log)
 +	{
 +		// Make sure the file isn't too old.
 +		double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec);
 +		
 +		//			llinfos << "age is " << age << llendl;
 +		
 +		if(age > 60.0)
 +		{
 +				// The file was last modified more than 60 seconds before the crash reporter was launched.  Assume it's stale.
 +			llwarns << "File " << mFilename << " is too old!" << llendl;
 +			return;
 +		}
 +	}
 +	*/
 +
 +	updateApplication("Gathering logs...");
 +
 +	// Figure out the filename of the debug log
 +	LLString db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log").c_str();
 +	std::ifstream debug_log_file(db_file_name.c_str());
 +
 +	// Look for it in the debug_info.log file
 +	if (debug_log_file.is_open())
 +	{		
 +		LLSDSerialize::fromXML(mDebugLog, debug_log_file);
 +		mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString();
 +		mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
 +		LLHTTPClient::setCABundle(mDebugLog["CAFilename"].asString());
 +		llinfos << "Using log file from debug log " << mFileMap["SecondLifeLog"] << llendl;
 +		llinfos << "Using settings file from debug log " << mFileMap["SettingsXml"] << llendl;
 +	}
 +	else
 +	{
 +		// Figure out the filename of the second life log
 +		LLHTTPClient::setCABundle(gDirUtilp->getCAFile());
 +		mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
 +		mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
 +	}
 +
 +	gatherPlatformSpecificFiles();
 +
 +	//Use the debug log to reconstruct the URL to send the crash report to
 +	mCrashHost = "https://";
 +	mCrashHost += mDebugLog["CurrentSimHost"].asString();
 +	mCrashHost += ":12043/crash/report";
 +	mAltCrashHost = "https://";
 +	mAltCrashHost += mDebugLog["GridUtilHost"].asString();
 +	mAltCrashHost += ":12043/crash/report";
 +
 +	mCrashInfo["DebugLog"] = mDebugLog;
 +	mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log");
 +	mFileMap["StackTrace"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
 +	
 +	updateApplication("Encoding files...");
 +
 +	for(std::map<LLString, LLString>::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr)
 +	{
 +		std::ifstream f((*itr).second.c_str());
 +		if(!f.is_open())
 +		{
 +			std::cout << "Can't find file " << (*itr).second.c_str() << std::endl;
 +			continue;
 +		}
 +		std::stringstream s;
 +		s << f.rdbuf();
 +		mCrashInfo[(*itr).first] = s.str();
 +	}
 +}
 +
 +LLSD LLCrashLogger::constructPostData()
 +{
 +	LLSD ret;
 +
 +	if(mCrashInPreviousExec)
 +	{
 +		mCrashInfo["CrashInPreviousExecution"] = "Y";
 +	}
 +
 +	return mCrashInfo;
 +}
 +
 +S32 LLCrashLogger::loadCrashBehaviorSetting()
 +{
 +	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
 +
 +	mCrashSettings.loadFromFile(filename);
 +		
 +	S32 value = mCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
 +	
 +	if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK;
 +
 +	return value;
 +}
 +
 +bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior)
 +{
 +	if (crash_behavior < CRASH_BEHAVIOR_ASK) return false;
 +	if (crash_behavior > CRASH_BEHAVIOR_NEVER_SEND) return false;
 +
 +	mCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior);
 +	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
 +
 +	mCrashSettings.saveToFile(filename, FALSE);
 +
 +	return true;
 +}
 +
 +bool LLCrashLogger::sendCrashLogs()
 +{
 +	gatherFiles();
 +
 +	LLSD post_data;
 +	post_data = constructPostData();
 +
 +	updateApplication("Sending reports...");
 +
 +	std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
 +															   "SecondLifeCrashReport");
 +	std::string report_file = dump_path + ".log";
 +
 +	std::ofstream out_file(report_file.c_str());
 +	LLSDSerialize::toPrettyXML(post_data, out_file);
 +	out_file.close();
 +	LLHTTPClient::post(mCrashHost, post_data, new LLCrashLoggerResponder(), 5);
 +
 +	gBreak = false;
 +	while(!gBreak)
 +	{
 +		updateApplication("Sending logs...");
 +	}
 +
 +	if(!gSent)
 +	{
 +		gBreak = false;
 +		LLHTTPClient::post(mAltCrashHost, post_data, new LLCrashLoggerResponder(), 5);
 +
 +		while(!gBreak)
 +		{
 +			updateApplication("Sending logs to Alternate Server...");
 +		}
 +	}
 +	mSentCrashLogs = gSent;
 +
 +	return true;
 +}
 +
 +void LLCrashLogger::updateApplication(LLString message)
 +{
 +	gServicePump->pump();
 +    gServicePump->callback();
 +}
 +
 +bool LLCrashLogger::init()
 +{
 +	// We assume that all the logs we're looking for reside on the current drive
 +	gDirUtilp->initAppDirs("SecondLife");
 +
 +	// Default to the product name "Second Life" (this is overridden by the -name argument)
 +	mProductName = "Second Life";
 +	
 +	mCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes "
 +		"(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)");
 +
 +	llinfos << "Loading crash behavior setting" << llendl;
 +	mCrashBehavior = loadCrashBehaviorSetting();
 +
 +	//Run through command line options
 +	if(getOption("previous").isDefined())
 +	{
 +		llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl;
 +		mCrashInPreviousExec = TRUE;
 +	}
 +
 +	if(getOption("dialog").isDefined())
 +	{
 +		llinfos << "Show the user dialog" << llendl;
 +		mCrashBehavior = CRASH_BEHAVIOR_ASK;
 +	}
 +
 +	LLSD server = getOption("user");
 +	if(server.isDefined())
 +	{
 +		mGridName = server.asString();
 +		llinfos << "Got userserver " << mGridName << llendl;
 +	}
 +	else
 +	{
 +		mGridName = "agni";
 +	}
 +
 +	LLSD name = getOption("name");
 +	if(name.isDefined())
 +	{	
 +		mProductName = name.asString();
 +	}
 +
 +	// If user doesn't want to send, bail out
 +	if (mCrashBehavior == CRASH_BEHAVIOR_NEVER_SEND)
 +	{
 +		llinfos << "Crash behavior is never_send, quitting" << llendl;
 +		return false;
 +	}
 +
 +	gServicePump = new LLPumpIO(gAPRPoolp);
 +	gServicePump->prime(gAPRPoolp);
 +	LLHTTPClient::setPump(*gServicePump);
 +	return true;
 +}
 diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h new file mode 100755 index 0000000000..d3218ab81c --- /dev/null +++ b/indra/llcrashlogger/llcrashlogger.h @@ -0,0 +1,85 @@ +/** 
 +* @file llcrashlogger.h
 +* @brief Crash Logger Definition
 +*
 +* $LicenseInfo:firstyear=2003&license=viewergpl$
 +* 
 +* Copyright (c) 2003-2007, Linden Research, Inc.
 +* 
 +* Second Life Viewer Source Code
 +* The source code in this file ("Source Code") is provided by Linden Lab
 +* to you under the terms of the GNU General Public License, version 2.0
 +* ("GPL"), unless you have obtained a separate licensing agreement
 +* ("Other License"), formally executed by you and Linden Lab.  Terms of
 +* the GPL can be found in doc/GPL-license.txt in this distribution, or
 +* online at http://secondlife.com/developers/opensource/gplv2
 +* 
 +* There are special exceptions to the terms and conditions of the GPL as
 +* it is applied to this Source Code. View the full text of the exception
 +* in the file doc/FLOSS-exception.txt in this software distribution, or
 +* online at http://secondlife.com/developers/opensource/flossexception
 +* 
 +* By copying, modifying or distributing this software, you acknowledge
 +* that you have read and understood your obligations described above,
 +* and agree to abide by those obligations.
 +* 
 +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 +* COMPLETENESS OR PERFORMANCE.
 +* $/LicenseInfo$
 +*/
 +#ifndef LLCRASHLOGGER_H
 +#define LLCRASHLOGGER_H
 +
 +#include <vector>
 +
 +#include "linden_common.h"
 +
 +#include "llapp.h"
 +#include "llsd.h"
 +#include "llcontrol.h"
 +
 +class LLCrashLogger : public LLApp
 +{
 +public:
 +	LLCrashLogger();
 +	virtual ~LLCrashLogger();
 +	S32 loadCrashBehaviorSetting();
 +	void gatherFiles();
 +	virtual void gatherPlatformSpecificFiles() {}
 +	bool saveCrashBehaviorSetting(S32 crash_behavior);
 +	bool sendCrashLogs();
 +	LLSD constructPostData();
 +	virtual void updateApplication(LLString message = "");
 +	virtual bool init();
 +	virtual bool mainLoop() = 0;
 +	virtual bool cleanup() { return true; }
 +	void setUserText(LLString& text) { mCrashInfo["UserNotes"] = text; }
 +	S32 getCrashBehavior() { return mCrashBehavior; }
 +protected:
 +	S32 mCrashBehavior;
 +	BOOL mCrashInPreviousExec;
 +	std::map<LLString, LLString> mFileMap;
 +	static const int mMaxSendSize = 200000;
 +	LLString mGridName;
 +	LLControlGroup mCrashSettings;
 +	LLString mProductName;
 +	LLSD mCrashInfo;
 +	LLString mCrashHost;
 +	LLString mAltCrashHost;
 +	LLSD mDebugLog;
 +	bool mSentCrashLogs;
 +};
 +
 +class LLCrashLoggerText : public LLCrashLogger
 +{
 +public:
 +	LLCrashLoggerText(void) {}
 +	~LLCrashLoggerText(void) {}
 +
 +	virtual bool mainLoop();
 +	virtual void updateApplication(LLString message = "");
 +};
 +
 +
 +#endif //LLCRASHLOGGER_H
 diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index 1d1be56349..0db9f8e2f1 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -1170,13 +1170,11 @@ std::ostream& operator<<(std::ostream& s, LLCircuitData& circuit)  	return s;  } -const LLString LLCircuitData::getInfoString() const +void LLCircuitData::getInfo(LLSD& info) const  { -	std::ostringstream info; -	info << "Circuit: " << mHost << std::endl -		 << (mbAlive ? "Alive" : "Not Alive") << std::endl -		 << "Age: " << mExistenceTimer.getElapsedTimeF32() << std::endl; -	return LLString(info.str()); +	info["Host"] = mHost.getIPandPort(); +	info["Alive"] = mbAlive; +	info["Age"] = mExistenceTimer.getElapsedTimeF32();  }  void LLCircuitData::dumpResendCountAndReset() @@ -1200,17 +1198,16 @@ std::ostream& operator<<(std::ostream& s, LLCircuit &circuit)  	return s;  } -const LLString LLCircuit::getInfoString() const +void LLCircuit::getInfo(LLSD& info) const  { -	std::ostringstream info; -	info << "Circuit Info:" << std::endl;  	LLCircuit::circuit_data_map::const_iterator end = mCircuitData.end();  	LLCircuit::circuit_data_map::const_iterator it; +	LLSD circuit_info;  	for(it = mCircuitData.begin(); it != end; ++it)  	{ -		info << (*it).second->getInfoString() << std::endl; +		(*it).second->getInfo(circuit_info); +		info["Circuits"].append(circuit_info);  	} -	return LLString(info.str());  }  void LLCircuit::getCircuitRange( diff --git a/indra/llmessage/llcircuit.h b/indra/llmessage/llcircuit.h index 128b1bc222..1a6611f5d4 100644 --- a/indra/llmessage/llcircuit.h +++ b/indra/llmessage/llcircuit.h @@ -75,6 +75,7 @@ const S32 LL_MAX_ACKED_PACKETS_PER_FRAME = 200;  //  class LLMessageSystem;  class LLEncodedDatagramService; +class LLSD;  //  // Classes @@ -158,7 +159,7 @@ public:  	//  	void					checkPeriodTime();		// Reset per-period counters if necessary.  	friend std::ostream&	operator<<(std::ostream& s, LLCircuitData &circuit); -	const LLString getInfoString() const; +	void getInfo(LLSD& info) const;  	friend class LLCircuit;  	friend class LLMessageSystem; @@ -304,7 +305,7 @@ public:  	void sendAcks();  	friend std::ostream& operator<<(std::ostream& s, LLCircuit &circuit); -	const LLString getInfoString() const; +	void getInfo(LLSD& info) const;  	void			dumpResends(); diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index e2cd19b264..d446730c33 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -1562,12 +1562,9 @@ U32 LLMessageSystem::getOurCircuitCode()  	return mOurCircuitCode;  } -LLString LLMessageSystem::getCircuitInfoString() +void LLMessageSystem::getCircuitInfo(LLSD& info) const  { -	LLString info_string; - -	info_string += mCircuitInfo.getInfoString(); -	return info_string; +	mCircuitInfo.getInfo(info);  }  // returns whether the given host is on a trusted circuit diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 4454b40ab9..3381ece222 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -529,7 +529,7 @@ public:  	bool isMatchingDigestForWindow(const char* digest, const S32 window) const;  	void	showCircuitInfo(); -	LLString getCircuitInfoString(); +	void getCircuitInfo(LLSD& info) const;  	U32 getOurCircuitCode(); diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index b5db6efb4d..f415fe56ed 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -42,7 +42,6 @@  #include <errno.h>  #include <sys/types.h>  #include <sys/stat.h> -#include <errno.h>  // Utility stuff to get versions of the sh  #define PACKVERSION(major,minor) MAKELONG(minor,major) diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index 1a39e68e3c..2aff05232e 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -411,6 +411,7 @@ BOOL LLDXHardware::getInfo(BOOL vram_only)  			}  			std::string device_name = get_string(device_containerp, L"szDescription"); +  			std::string device_id = get_string(device_containerp, L"szDeviceID");  			LLDXDevice *dxdevicep = new LLDXDevice; @@ -451,6 +452,8 @@ BOOL LLDXHardware::getInfo(BOOL vram_only)  			} + +  			// Now, iterate through the related drivers  			hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp);  			if (FAILED(hr) || !driver_containerp) @@ -468,6 +471,7 @@ BOOL LLDXHardware::getInfo(BOOL vram_only)  			S32 file_num = 0;  			for (file_num = 0; file_num < (S32)num_files; file_num++ )  			{ +  				hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256);  				if (FAILED(hr))  				{ @@ -522,6 +526,104 @@ LCleanup:      return ok;  } +LLSD LLDXHardware::getDisplayInfo() +{ +	LLTimer hw_timer; +    HRESULT       hr; +	LLSD ret; +    CoInitialize(NULL); + +    IDxDiagProvider *dx_diag_providerp = NULL; +    IDxDiagContainer *dx_diag_rootp = NULL; +	IDxDiagContainer *devices_containerp = NULL; +	IDxDiagContainer *device_containerp = NULL; +	IDxDiagContainer *file_containerp = NULL; +	IDxDiagContainer *driver_containerp = NULL; + +    // CoCreate a IDxDiagProvider* +	llinfos << "CoCreateInstance IID_IDxDiagProvider" << llendl; +    hr = CoCreateInstance(CLSID_DxDiagProvider, +                          NULL, +                          CLSCTX_INPROC_SERVER, +                          IID_IDxDiagProvider, +                          (LPVOID*) &dx_diag_providerp); + +	if (FAILED(hr)) +	{ +		llwarns << "No DXDiag provider found!  DirectX 9 not installed!" << llendl; +		gWriteDebug("No DXDiag provider found!  DirectX 9 not installed!\n"); +		goto LCleanup; +	} +    if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed +    { +        // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize +        // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are  +        // digital signed as logo'd by WHQL which may connect via internet to update  +        // WHQL certificates.     +        DXDIAG_INIT_PARAMS dx_diag_init_params; +        ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS)); + +        dx_diag_init_params.dwSize                  = sizeof(DXDIAG_INIT_PARAMS); +        dx_diag_init_params.dwDxDiagHeaderVersion   = DXDIAG_DX9_SDK_VERSION; +        dx_diag_init_params.bAllowWHQLChecks        = TRUE; +        dx_diag_init_params.pReserved               = NULL; + +		llinfos << "dx_diag_providerp->Initialize" << llendl; +        hr = dx_diag_providerp->Initialize(&dx_diag_init_params); +        if(FAILED(hr)) +		{ +            goto LCleanup; +		} + +		llinfos << "dx_diag_providerp->GetRootContainer" << llendl; +        hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp ); +        if(FAILED(hr) || !dx_diag_rootp) +		{ +            goto LCleanup; +		} + +		HRESULT hr; + +		// Get display driver information +		llinfos << "dx_diag_rootp->GetChildContainer" << llendl; +		hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); +		if(FAILED(hr) || !devices_containerp) +		{ +            goto LCleanup; +		} + +		// Get device 0 +		llinfos << "devices_containerp->GetChildContainer" << llendl; +		hr = devices_containerp->GetChildContainer(L"0", &device_containerp); +		if(FAILED(hr) || !device_containerp) +		{ +            goto LCleanup; +		} +		 +		// Get the English VRAM string +		std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); + + +		// Dump the string as an int into the structure +		char *stopstring; +		ret["VRAM"] = strtol(ram_str.c_str(), &stopstring, 10); +		std::string device_name = get_string(device_containerp, L"szDescription"); +		ret["DeviceName"] = device_name; +		std::string device_driver=  get_string(device_containerp, L"szDriverVersion"); +		ret["DriverVersion"] = device_driver; +	} +LCleanup: +	SAFE_RELEASE(file_containerp); +	SAFE_RELEASE(driver_containerp); +	SAFE_RELEASE(device_containerp); +	SAFE_RELEASE(devices_containerp); +    SAFE_RELEASE(dx_diag_rootp); +    SAFE_RELEASE(dx_diag_providerp); +     +    CoUninitialize(); +	return ret; +} +  void LLDXHardware::setWriteDebugFunc(void (*func)(const char*))  {  	gWriteDebug = func; diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h index 1d5d69d8ca..e2a255da76 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -36,6 +36,7 @@  #include "stdtypes.h"  #include "llstring.h" +#include "llsd.h"  class LLVersion  { @@ -93,6 +94,8 @@ public:  	S32 getVRAM() const { return mVRAM; } +	LLSD getDisplayInfo(); +  	// Find a particular device that matches the following specs.  	// Empty strings indicate that you don't care.  	// You can separate multiple devices with '|' chars to indicate you want diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp new file mode 100644 index 0000000000..ba50af9d00 --- /dev/null +++ b/indra/mac_crash_logger/llcrashloggermac.cpp @@ -0,0 +1,310 @@ +/**  + * @file llcrashloggermac.cpp + * @brief Mac OSX crash logger implementation + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + *  + * Copyright (c) 2003-2007, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llcrashloggermac.h" + +#include <Carbon/Carbon.h> +#include <iostream> +#include <sstream> + +#include "boost/tokenizer.hpp" + +#include "indra_constants.h"	// CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME +#include "llerror.h" +#include "llfile.h" +#include "lltimer.h" +#include "llstring.h" +#include "lldir.h" +#include "llsdserialize.h" + +#define MAX_LOADSTRING 100 +const char* const SETTINGS_FILE_HEADER = "version"; +const S32 SETTINGS_FILE_VERSION = 101; + +// Windows Message Handlers + +BOOL gFirstDialog = TRUE;	// Are we currently handling the Send/Don't Send dialog? +FILE *gDebugFile = NULL; + +WindowRef gWindow = NULL; +EventHandlerRef gEventHandler = NULL; +LLString gUserNotes = ""; +bool gSendReport = false; +bool gRememberChoice = false; +IBNibRef nib = NULL; + +OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) +{ +	OSStatus result = eventNotHandledErr; +	OSStatus err; +	UInt32 evtClass = GetEventClass(event); +	UInt32 evtKind = GetEventKind(event); +	if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) +	{ +		HICommand cmd; +		err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); +		 + +		 +		if(err == noErr) +		{ +			//Get the value of the checkbox +			ControlID id; +			ControlRef checkBox = NULL; +			id.signature = 'remb'; +			id.id = 0; +			err = GetControlByID(gWindow, &id, &checkBox); +			 +			if(err == noErr) +			{ +				if(GetControl32BitValue(checkBox) == kControlCheckBoxCheckedValue) +				{ +					gRememberChoice = true; +				} +				else +				{ +					gRememberChoice = false; +				} +			}	 +			switch(cmd.commandID) +			{ +				case kHICommandOK: +				{ +					char buffer[65535];		/* Flawfinder: ignore */ +					Size size = sizeof(buffer) - 1; +					ControlRef textField = NULL; + +					id.signature = 'text'; +					id.id = 0; + +					err = GetControlByID(gWindow, &id, &textField); +					if(err == noErr) +					{ +						// Get the user response text +						err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size); +					} +					if(err == noErr) +					{ +						// Make sure the string is terminated. +						buffer[size] = 0; +						//setUserText(buffer); +						llinfos << buffer << llendl; +					} +					 +					// Send the report. + +					QuitAppModalLoopForWindow(gWindow); +					gSendReport = true; +					result = noErr; +				} +				break; +				 +				case kHICommandCancel: +					QuitAppModalLoopForWindow(gWindow); +					result = noErr; +				break; +			} +		} +	} + +	return(result); +} + + +LLCrashLoggerMac::LLCrashLoggerMac(void) +{ +} + +LLCrashLoggerMac::~LLCrashLoggerMac(void) +{ +} + +bool LLCrashLoggerMac::init(void) +{	 +	bool ok = LLCrashLogger::init(); +	if(!ok) return false; +	// Real UI... +	OSStatus err; +	 +	err = CreateNibReference(CFSTR("CrashReporter"), &nib); +	 +	if(err == noErr) +	{ +		err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow); +	} + +	if(err == noErr) +	{ +		// Set focus to the edit text area +		ControlRef textField = NULL; +		ControlID id; + +		id.signature = 'text'; +		id.id = 0; +		 +		// Don't set err if any of this fails, since it's non-critical. +		if(GetControlByID(gWindow, &id, &textField) == noErr) +		{ +			SetKeyboardFocus(gWindow, textField, kControlFocusNextPart); +		} +	} +	 +	if(err == noErr) +	{ +		ShowWindow(gWindow); +	} +	 +	if(err == noErr) +	{ +		// Set up an event handler for the window. +		EventTypeSpec handlerEvents[] =  +		{ +			{ kEventClassCommand, kEventCommandProcess } +		}; + +		InstallWindowEventHandler( +				gWindow,  +				NewEventHandlerUPP(dialogHandler),  +				GetEventTypeCount (handlerEvents),  +				handlerEvents,  +				0,  +				&gEventHandler); +	} +	return true; +} + +void LLCrashLoggerMac::gatherPlatformSpecificFiles() +{ +	updateApplication("Gathering hardware information..."); +	char path[MAX_PATH];		 +	FSRef folder; +	 +	if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr) +	{ +		// folder is an FSRef to ~/Library/Logs/ +		if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr) +		{ +			struct stat dw_stat; +			LLString mBuf; +			// Try the 10.3 path first... +			LLString dw_file_name = LLString(path) + LLString("/CrashReporter/Second Life.crash.log"); +			int res = stat(dw_file_name.c_str(), &dw_stat); + +			if (res) +			{ +				// Try the 10.2 one next... +				dw_file_name = LLString(path) + LLString("/Second Life.crash.log"); +				res = stat(dw_file_name.c_str(), &dw_stat); +			} +				 +			if (!res) +			{ +				std::ifstream fp(dw_file_name.c_str()); +				std::stringstream str; +				if(!fp.is_open()) return; +				str << fp.rdbuf(); +				mBuf = str.str(); +				 +				// Crash logs consist of a number of entries, one per crash. +				// Each entry is preceeded by "**********" on a line by itself. +				// We want only the most recent (i.e. last) one. +				const char *sep = "**********"; +				const char *start = mBuf.c_str(); +				const char *cur = start; +				const char *temp = strstr(cur, sep); +				 +				while(temp != NULL) +				{ +					// Skip past the marker we just found +					cur = temp + strlen(sep);		/* Flawfinder: ignore */ +					 +					// and try to find another +					temp = strstr(cur, sep); +				} +				 +				// If there's more than one entry in the log file, strip all but the last one. +				if(cur != start) +				{ +					mBuf.erase(0, cur - start); +				} +				mDebugLog["CrashInfo"] = mBuf; +			} +			else +			{ +				llwarns << "Couldn't find any CrashReporter files..." << llendl; +			} +		} +	} +} + +bool LLCrashLoggerMac::mainLoop() +{ +	OSStatus err = noErr; +				 +	if(err == noErr) +	{ +		RunAppModalLoopForWindow(gWindow); +	} +	 +	if(gRememberChoice) +	{ +		if(gSendReport) saveCrashBehaviorSetting(CRASH_BEHAVIOR_ALWAYS_SEND); +		else saveCrashBehaviorSetting(CRASH_BEHAVIOR_NEVER_SEND); +	} +	 +	if(gSendReport) +	{ +		sendCrashLogs(); +	}		 +	 +	if(gWindow != NULL) +	{ +		DisposeWindow(gWindow); +	} +	 +	if(nib != NULL) +	{ +		DisposeNibReference(nib); +	} +	 +	return true; +} + +void LLCrashLoggerMac::updateApplication(LLString message) +{ +	LLCrashLogger::updateApplication(); +} + +bool LLCrashLoggerMac::cleanup() +{ +	return true; +} diff --git a/indra/mac_crash_logger/llcrashloggermac.h b/indra/mac_crash_logger/llcrashloggermac.h new file mode 100644 index 0000000000..cf4e766bda --- /dev/null +++ b/indra/mac_crash_logger/llcrashloggermac.h @@ -0,0 +1,51 @@ +/**  + * @file llcrashloggermac.h + * @brief Mac OSX crash logger definition + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + *  + * Copyright (c) 2003-2007, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLCRASHLOGGERMAC_H +#define LLCRASHLOGGERMAC_H + +#include "linden_common.h" +#include "llcrashlogger.h" +#include "llstring.h" + +class LLCrashLoggerMac : public LLCrashLogger +{ +public: +	LLCrashLoggerMac(void); +	~LLCrashLoggerMac(void); +	virtual bool init(); +	virtual bool mainLoop(); +	virtual void updateApplication(LLString message = ""); +	virtual bool cleanup(); +	virtual void gatherPlatformSpecificFiles(); +}; + +#endif diff --git a/indra/mac_crash_logger/mac_crash_logger.cpp b/indra/mac_crash_logger/mac_crash_logger.cpp index 2501b4a521..bf3151a490 100644 --- a/indra/mac_crash_logger/mac_crash_logger.cpp +++ b/indra/mac_crash_logger/mac_crash_logger.cpp @@ -31,675 +31,21 @@  #include "linden_common.h" -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <curl/curl.h> - -#include "llerror.h" -#include "lltimer.h" -#include "lldir.h" - -#include "llstring.h" - -class LLFileEncoder -{ -public: -	LLFileEncoder(const char *formname, const char *filename, bool isCrashLog = false); - -	BOOL isValid() const { return mIsValid; } -	LLString encodeURL(const S32 max_length = 0); -public: -	BOOL mIsValid; -	LLString mFilename; -	LLString mFormname; -	LLString mBuf; -}; - -LLString encode_string(const char *formname, const LLString &str); - -#include <Carbon/Carbon.h> - -LLString gServerResponse; -BOOL gSendReport = FALSE; -LLString gUserserver; -LLString gUserText; -WindowRef gWindow = NULL; -EventHandlerRef gEventHandler = NULL; -BOOL gCrashInPreviousExec = FALSE; -time_t gLaunchTime; - -size_t curl_download_callback(void *data, size_t size, size_t nmemb, -										  void *user_data) -{ -	S32 bytes = size * nmemb; -	char *cdata = (char *) data; -	for (int i =0; i < bytes; i += 1) -	{ -		gServerResponse += (cdata[i]); -	} -	return bytes; -} - -OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) -{ -	OSStatus result = eventNotHandledErr; -	OSStatus err; -	UInt32 evtClass = GetEventClass(event); -	UInt32 evtKind = GetEventKind(event); -	 -	if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) -	{ -		HICommand cmd; -		err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); -		 -		if(err == noErr) -		{ -			switch(cmd.commandID) -			{ -				case kHICommandOK: -				{ -					char buffer[65535];		/* Flawfinder: ignore */ -					Size size = sizeof(buffer) - 1; -					ControlRef textField = NULL; -					ControlID id; - -					id.signature = 'text'; -					id.id = 0; - -					err = GetControlByID(gWindow, &id, &textField); -					if(err == noErr) -					{ -						// Get the user response text -						err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size); -					} -					if(err == noErr) -					{ -						// Make sure the string is terminated. -						buffer[size] = 0; -						gUserText = buffer; -						llinfos << buffer << llendl; -					} -					 -					// Send the report. -					gSendReport = TRUE; - -					QuitAppModalLoopForWindow(gWindow); -					result = noErr; -				} -				break; -				 -				case kHICommandCancel: -					QuitAppModalLoopForWindow(gWindow); -					result = noErr; -				break; -			} -		} -	} -	 -	return(result); -} +#include "llcrashloggermac.h"  int main(int argc, char **argv)  { -	const S32 DW_MAX_SIZE = 100000;			// Maximum size to transmit of the Dr. Watson log file -	const S32 SL_MAX_SIZE = 100000;			// Maximum size of the Second Life log file. -	int i; -	 -	time(&gLaunchTime); +	//time(&gLaunchTime);  	llinfos << "Starting Second Life Viewer Crash Reporter" << llendl; -	 -	for(i=1; i<argc; i++) -	{ -		if(!strcmp(argv[i], "-previous")) -		{ -			gCrashInPreviousExec = TRUE; -		} -		if(!strcmp(argv[i], "-user")) -		{ -			if ((i + 1) < argc) -			{ -				i++; -				gUserserver = argv[i]; -				llinfos << "Got userserver " << gUserserver << llendl; -			} -		} -	} -	 -	if( gCrashInPreviousExec ) -	{ -		llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl; -	} -	 -	if(!gCrashInPreviousExec) -	{ -		// Delay five seconds to let CrashReporter do its thing. -		sleep(5); -	} -		 -#if 1 -	// Real UI... -	OSStatus err; -	IBNibRef nib = NULL; -	 -	err = CreateNibReference(CFSTR("CrashReporter"), &nib); -	 -	if(err == noErr) -	{ -		if(gCrashInPreviousExec) -		{ -			err = CreateWindowFromNib(nib, CFSTR("CrashReporterDelayed"), &gWindow); -		} -		else -		{ -			err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow); -		} -	} - -	if(err == noErr) -	{ -		// Set focus to the edit text area -		ControlRef textField = NULL; -		ControlID id; - -		id.signature = 'text'; -		id.id = 0; -		 -		// Don't set err if any of this fails, since it's non-critical. -		if(GetControlByID(gWindow, &id, &textField) == noErr) -		{ -			SetKeyboardFocus(gWindow, textField, kControlFocusNextPart); -		} -	} -	 -	if(err == noErr) -	{ -		ShowWindow(gWindow); -	} -	 -	if(err == noErr) -	{ -		// Set up an event handler for the window. -		EventTypeSpec handlerEvents[] =  -		{ -			{ kEventClassCommand, kEventCommandProcess } -		}; - -		InstallWindowEventHandler( -				gWindow,  -				NewEventHandlerUPP(dialogHandler),  -				GetEventTypeCount (handlerEvents),  -				handlerEvents,  -				0,  -				&gEventHandler); -	} -			 -	if(err == noErr) -	{ -		RunAppModalLoopForWindow(gWindow); -	} -			 -	if(gWindow != NULL) -	{ -		DisposeWindow(gWindow); -	} -	 -	if(nib != NULL) -	{ -		DisposeNibReference(nib); -	} -#else -	// Cheap version -- just use the standard system alert. -	SInt16 itemHit = 0; -	AlertStdCFStringAlertParamRec params; -	OSStatus err = noErr; -	DialogRef alert = NULL; - -	params.version = kStdCFStringAlertVersionOne; -	params.movable = false; -	params.helpButton = false; -	params.defaultText = CFSTR("Send Report"); -	params.cancelText = CFSTR("Don't Send Report"); -	params.otherText = 0; -	params.defaultButton = kAlertStdAlertOKButton; -	params.cancelButton = kAlertStdAlertCancelButton; -	params.position = kWindowDefaultPosition; -	params.flags = 0; - -	err = CreateStandardAlert( -			kAlertCautionAlert, -			CFSTR("Second Life appears to have crashed."), -			CFSTR( -			"To help us debug the problem, you can send a crash report to Linden Lab.  " -			"The report contains information about your microprocessor type, graphics card, " -			"memory, things that happened during the last run of the program, and the Crash Log " -			"of where the crash occurred.\r" -			"\r" -			"You may also report crashes in the forums, or by sending e-mail to peter@lindenlab.com"), -			¶ms, -			&alert); -	 -	if(err == noErr) -	{ -		err = RunStandardAlert( -				alert, -				NULL, -				&itemHit); -  	} -	 -	if(itemHit == kAlertStdAlertOKButton) -		gSendReport = TRUE; -#endif -	 -	if(!gSendReport) -	{ -		// Only send the report if the user agreed to it. -		llinfos << "User cancelled, not sending report" << llendl; - -		return(0); -	} - -	// We assume that all the logs we're looking for reside on the current drive -	gDirUtilp->initAppDirs("SecondLife"); - -	int res; - -	// Lots of silly variable, replicated for each log file. -	LLString db_file_name; -	LLString sl_file_name; -	LLString dw_file_name; // DW file name is a hack for now... -	LLString st_file_name; // stats.log file -	LLString si_file_name; // settings.ini file - -	LLFileEncoder *db_filep = NULL; -	LLFileEncoder *sl_filep = NULL; -	LLFileEncoder *st_filep = NULL; -	LLFileEncoder *dw_filep = NULL; -	LLFileEncoder *si_filep = NULL; - -	/////////////////////////////////// -	// -	// We do the parsing for the debug_info file first, as that will -	// give us the location of the SecondLife.log file. -	// - -	// Figure out the filename of the debug log -	db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log").c_str(); -	db_filep = new LLFileEncoder("DB", db_file_name.c_str()); - -	// Get the filename of the SecondLife.log file - -	// *NOTE: changing the size of either of these buffers will -	// require changing the sscanf() format string to correctly -	// account for it. -	char tmp_sl_name[LL_MAX_PATH];	/* Flawfinder: ignore */ -	tmp_sl_name[0] = '\0'; -	char tmp_space[MAX_STRING];		/* Flawfinder: ignore */ -	tmp_space[0] = '\0'; - -	// Look for it in the debug_info.log file -	if (db_filep->isValid()) -	{ -		// This was originally scanning for "SL Log: %[^\r\n]", which happily skipped to the next line -		// on debug logs (which don't have anything after "SL Log:" and tried to open a nonsensical filename. -		sscanf( -			db_filep->mBuf.c_str(), -			"SL Log:%254[ ]%1023[^\r\n]", -			tmp_space, -			tmp_sl_name); -	} -	else -	{ -		delete db_filep; -		db_filep = NULL; -	} - -	// If we actually have a legitimate file name, use it. -	if (tmp_sl_name[0]) -	{ -		sl_file_name = tmp_sl_name; -		llinfos << "Using log file from debug log " << sl_file_name << llendl; -	} -	else -	{ -		// Figure out the filename of the second life log -		sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log").c_str(); -	} - -	// Now we get the SecondLife.log file if it's there, and recent enough... -	sl_filep = new LLFileEncoder("SL", sl_file_name.c_str()); -	if (!sl_filep->isValid()) -	{ -		delete sl_filep; -		sl_filep = NULL; -	} - -	st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log").c_str(); -	st_filep = new LLFileEncoder("ST", st_file_name.c_str()); -	if (!st_filep->isValid()) -	{ -		delete st_filep; -		st_filep = NULL; -	} - -	si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.ini").c_str(); -	si_filep = new LLFileEncoder("SI", si_file_name.c_str()); -	if (!si_filep->isValid()) -	{ -		delete si_filep; -		si_filep = NULL; -	} - -	// MBW -- This needs to go find "~/Library/Logs/CrashReporter/Second Life.crash.log" on 10.3 -	// or "~/Library/Logs/Second Life.crash.log" on 10.2. -	{ -		char path[MAX_PATH];		/* Flawfinder: ignore */ -		FSRef folder; -		 -		if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr) -		{ -			// folder is an FSRef to ~/Library/Logs/ -			if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr) -			{ -				struct stat dw_stat; -//				printf("path is %s\n", path); -				 -				// Try the 10.3 path first... -				dw_file_name = LLString(path) + LLString("/CrashReporter/Second Life.crash.log"); -				res = stat(dw_file_name.c_str(), &dw_stat); - -				if (res) -				{ -					// Try the 10.2 one next... -					dw_file_name = LLString(path) + LLString("/Second Life.crash.log"); -					res = stat(dw_file_name.c_str(), &dw_stat); -				} -				 -				if (!res) -				{ -					dw_filep = new LLFileEncoder("DW", dw_file_name.c_str(), true); -					if (!dw_filep->isValid()) -					{ -						delete dw_filep; -						dw_filep = NULL; -					} -				} -				else -				{ -					llwarns << "Couldn't find any CrashReporter files..." << llendl; -				} -			} -		} -	} - -	LLString post_data; -	LLString tmp_url_buf; - -	// Append the userserver -	tmp_url_buf = encode_string("USER", gUserserver); -	post_data += tmp_url_buf; -	llinfos << "PostData:" << post_data << llendl; - -	if (gCrashInPreviousExec) -	{ -		post_data.append("&"); -		tmp_url_buf = encode_string("EF", "Y"); -		post_data += tmp_url_buf; -	} - -	if (db_filep) -	{ -		post_data.append("&"); -		tmp_url_buf = db_filep->encodeURL(); -		post_data += tmp_url_buf; -		llinfos << "Sending DB log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending DB log file" << llendl; -	} - -	if (sl_filep) -	{ -		post_data.append("&"); -		tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE); -		post_data += tmp_url_buf; -		llinfos << "Sending SL log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending SL log file" << llendl; -	} - -	if (st_filep) -	{ -		post_data.append("&"); -		tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE); -		post_data += tmp_url_buf; -		llinfos << "Sending stats log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending stats log file" << llendl; -	} -	if (dw_filep) +	LLCrashLoggerMac app; +	app.parseCommandOptions(argc, argv); +	if(!app.init())  	{ -		post_data.append("&"); -		tmp_url_buf = dw_filep->encodeURL(DW_MAX_SIZE); -		post_data += tmp_url_buf; +		return 0;  	} -	else -	{ -		llinfos << "Not sending crash log file" << llendl; -	} - -	if (si_filep) -	{ -		post_data.append("&"); -		tmp_url_buf = si_filep->encodeURL(); -		post_data += tmp_url_buf; -		llinfos << "Sending settings log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending settings.ini file" << llendl; -	} - -	if (gUserText.size()) -	{ -		post_data.append("&"); -		tmp_url_buf = encode_string("UN", gUserText); -		post_data += tmp_url_buf; -	} - -	delete db_filep; -	db_filep = NULL; -	delete sl_filep; -	sl_filep = NULL; -	delete dw_filep; -	dw_filep = NULL; - -	// Debugging spam -#if 0 -	printf("Crash report post data:\n--------\n"); -	printf("%s", post_data.getString()); -	printf("\n--------\n"); -#endif -	 -	// Send the report.  Yes, it's this easy. -	{ -		CURL *curl = curl_easy_init(); - -		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); -		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback); -		curl_easy_setopt(curl, CURLOPT_POST, 1);  -		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str());  -		curl_easy_setopt(curl, CURLOPT_URL,	"http://secondlife.com/cgi-bin/viewer_crash_reporter2"); -		 -		llinfos << "Connecting to crash report server" << llendl; -		CURLcode result = curl_easy_perform(curl); -		 -		curl_easy_cleanup(curl); +	app.mainLoop(); -		if(result != CURLE_OK) -		{ -			llinfos << "Couldn't talk to crash report server" << llendl; -		} -		else -		{ -			llinfos << "Response from crash report server:" << llendl; -			llinfos << gServerResponse << llendl;			 -		} -	} -	  	return 0;  } - -LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename, bool isCrashLog) -{ -	mFormname = form_name; -	mFilename = filename; -	mIsValid = FALSE; - -	int res; -	 -	struct stat stat_data; -	res = stat(mFilename.c_str(), &stat_data); -	if (res) -	{ -		llwarns << "File " << mFilename << " is missing!" << llendl; -		return; -	} -	else -	{ -		// Debugging spam -//		llinfos << "File " << mFilename << " is present..." << llendl; - -		if(!gCrashInPreviousExec && isCrashLog) -		{ -			// Make sure the file isn't too old. -			double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec); - -//			llinfos << "age is " << age << llendl; - -			if(age > 60.0) -			{ -				// The file was last modified more than 60 seconds before the crash reporter was launched.  Assume it's stale. -				llwarns << "File " << mFilename << " is too old!" << llendl; -				return; -			} -		} - -	} - -	S32 buf_size = stat_data.st_size; -	FILE* fp = fopen(mFilename.c_str(), "rb");		/* Flawfinder: ignore */ -	U8 *buf = new U8[buf_size + 1]; -	fread(buf, 1, buf_size, fp); -	fclose(fp); -	buf[buf_size] = 0; - -	mBuf = (char *)buf; -	 -	if(isCrashLog) -	{ -		// Crash logs consist of a number of entries, one per crash. -		// Each entry is preceeded by "**********" on a line by itself. -		// We want only the most recent (i.e. last) one. -		const char *sep = "**********"; -		const char *start = mBuf.c_str(); -		const char *cur = start; -		const char *temp = strstr(cur, sep); -		 -		while(temp != NULL) -		{ -			// Skip past the marker we just found -			cur = temp + strlen(sep);		/* Flawfinder: ignore */ -			 -			// and try to find another -			temp = strstr(cur, sep); -		} -		 -		// If there's more than one entry in the log file, strip all but the last one. -		if(cur != start) -		{ -			mBuf.erase(0, cur - start); -		} -	} - -	mIsValid = TRUE; -	delete[] buf; -} - -LLString LLFileEncoder::encodeURL(const S32 max_length) -{ -	LLString result = mFormname; -	result.append("="); - -	S32 i = 0; - -	if (max_length) -	{ -		if (mBuf.size() > max_length) -		{ -			i = mBuf.size() - max_length; -		} -	} - -#if 0 -	// Plain text version for debugging -	result.append(mBuf); -#else -	// Not using LLString because of bad performance issues -	S32 buf_size = mBuf.size(); -	S32 url_buf_size = 3*mBuf.size() + 1; -	char *url_buf = new char[url_buf_size]; -	if (url_buf == NULL) -	{ -		llerrs << "Memory Allocation Failed" << llendl; -		return result; -	} -	S32 cur_pos = 0; -	for (; i < buf_size; i++) -	{ -		sprintf(url_buf + cur_pos, "%%%02x", mBuf[i]);		/* Flawfinder: ignore */ -		cur_pos += 3; -	} -	url_buf[i*3] = 0; - -	result.append(url_buf); -	delete[] url_buf; -#endif -	return result; -} - -LLString encode_string(const char *formname, const LLString &str) -{ -	LLString result = formname; -	result.append("="); -	// Not using LLString because of bad performance issues -	S32 buf_size = str.size(); -	S32 url_buf_size = 3*str.size() + 1; -	char *url_buf = new char[url_buf_size]; -	if (url_buf == NULL) -	{ -		llerrs << "Memory Allocation Failed" << llendl; -	    return result; -	} - -	S32 cur_pos = 0; -	S32 i; -	for (i = 0; i < buf_size; i++) -	{ -		sprintf(url_buf + cur_pos, "%%%02x", str[i]);		/* Flawfinder: ignore */ -		cur_pos += 3; -	} -	url_buf[i*3] = 0; - -	result.append(url_buf); -	delete[] url_buf; -	return result; -} diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c0e9833829..63d1986dec 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -106,6 +106,8 @@  #include "llcontainerview.h"  #include "llhoverview.h" +#include "llsdserialize.h" +  #if LL_WINDOWS && LL_LCD_COMPILE  	#include "lllcd.h"  #endif @@ -267,6 +269,8 @@ BOOL gAcceptCriticalMessage = FALSE;  LLUUID				gViewerDigest;	// MD5 digest of the viewer's executable file.  BOOL gLastExecFroze = FALSE; +LLSD gDebugInfo; +  U32	gFrameCount = 0;  U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground  LLPumpIO*			gServicePump = NULL; @@ -915,7 +919,6 @@ LLTextureFetch* LLAppViewer::sTextureFetch = NULL;  LLAppViewer::LLAppViewer() :   	mMarkerFile(NULL),  	mLastExecFroze(false), -	mDebugFile(NULL),  	mCrashBehavior(CRASH_BEHAVIOR_ASK),  	mReportedCrash(false),  	mNumSessions(0), @@ -1220,7 +1223,7 @@ bool LLAppViewer::init()  		CreateLCDDebugWindows();  	#endif -	writeDebug(gGLManager.getGLInfoString()); +	gGLManager.getGLInfo(gDebugInfo);  	llinfos << gGLManager.getGLInfoString() << llendl;  	//load key settings @@ -2351,30 +2354,13 @@ bool LLAppViewer::initWindow()  	return true;  } -void LLAppViewer::writeDebug(const char *str) -{ -	if (!mDebugFile) -	{ -		std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); -		llinfos << "Opening debug file " << debug_filename << llendl; -		mDebugFile = LLFile::fopen(debug_filename.c_str(), "w");		/* Flawfinder: ignore */ -        if (!mDebugFile) -        { -		    llinfos << "Opening debug file " << debug_filename << " failed. Using stderr." << llendl; -            mDebugFile = stderr; -        } -	} -	fputs(str, mDebugFile); -	fflush(mDebugFile); -} -  void LLAppViewer::closeDebug()  { -	if (mDebugFile) -	{ -		fclose(mDebugFile); -	} -	mDebugFile = NULL; +	std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); +	llinfos << "Opening debug file " << debug_filename << llendl; +	std::ofstream out_file(debug_filename.c_str()); +	LLSDSerialize::toPrettyXML(gDebugInfo, out_file); +	out_file.close();  }  void LLAppViewer::cleanupSavedSettings() @@ -2443,23 +2429,22 @@ void LLAppViewer::removeCacheFiles(const char* file_mask)  void LLAppViewer::writeSystemInfo()  { -	writeDebug("SL Log: "); -	writeDebug(LLError::logFileName()); -	writeDebug("\n"); - -	std::string tmp_str = gSecondLife -		+ llformat(" version %d.%d.%d build %d", -				   LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VERSION_BUILD); -	writeDebug(tmp_str.c_str()); -	writeDebug("\n"); -	writeDebug(gSysCPU.getCPUString()); -	writeDebug("\n"); +	gDebugInfo["SLLog"] = LLError::logFileName(); + +	gDebugInfo["ClientInfo"]["Name"] = gSecondLife; +	gDebugInfo["ClientInfo"]["MajorVersion"] = LL_VERSION_MAJOR; +	gDebugInfo["ClientInfo"]["MinorVersion"] = LL_VERSION_MINOR; +	gDebugInfo["ClientInfo"]["PatchVersion"] = LL_VERSION_PATCH; +	gDebugInfo["ClientInfo"]["BuildVersion"] = LL_VERSION_BUILD; + +	gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily(); +	gDebugInfo["CPUInfo"]["CPUMhz"] = gSysCPU.getMhz(); +	gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec(); +	gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); +	gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); -	tmp_str = llformat("RAM: %u KB\n", gSysMemory.getPhysicalMemoryKB()); -	writeDebug(tmp_str.c_str()); -	writeDebug("OS: "); -	writeDebug(getOSInfo().getOSString().c_str()); -	writeDebug("\n"); +	gDebugInfo["RAMInfo"] = llformat("%u", gSysMemory.getPhysicalMemoryKB()); +	gDebugInfo["OSInfo"] = mSysOSInfo.getOSString().c_str();  	// Dump some debugging info  	llinfos << gSecondLife << " version " @@ -2498,16 +2483,11 @@ void LLAppViewer::handleViewerCrash()  	}  	pApp->mReportedCrash = TRUE; -	BOOL do_crash_report = FALSE; - -	do_crash_report = TRUE; - -	pApp->writeDebug("Viewer exe: "); -	pApp->writeDebug(gDirUtilp->getExecutablePathAndName().c_str()); -	pApp->writeDebug("\n"); -	pApp->writeDebug("Cur path: "); -	pApp->writeDebug(gDirUtilp->getCurPath().c_str()); -	pApp->writeDebug("\n\n"); +	gDebugInfo["SettingsFilename"] = gSettingsFileName; +	gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); +	gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName().c_str(); +	gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath().c_str(); +	gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName();  	if (gMessageSystem && gDirUtilp)  	{ @@ -2517,27 +2497,24 @@ void LLAppViewer::handleViewerCrash()  		if(file.good())  		{  			gMessageSystem->summarizeLogs(file); +			file.close();  		}  	}  	if (gMessageSystem)  	{ -		pApp->writeDebug(gMessageSystem->getCircuitInfoString()); +		gMessageSystem->getCircuitInfo(gDebugInfo["CircuitInfo"]);  		gMessageSystem->stopLogging();  	} -	pApp->writeDebug("\n");  	if (gWorldp)  	{ -		pApp->writeDebug(gWorldp->getInfoString()); +		gWorldp->getInfo(gDebugInfo);  	}  	// Close the debug file  	pApp->closeDebug();  	LLError::logToFile(""); -	// Close the SecondLife.log -	//pApp->removeMarkerFile(); -  	// Call to pure virtual, handled by platform specifc llappviewer instance.  	pApp->handleCrashReporting();  diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 227a27a8ac..e97aead955 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -68,9 +68,6 @@ public:  	// This version stores the argc and argv for later usage, make sure the params passed in last as long as this class.  	bool tempStoreCommandOptions(int argc, char** argv); -	// write string to "debug_info.log", used for crash reporting. -	void writeDebug(const char *str);  -	void writeDebug(const std::string& str) { writeDebug(str.c_str()); };  	void closeDebug();  	const LLOSInfo& getOSInfo() const { return mSysOSInfo; } @@ -165,8 +162,6 @@ private:  	FILE *mMarkerFile; // A file created to indicate the app is running.  	bool mLastExecFroze; // Set on init if the marker file was found. -	FILE* mDebugFile; // output stream written to via writeDebug() -  	LLOSInfo mSysOSInfo;   	S32 mCrashBehavior;  	bool mReportedCrash; @@ -202,6 +197,7 @@ extern BOOL gProbeHardware;  extern LLString gDisabledMessage; // llstartup  extern BOOL gHideLinks; // used by llpanellogin, lllfloaterbuycurrency, llstartup  extern BOOL gInProductionGrid;  +extern LLSD gDebugInfo;  extern BOOL	gAllowIdleAFK;  extern F32 gAFKTimeout; diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 1d7a6690fc..814c209e67 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -322,9 +322,16 @@ bool LLAppViewerWin32::initWindow()  	return LLAppViewer::initWindow();  } -void write_debug_callback(const char* str) +void write_debug_dx(const char* str)  { -	LLAppViewer::instance()->writeDebug(str); +	LLString value = gDebugInfo["DXInfo"].asString(); +	value += str; +	gDebugInfo["DXInfo"] = value; +} + +void write_debug_dx(const std::string& str) +{ +	write_debug_dx(str.c_str());  }  bool LLAppViewerWin32::initHardwareTest() @@ -340,7 +347,7 @@ bool LLAppViewerWin32::initHardwareTest()  		LLSplashScreen::update("Detecting hardware...");  		llinfos << "Attempting to poll DirectX for hardware info" << llendl; -		gDXHardware.setWriteDebugFunc(write_debug_callback); +		gDXHardware.setWriteDebugFunc(write_debug_dx);  		BOOL probe_ok = gDXHardware.getInfo(vram_only);  		if (!probe_ok diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index c43c4e8685..dda155d0df 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -773,12 +773,11 @@ BOOL idle_startup()  			gSavedSettings.setString("FirstName", firstname);  			gSavedSettings.setString("LastName", lastname); + +			 +  			llinfos << "Attempting login as: " << firstname << " " << lastname << llendl; -			LLAppViewer::instance()->writeDebug("Attempting login as: "); -			LLAppViewer::instance()->writeDebug(firstname); -			LLAppViewer::instance()->writeDebug(" "); -			LLAppViewer::instance()->writeDebug(lastname); -			LLAppViewer::instance()->writeDebug("\n"); +			gDebugInfo["LoginName"] = firstname + " " + lastname;	  		}  		// create necessary directories @@ -826,6 +825,7 @@ BOOL idle_startup()  			LLPanelLogin::close();  		} +		  		//For HTML parsing in text boxes.  		LLTextEditor::setLinkColor( gSavedSettings.getColor4("HTMLLinkColor") );  		LLTextEditor::setURLCallbacks ( &LLWeb::loadURL, &LLURLDispatcher::dispatch, &LLURLDispatcher::dispatch   ); @@ -895,6 +895,8 @@ BOOL idle_startup()  	if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState())  	{  //#define LL_MINIMIAL_REQUESTED_OPTIONS +		gDebugInfo["GridUtilHost"] = gGridInfo[gGridChoice].mName; +  		lldebugs << "STATE_LOGIN_AUTH_INIT" << llendl;  		if (!gUserAuthp)  		{ @@ -932,6 +934,7 @@ BOOL idle_startup()  		}  		LLAppViewer::instance()->getLoginURIs();  		sAuthUris = LLAppViewer::instance()->getLoginURIs(); +  		sAuthUriNum = 0;  		auth_method = "login_to_simulator";  		auth_desc = "Logging in.  "; @@ -1226,15 +1229,11 @@ BOOL idle_startup()  			const char* text;  			text = gUserAuthp->getResponse("agent_id");  			if(text) gAgentID.set(text); -			LLAppViewer::instance()->writeDebug("AgentID: "); -			LLAppViewer::instance()->writeDebug(text); -			LLAppViewer::instance()->writeDebug("\n"); +			gDebugInfo["AgentID"] = text;  			text = gUserAuthp->getResponse("session_id");  			if(text) gAgentSessionID.set(text); -			LLAppViewer::instance()->writeDebug("SessionID: "); -			LLAppViewer::instance()->writeDebug(text); -			LLAppViewer::instance()->writeDebug("\n"); +			gDebugInfo["SessionID"] = text;  			text = gUserAuthp->getResponse("secure_session_id");  			if(text) gAgent.mSecureSessionID.set(text); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 95a1db12df..5bfe023168 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -964,28 +964,16 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg)  	}  } -LLString LLViewerRegion::getInfoString() +void LLViewerRegion::getInfo(LLSD& info)  { -	char tmp_buf[256];		/* Flawfinder: ignore */ -	LLString info; -	 -	info = "Region: "; -	getHost().getString(tmp_buf, 256); -	info += tmp_buf; -	info += ":"; -	info += getName(); -	info += "\n"; - +	info["Region"]["Host"] = getHost().getIPandPort(); +	info["Region"]["Name"] = getName();  	U32 x, y;  	from_region_handle(getHandle(), &x, &y); -	snprintf(tmp_buf, sizeof(tmp_buf), "%d:%d", x, y);		/* Flawfinder: ignore */ -	info += "Handle:"; -	info += tmp_buf; -	info += "\n"; -	return info; +	info["Region"]["Handle"]["x"] = (LLSD::Integer)x; +	info["Region"]["Handle"]["y"] = (LLSD::Integer)y;  } -  void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)  {  	U32 local_id = objectp->getLocalID(); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 013a96f2d1..a0953e561e 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -223,7 +223,7 @@ public:  	F32 getLandHeightRegion(const LLVector3& region_pos); -	LLString getInfoString(); +	void getInfo(LLSD& info);  	// handle a full update message  	void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); diff --git a/indra/newview/llwindebug.cpp b/indra/newview/llwindebug.cpp index 88ba5822eb..13c5ac3bbb 100644 --- a/indra/newview/llwindebug.cpp +++ b/indra/newview/llwindebug.cpp @@ -33,12 +33,70 @@  #ifdef LL_WINDOWS +#include <tchar.h> +#include <tlhelp32.h> +#include <atlbase.h> +#include "llappviewer.h"  #include "llwindebug.h"  #include "llviewercontrol.h"  #include "lldir.h" - -#include "llappviewer.h" - +#include "llsd.h" +#include "llsdserialize.h" + +#pragma warning(disable: 4200)	//nonstandard extension used : zero-sized array in struct/union +#pragma warning(disable: 4100)	//unreferenced formal parameter + +/* +LLSD Block for Windows Dump Information +<llsd> +  <map> +    <key>Platform</key> +    <string></string> +    <key>Process</key> +    <string></string> +    <key>Module</key> +    <string></string> +    <key>Date Modified</key> +    <string></string> +    <key>Exception Code</key> +    <string></string> +    <key>Exception Read/Write Address</key> +    <string></string> +    <key>Instruction</key> +    <string></string> +    <key>Registers</key> +    <map> +      <!-- Continued for all registers --> +      <key>EIP</key> +      <string>...</string> +      <!-- ... --> +    </map> +    <key>Call Stack</key> +    <array> +      <!-- One map per stack frame --> +      <map> +	<key>Module Name</key> +	<string></string> +	<key>Module Base Address</key> +	<string></string> +	<key>Module Offset Address</key> +	<string></string> +	<key>Parameters</key> +	<array> +	  <string></string> +	</array> +      </map> +      <!-- ... --> +    </array> +  </map> +</llsd> + +*/ + +// From viewer.h +extern BOOL gInProductionGrid; + +extern void (*gCrashCallback)(void);  // based on dbghelp.h  typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, @@ -49,6 +107,255 @@ typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hF  MINIDUMPWRITEDUMP f_mdwp = NULL; +#undef UNICODE + +HMODULE	hDbgHelp; + +// Tool Help functions. +typedef	HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); +typedef	BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); +typedef	BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); + +CREATE_TOOL_HELP32_SNAPSHOT	CreateToolhelp32Snapshot_; +MODULE32_FIRST	Module32First_; +MODULE32_NEST	Module32Next_; + +#define	DUMP_SIZE_MAX	8000	//max size of our dump +#define	CALL_TRACE_MAX	((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40))	//max number of traced calls +#define	NL				L"\r\n"	//new line + +//**************************************************************************************** +BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr) +//**************************************************************************************** +// Find module by Ret_Addr (address in the module). +// Return Module_Name (full path) and Module_Addr (start address). +// Return TRUE if found. +{ +	MODULEENTRY32	M = {sizeof(M)}; +	HANDLE	hSnapshot; + +	bool found = false; +	 +	if (CreateToolhelp32Snapshot_) +	{ +		hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0); +		 +		if ((hSnapshot != INVALID_HANDLE_VALUE) && +			Module32First_(hSnapshot, &M)) +		{ +			do +			{ +				if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize) +				{ +					lstrcpyn(Module_Name, M.szExePath, MAX_PATH); +					Module_Addr = M.modBaseAddr; +					found = true; +					break; +				} +			} while (Module32Next_(hSnapshot, &M)); +		} + +		CloseHandle(hSnapshot); +	} + +	return found; +} //Get_Module_By_Ret_Addr + +//****************************************************************** +void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info) +//****************************************************************** +// Fill Str with call stack info. +// pException can be either GetExceptionInformation() or NULL. +// If pException = NULL - get current call stack. +{	 + +	USES_CONVERSION; + +	LPWSTR	Module_Name = new WCHAR[MAX_PATH]; +	PBYTE	Module_Addr = 0; +	 +	typedef struct STACK +	{ +		STACK *	Ebp; +		PBYTE	Ret_Addr; +		DWORD	Param[0]; +	} STACK, * PSTACK; + +	STACK	Stack = {0, 0}; +	PSTACK	Ebp; + +	if (pException)		//fake frame for exception address +	{ +		Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp; +		Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress; +		Ebp = &Stack; +	} +	else +	{ +		Ebp = (PSTACK)&pException - 1;	//frame addr of Get_Call_Stack() + +		// Skip frame of Get_Call_Stack(). +		if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) +			Ebp = Ebp->Ebp;		//caller ebp +	} + +	// Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. +	// Break trace on wrong stack frame. +	for (int Ret_Addr_I = 0, i = 0; +		(Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); +		Ret_Addr_I++, Ebp = Ebp->Ebp, ++i) +	{ +		// If module with Ebp->Ret_Addr found. + +		if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr)) +		{ +			// Save module's address and full path. +			info["Call Stack"][i]["Module Name"] = W2A(Module_Name); +			info["Call Stack"][i]["Module Address"] = (int)Module_Addr; +			info["Call Stack"][i]["Call Offset"] = (int)(Ebp->Ret_Addr - Module_Addr); + +			LLSD params; +			// Save 5 params of the call. We don't know the real number of params. +			if (pException && !Ret_Addr_I)	//fake frame for exception address +				params[0] = "Exception Offset"; +			else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) +			{ +				for(int j = 0; j < 5; ++j) +				{ +					params[j] = (int)Ebp->Param[j]; +				} +			} +			info["Call Stack"][i]["Parameters"] = params; +		} +		info["Call Stack"][i]["Return Address"] = (int)Ebp->Ret_Addr;			 +	} +} //Get_Call_Stack + +//*********************************** +void WINAPI Get_Version_Str(LLSD& info) +//*********************************** +// Fill Str with Windows version. +{ +	OSVERSIONINFOEX	V = {sizeof(OSVERSIONINFOEX)};	//EX for NT 5.0 and later + +	if (!GetVersionEx((POSVERSIONINFO)&V)) +	{ +		ZeroMemory(&V, sizeof(V)); +		V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); +		GetVersionEx((POSVERSIONINFO)&V); +	} + +	if (V.dwPlatformId != VER_PLATFORM_WIN32_NT) +		V.dwBuildNumber = LOWORD(V.dwBuildNumber);	//for 9x HIWORD(dwBuildNumber) = 0x04xx + +	info["Platform"] = llformat("Windows:  %d.%d.%d, SP %d.%d, Product Type %d",	//SP - service pack, Product Type - VER_NT_WORKSTATION,... +		V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor, V.wProductType); +} //Get_Version_Str + +//************************************************************* +LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException) +//************************************************************* +// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str. +{ +	USES_CONVERSION; + +	LLSD info; +	LPWSTR		Str; +	int			Str_Len; +	int			i; +	LPWSTR		Module_Name = new WCHAR[MAX_PATH]; +	PBYTE		Module_Addr; +	HANDLE		hFile; +	FILETIME	Last_Write_Time; +	FILETIME	Local_File_Time; +	SYSTEMTIME	T; +	 +	Str = new WCHAR[DUMP_SIZE_MAX]; +	Str_Len = 0; +	if (!Str) +		return NULL; +	 +	Get_Version_Str(info); + +	 +	GetModuleFileName(NULL, Str, MAX_PATH); +	info["Process"] = W2A(Str); + +	// If exception occurred. +	if (pException) +	{ +		EXCEPTION_RECORD &	E = *pException->ExceptionRecord; +		CONTEXT &			C = *pException->ContextRecord; + +		// If module with E.ExceptionAddress found - save its path and date. +		if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) +		{ +			info["Module"] = W2A(Module_Name); + +			if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, +				FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) +			{ +				if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)) +				{ +					FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time); +					FileTimeToSystemTime(&Local_File_Time, &T); + +					info["Date Modified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear); +				} +				CloseHandle(hFile); +			} +		} +		else +		{ +			info["Exception Addr"] = (int)E.ExceptionAddress; +		} +		 +		info["Exception Code"] = (int)E.ExceptionCode; +		 +		/* +		//TODO: Fix this +		if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) +		{ +			// Access violation type - Write/Read. +			LLSD exception_info; +			exception_info["Type"] = E.ExceptionInformation[0] ? "Write" : "Read"; +			exception_info["Address"] = llformat("%08x", E.ExceptionInformation[1]); +			info["Exception Information"] = exception_info; +		} +		*/ + +		 +		// Save instruction that caused exception. +		Str_Len = 0; +		for (i = 0; i < 16; i++) +			Str_Len += wsprintf(Str + Str_Len, L" %02X", PBYTE(E.ExceptionAddress)[i]); +		info["Instruction"] = W2A(Str); + +		LLSD registers; +		registers["EAX"] = (int)C.Eax; +		registers["EBX"] = (int)C.Ebx; +		registers["ECX"] = (int)C.Ecx; +		registers["EDX"] = (int)C.Edx; +		registers["ESI"] = (int)C.Esi; +		registers["EDI"] = (int)C.Edi; +		registers["ESP"] = (int)C.Esp; +		registers["EBP"] = (int)C.Ebp; +		registers["EIP"] = (int)C.Eip; +		registers["EFlags"] = (int)C.EFlags; +		info["Registers"] = registers; +	} //if (pException) +	 +	// Save call stack info. +	Get_Call_Stack(pException, info); + +	if (Str[0] == NL[0]) +		lstrcpy(Str, Str + sizeof(NL) - 1); +	 + +	return info; +} //Get_Exception_Info + +#define UNICODE  class LLMemoryReserve { @@ -92,7 +399,6 @@ static LLMemoryReserve gEmergencyMemoryReserve;  // static  BOOL LLWinDebug::setupExceptionHandler()  { -#ifdef LL_RELEASE_FOR_DOWNLOAD  	static BOOL s_first_run = TRUE;  	// Load the dbghelp dll now, instead of waiting for the crash. @@ -119,7 +425,7 @@ BOOL LLWinDebug::setupExceptionHandler()  			msg += local_dll_name;  			msg += "!\n"; -			LLAppViewer::instance()->writeDebug(msg.c_str()); +			//write_debug(msg.c_str());  			ok = FALSE;  		} @@ -129,7 +435,7 @@ BOOL LLWinDebug::setupExceptionHandler()  			if (!f_mdwp)  			{ -				LLAppViewer::instance()->writeDebug("No MiniDumpWriteDump!\n"); +				//write_debug("No MiniDumpWriteDump!\n");  				FreeLibrary(hDll);  				hDll = NULL;  				ok = FALSE; @@ -139,76 +445,37 @@ BOOL LLWinDebug::setupExceptionHandler()  		gEmergencyMemoryReserve.reserve();  	} -	// *REMOVE: LLApp now handles the exception handing.  -	//            LLAppViewerWin32 calls SetUnhandledExceptionFilter() - -	//LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; -	//prev_filter = SetUnhandledExceptionFilter(LLWinDebug::handleException); - -	//if (s_first_run) -	//{ -	//	// We're fine, this is the first run. -	//	s_first_run = FALSE; -	//	return ok; -	//} -	//if (!prev_filter) -	//{ -	//	llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with NULL!" << llendl; -	//	ok = FALSE; -	//} -	//if (prev_filter != LLWinDebug::handleException) -	//{ -	//	llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with " << prev_filter << "!" << llendl; -	//	ok = FALSE; -	//} +	LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; +	prev_filter = SetUnhandledExceptionFilter(LLWinDebug::handleException); -	return ok; -#else -	// Internal builds don't mess with exception handling. -	return TRUE; -#endif -} +	// Try to get Tool Help library functions. +	HMODULE hKernel32; +	hKernel32 = GetModuleHandle(_T("KERNEL32")); +	CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot"); +	Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32FirstW"); +	Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32NextW"); -void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename) -{ -	if(f_mdwp == NULL)  +	if (s_first_run)  	{ -		LLAppViewer::instance()->writeDebug("No way to generate a minidump, no MiniDumpWriteDump function!\n"); +		// We're fine, this is the first run. +		s_first_run = FALSE; +		return ok;  	} -	else if(gDirUtilp == NULL) +	if (!prev_filter)  	{ -		LLAppViewer::instance()->writeDebug("No way to generate a minidump, no gDirUtilp!\n"); +		llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with NULL!" << llendl; +		ok = FALSE;  	} -	else +	if (prev_filter != LLWinDebug::handleException)  	{ -		std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, -															   filename); - -		HANDLE hFile = CreateFileA(dump_path.c_str(), -									GENERIC_WRITE, -									FILE_SHARE_WRITE, -									NULL, -									CREATE_ALWAYS, -									FILE_ATTRIBUTE_NORMAL, -									NULL); - -		if (hFile != INVALID_HANDLE_VALUE) -		{ -			// Write the dump, ignoring the return value -			f_mdwp(GetCurrentProcess(), -					GetCurrentProcessId(), -					hFile, -					type, -					ExInfop, -					NULL, -					NULL); - -			CloseHandle(hFile); -		} - +		llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with " << prev_filter << "!" << llendl; +		ok = FALSE;  	} -} +	return ok; +	// Internal builds don't mess with exception handling. +	//return TRUE; +}  // static  LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop)  { @@ -222,42 +489,35 @@ LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop)  	//  	gEmergencyMemoryReserve.release(); -	BOOL userWantsMaxiDump = -		(stricmp(gSavedSettings.getString("LastName").c_str(), "linden") == 0) -		|| (stricmp(gSavedSettings.getString("LastName").c_str(), "tester") == 0); - -	BOOL alsoSaveMaxiDump = userWantsMaxiDump && !gInProductionGrid; - -	/* Calculate alsoSaveMaxiDump here */ -  	if (exception_infop)  	{ -		_MINIDUMP_EXCEPTION_INFORMATION ExInfo; -		ExInfo.ThreadId = ::GetCurrentThreadId(); -		ExInfo.ExceptionPointers = exception_infop; -		ExInfo.ClientPointers = NULL; +		std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, +															   "SecondLifeException"); -		writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp"); +		std::string log_path = dump_path + ".log"; -		if(alsoSaveMaxiDump) -			writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp"); +		LLSD info; +		info = Get_Exception_Info(exception_infop); +		if (info) +		{ +			std::ofstream out_file(log_path.c_str()); +			LLSDSerialize::toPrettyXML(info, out_file); +			out_file.close(); +		}  	}  	else  	{ -		writeDumpToFile(MiniDumpNormal, NULL, "SecondLife.dmp"); - -		if(alsoSaveMaxiDump) -			writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), NULL, "SecondLifePlus.dmp"); -	} - -	if (!exception_infop) -	{  		// We're calling this due to a network error, not due to an actual exception.  		// It doesn't realy matter what we return.  		return EXCEPTION_CONTINUE_SEARCH;  	} +	//handle viewer crash must be called here since +	//we don't return handling of the application  +	//back to the process.  +	LLAppViewer::handleViewerCrash(); +  	//  	// At this point, we always want to exit the app.  There's no graceful  	// recovery for an unhandled exception. @@ -269,4 +529,3 @@ LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop)  }  #endif - diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index bb1f11df67..e420138216 100644 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -41,7 +41,7 @@ public:  	static BOOL setupExceptionHandler();  	static LONG WINAPI handleException(struct _EXCEPTION_POINTERS *pExceptionInfo); -	static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename); +	//static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const char *filename);  };  #endif // LL_LLWINDEBUG_H diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 36be05fe7f..e76123557c 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -972,16 +972,16 @@ void LLWorld::requestCacheMisses()  	}  } -LLString LLWorld::getInfoString() +void LLWorld::getInfo(LLSD& info)  { -	LLString info_string("World Info:\n"); +	LLSD region_info;  	for (region_list_t::iterator iter = mRegionList.begin();  		 iter != mRegionList.end(); ++iter) -	{ +	{	  		LLViewerRegion* regionp = *iter; -		info_string += regionp->getInfoString(); +		regionp->getInfo(region_info); +		info["World"].append(region_info);  	} -	return info_string;  }  void LLWorld::disconnectRegions() diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index 91685cd297..e634459acd 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -142,7 +142,7 @@ public:  	void setSpaceTimeUSec(const U64 space_time_usec);  	U64 getSpaceTimeUSec() const; -	LLString getInfoString(); +	void getInfo(LLSD& info);  public:  	typedef std::list<LLViewerRegion*> region_list_t; diff --git a/indra/newview/macutil_Prefix.h b/indra/newview/macutil_Prefix.h index f8050c8d35..145a01c702 100644 --- a/indra/newview/macutil_Prefix.h +++ b/indra/newview/macutil_Prefix.h @@ -39,3 +39,6 @@  #include <Carbon/Carbon.h> +#undef check +#undef verify +#undef require diff --git a/indra/win_crash_logger/StdAfx.h b/indra/win_crash_logger/StdAfx.h index 6f046f9820..d954823c74 100644 --- a/indra/win_crash_logger/StdAfx.h +++ b/indra/win_crash_logger/StdAfx.h @@ -52,6 +52,8 @@  #include <malloc.h>  #include <memory.h>  #include <tchar.h> +#include <atlbase.h> +  // Local Header Files diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp new file mode 100644 index 0000000000..007e2b0ed5 --- /dev/null +++ b/indra/win_crash_logger/llcrashloggerwindows.cpp @@ -0,0 +1,348 @@ +/**  +* @file llcrashloggerwindows.cpp +* @brief Windows crash logger implementation +* +* $LicenseInfo:firstyear=2003&license=viewergpl$ +*  +* Copyright (c) 2003-2007, Linden Research, Inc. +*  +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab.  Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlife.com/developers/opensource/gplv2 +*  +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlife.com/developers/opensource/flossexception +*  +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +*  +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "stdafx.h" +#include "resource.h" +#include "llcrashloggerwindows.h" + +#include <sstream> + +#include "boost/tokenizer.hpp" + +#include "dbghelp.h" +#include "indra_constants.h"	// CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME +#include "llerror.h" +#include "llfile.h" +#include "lltimer.h" +#include "llstring.h" +#include "lldxhardware.h" +#include "lldir.h" +#include "llsdserialize.h" + +#define MAX_LOADSTRING 100 +const char* const SETTINGS_FILE_HEADER = "version"; +const S32 SETTINGS_FILE_VERSION = 101; + +// Windows Message Handlers + +// Global Variables: +HINSTANCE hInst= NULL;					// current instance +TCHAR szTitle[MAX_LOADSTRING];				/* Flawfinder: ignore */		// The title bar text +TCHAR szWindowClass[MAX_LOADSTRING];		/* Flawfinder: ignore */		// The title bar text + +HWND gHwndReport = NULL;	// Send/Don't Send dialog +HWND gHwndProgress = NULL;	// Progress window +HCURSOR gCursorArrow = NULL; +HCURSOR gCursorWait = NULL; +BOOL gFirstDialog = TRUE;	// Are we currently handling the Send/Don't Send dialog? +std::stringstream gDXInfo; + +void write_debug(const char *str) +{ +	gDXInfo << str;		/* Flawfinder: ignore */ +} + +void write_debug(std::string& str) +{ +	write_debug(str.c_str()); +} + +void show_progress(const char* message) +{ +	std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message)); +	if (gHwndProgress) +	{ +		SendDlgItemMessage(gHwndProgress,       // handle to destination window  +							IDC_LOG, +							WM_SETTEXT,			// message to send +							FALSE,				// undo option +							(LPARAM)msg.c_str()); +	} +} + +void update_messages() +{ +	MSG msg; +	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) +	{ +		if (msg.message == WM_QUIT) +		{ +			exit(0); +		} +		TranslateMessage(&msg); +		DispatchMessage(&msg); +	} +} + +void sleep_and_pump_messages( U32 seconds ) +{ +	const U32 CYCLES_PER_SECOND = 10; +	U32 cycles = seconds * CYCLES_PER_SECOND; +	while( cycles-- ) +	{ +		update_messages(); +		ms_sleep(1000 / CYCLES_PER_SECOND); +	} +} + +// Include product name in the window caption. +void LLCrashLoggerWindows::ProcessCaption(HWND hWnd) +{ +	TCHAR templateText[1024];		/* Flawfinder: ignore */ +	TCHAR finalText[2048];		/* Flawfinder: ignore */ +	GetWindowText(hWnd, templateText, sizeof(templateText)); +	swprintf(finalText, sizeof(CA2T(mProductName.c_str())), templateText, CA2T(mProductName.c_str()));		/* Flawfinder: ignore */ +	SetWindowText(hWnd, finalText); +} + + +// Include product name in the diaog item text. +void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem) +{ +	TCHAR templateText[1024];		/* Flawfinder: ignore */ +	TCHAR finalText[2048];		/* Flawfinder: ignore */ +	GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); +	swprintf(finalText, sizeof(CA2T(mProductName.c_str())), templateText, CA2T(mProductName.c_str()));		/* Flawfinder: ignore */ +	SetDlgItemText(hWnd, nIDDlgItem, finalText); +} + +bool handle_button_click(WORD button_id) +{ +	USES_CONVERSION; +	// Is this something other than Send or Don't Send? +	if (button_id != IDOK +		&& button_id != IDCANCEL) +	{ +		return false; +	} + +	// See if "do this next time" is checked and save state +	S32 crash_behavior = CRASH_BEHAVIOR_ASK; +	LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0); +	if (result == BST_CHECKED) +	{ +		if (button_id == IDOK) +		{ +			crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND; +		} +		else if (button_id == IDCANCEL) +		{ +			crash_behavior = CRASH_BEHAVIOR_NEVER_SEND; +		} +		((LLCrashLoggerWindows*)LLCrashLogger::instance())->saveCrashBehaviorSetting(crash_behavior); +	} +	 +	// We're done with this dialog. +	gFirstDialog = FALSE; + +	// Send the crash report if requested +	if (button_id == IDOK) +	{ +		WCHAR wbuffer[20000]; +		GetDlgItemText(gHwndReport, // handle to dialog box +						IDC_EDIT1,  // control identifier +						wbuffer, // pointer to buffer for text +						20000 // maximum size of string +						); +		LLString user_text(T2CA(wbuffer)); +		// Activate and show the window. +		ShowWindow(gHwndProgress, SW_SHOW);  +		// Try doing this second to make the progress window go frontmost. +		ShowWindow(gHwndReport, SW_HIDE); +		((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text); +		((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs(); +	} +	// Quit the app +	LLApp::setQuitting(); +	return true; +} + + +LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ +	switch( message ) +	{ +	case WM_CREATE: +		return 0; + +	case WM_COMMAND: +		if( gFirstDialog ) +		{ +			WORD button_id = LOWORD(wParam); +			bool handled = handle_button_click(button_id); +			if (handled) +			{ +				return 0; +			} +		} +		break; + +	case WM_DESTROY: +		// Closing the window cancels +		LLApp::setQuitting(); +		PostQuitMessage(0); +		return 0; +	} + +	return DefWindowProc(hwnd, message, wParam, lParam); +} + + +LLCrashLoggerWindows::LLCrashLoggerWindows(void) +{ +} + +LLCrashLoggerWindows::~LLCrashLoggerWindows(void) +{ +} + +bool LLCrashLoggerWindows::init(void) +{	 +	bool ok = LLCrashLogger::init(); +	if(!ok) return false; + +	/* +	mbstowcs(gProductName, mProductName.c_str(), sizeof(gProductName)/sizeof(gProductName[0])); +	gProductName[ sizeof(gProductName)/sizeof(gProductName[0]) - 1 ] = 0; +	swprintf(gProductName, L"Second Life"); +	*/ + +	llinfos << "Loading dialogs" << llendl; + +	// Initialize global strings +	LoadString(mhInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); +	LoadString(mhInst, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING); + +	gCursorArrow = LoadCursor(NULL, IDC_ARROW); +	gCursorWait = LoadCursor(NULL, IDC_WAIT); + +	// Register a window class that will be used by our dialogs +	WNDCLASS wndclass; +	wndclass.style = CS_HREDRAW | CS_VREDRAW; +	wndclass.lpfnWndProc = WndProc; +	wndclass.cbClsExtra = 0; +	wndclass.cbWndExtra = DLGWINDOWEXTRA;  // Required, since this is used for dialogs! +	wndclass.hInstance = mhInst; +	wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) ); +	wndclass.hCursor = gCursorArrow; +	wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); +	wndclass.lpszMenuName = NULL; +	wndclass.lpszClassName = szWindowClass; +	RegisterClass( &wndclass ); +	 +	return true; +} + +void LLCrashLoggerWindows::gatherPlatformSpecificFiles() +{ +	updateApplication("Gathering hardware information. App may appear frozen."); +	// DX hardware probe blocks, so we can't cancel during it +	//Generate our dx_info.log file  +	SetCursor(gCursorWait); +	// At this point we're responsive enough the user could click the close button +	SetCursor(gCursorArrow); +	mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); +	mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLifeException.log"); +} + +bool LLCrashLoggerWindows::mainLoop() +{	 + +	USES_CONVERSION; + +	// Note: parent hwnd is 0 (the desktop).  No dlg proc.  See Petzold (5th ed) HexCalc example, Chapter 11, p529 +	// win_crash_logger.rc has been edited by hand. +	// Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) + +	gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); +	ProcessCaption(gHwndProgress); +	ShowWindow(gHwndProgress, SW_HIDE ); + +	if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) +	{ +		ShowWindow(gHwndProgress, SW_SHOW ); +		sendCrashLogs(); +	} +	else if (mCrashBehavior == CRASH_BEHAVIOR_ASK) +	{ +		gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PREVREPORTBOX), 0, NULL); + +		// Include the product name in the caption and various dialog items. +		ProcessCaption(gHwndReport); +		ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG); + +		// Update the header to include whether or not we crashed on the last run. +		TCHAR header[2048]; +		CA2T product(mProductName.c_str()); +		if (mCrashInPreviousExec) +		{ +			swprintf(header, _T("%s appears to have crashed or frozen the last time it ran."), product);		/* Flawfinder: ignore */ +		} +		else +		{ +			swprintf(header, _T("%s appears to have crashed."), product);		/* Flawfinder: ignore */ +		} +		SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header);		 +		ShowWindow(gHwndReport, SW_SHOW ); +		 +		MSG msg; +		while (!LLApp::isQuitting() && GetMessage(&msg, NULL, 0, 0)) +		{ +			TranslateMessage(&msg); +			DispatchMessage(&msg); +		} +		return msg.wParam; +	} +	else +	{ +		llwarns << "Unknown crash behavior " << mCrashBehavior << llendl; +		return 1; +	} +	return 0; +} + +void LLCrashLoggerWindows::updateApplication(LLString message) +{ +	LLCrashLogger::updateApplication(); +	if(message != "") show_progress(message.c_str()); +	update_messages(); +} + +bool LLCrashLoggerWindows::cleanup() +{ +	if(mSentCrashLogs) show_progress("Done"); +	else show_progress("Could not connect to servers, logs not sent"); +	sleep_and_pump_messages(3); + +	PostQuitMessage(0); +	return true; +} + diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h new file mode 100644 index 0000000000..1f5a216947 --- /dev/null +++ b/indra/win_crash_logger/llcrashloggerwindows.h @@ -0,0 +1,59 @@ +/**  +* @file llcrashloggerwindows.h +* @brief Windows crash logger definition +* +* $LicenseInfo:firstyear=2003&license=viewergpl$ +*  +* Copyright (c) 2003-2007, Linden Research, Inc. +*  +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab.  Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlife.com/developers/opensource/gplv2 +*  +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlife.com/developers/opensource/flossexception +*  +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +*  +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef LLCRASHLOGGERWINDOWS_H +#define LLCRASHLOGGERWINDOWS_H + +#include "linden_common.h" +#include "llcrashlogger.h" +#include "windows.h" +#include "llstring.h" + +class LLCrashLoggerWindows : public LLCrashLogger +{ +public: +	LLCrashLoggerWindows(void); +	~LLCrashLoggerWindows(void); +	virtual bool init(); +	virtual bool mainLoop(); +	virtual void updateApplication(LLString message = ""); +	virtual bool cleanup(); +	virtual void gatherPlatformSpecificFiles(); +	//void annotateCallStack(); +	void setHandle(HINSTANCE hInst) { mhInst = hInst; } +private: +	void ProcessDlgItemText(HWND hWnd, int nIDDlgItem); +	void ProcessCaption(HWND hWnd); +	HINSTANCE mhInst; + +}; + +#endif diff --git a/indra/win_crash_logger/resource.h b/indra/win_crash_logger/resource.h index ee6bf3d575..f1ef850f76 100644 --- a/indra/win_crash_logger/resource.h +++ b/indra/win_crash_logger/resource.h @@ -1,3 +1,34 @@ +/**  +* @file resource.h +* @brief Windows crash logger windows resources +* +* $LicenseInfo:firstyear=2003&license=viewergpl$ +*  +* Copyright (c) 2003-2007, Linden Research, Inc. +*  +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab.  Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlife.com/developers/opensource/gplv2 +*  +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlife.com/developers/opensource/flossexception +*  +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +*  +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ +  //{{NO_DEPENDENCIES}}  // Microsoft Visual C++ generated include file.  // Used by win_crash_logger.rc @@ -22,6 +53,7 @@  #define IDC_STATIC_HEADER               1007  #define IDC_STATIC_WHATINFO             1008  #define IDC_STATIC_MOTIVATION           1009 +#define IDC_STATIC_MSG                  1010  #define IDC_STATIC                      -1  // Next default values for new objects @@ -30,7 +62,7 @@  #ifndef APSTUDIO_READONLY_SYMBOLS  #define _APS_NEXT_RESOURCE_VALUE        131  #define _APS_NEXT_COMMAND_VALUE         32771 -#define _APS_NEXT_CONTROL_VALUE         1010 +#define _APS_NEXT_CONTROL_VALUE         1011  #define _APS_NEXT_SYMED_VALUE           110  #endif  #endif diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp index 266940741b..c6b4ff1c34 100644 --- a/indra/win_crash_logger/win_crash_logger.cpp +++ b/indra/win_crash_logger/win_crash_logger.cpp @@ -35,98 +35,22 @@  // Must be first include, precompiled headers.  #include "stdafx.h" -#include "linden_common.h" -#include "llcontrol.h" -#include "resource.h" +#include <stdlib.h> -#include <direct.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <wininet.h> +#include "llcrashloggerwindows.h" -#include "indra_constants.h"	// CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "lltimer.h" -#include "lldir.h" -#include "llstring.h" -#include "lldxhardware.h" - -LLControlGroup gCrashSettings;	// saved at end of session - -// Constants -#define MAX_LOADSTRING 100 -const char* const SETTINGS_FILE_HEADER = "version"; -const S32 SETTINGS_FILE_VERSION = 101; - -// Functions -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -bool handle_button_click(WORD button_id); -S32 load_crash_behavior_setting(); -bool save_crash_behavior_setting(S32 crash_behavior); -void send_crash_report(); -void write_debug(const char *str); -void write_debug(std::string& str); - -// Global Variables: -HINSTANCE hInst= NULL;					// current instance -TCHAR szTitle[MAX_LOADSTRING];				/* Flawfinder: ignore */		// The title bar text -TCHAR szWindowClass[MAX_LOADSTRING];		/* Flawfinder: ignore */		// The title bar text - -LLString gUserText;			// User's description of the problem -time_t gStartTime = 0; -HWND gHwndReport = NULL;	// Send/Don't Send dialog -HWND gHwndProgress = NULL;	// Progress window -HCURSOR gCursorArrow = NULL; -HCURSOR gCursorWait = NULL; -BOOL gFirstDialog = TRUE;	// Are we currently handling the Send/Don't Send dialog? -BOOL gCrashInPreviousExec = FALSE; -FILE *gDebugFile = NULL; -LLString gUserserver; -WCHAR gProductName[512];  //  // Implementation  // -// Include product name in the window caption. -void ProcessCaption(HWND hWnd) -{ -	TCHAR templateText[1024];		/* Flawfinder: ignore */ -	TCHAR finalText[2048];		/* Flawfinder: ignore */ -	GetWindowText(hWnd, templateText, sizeof(templateText)); -	swprintf(finalText, templateText, gProductName);		/* Flawfinder: ignore */ -	SetWindowText(hWnd, finalText); -} - - -// Include product name in the diaog item text. -void ProcessDlgItemText(HWND hWnd, int nIDDlgItem) -{ -	TCHAR templateText[1024];		/* Flawfinder: ignore */ -	TCHAR finalText[2048];		/* Flawfinder: ignore */ -	GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); -	swprintf(finalText, templateText, gProductName);		/* Flawfinder: ignore */ -	SetDlgItemText(hWnd, nIDDlgItem, finalText); -} -  int APIENTRY WinMain(HINSTANCE hInstance,                       HINSTANCE hPrevInstance,                       LPSTR     lpCmdLine,                       int       nCmdShow)  {  	llinfos << "Starting crash reporter" << llendl; -	// We assume that all the logs we're looking for reside on the current drive -	gDirUtilp->initAppDirs("SecondLife"); -	 -	// Default to the product name "Second Life" (this is overridden by the -name argument) -	swprintf(gProductName, L"Second Life");		/* Flawfinder: ignore */ - -	gCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes " -		"(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)"); - -	llinfos << "Loading crash behavior setting" << llendl; -	S32 crash_behavior = load_crash_behavior_setting();  	// In Win32, we need to generate argc and argv ourselves...  	// Note: GetCommandLine() returns a  potentially return a LPTSTR @@ -139,7 +63,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,  	const S32	MAX_ARGS = 100;  	int argc = 0; -	char *argv[MAX_ARGS];		/* Flawfinder: ignore */ +	char *argv[MAX_ARGS];		  	char *token = NULL;  	if( cmd_line_including_exe_name[0] == '\"' ) @@ -159,7 +83,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,  	{  		argv[argc++] = token;  		/* Get next token: */ -		if (*(token + strlen(token) + 1) == '\"')		/* Flawfinder: ignore */ +		if (*(token + strlen(token) + 1) == '\"')		  		{  			token = strtok( NULL, "\"");  		} @@ -169,784 +93,32 @@ int APIENTRY WinMain(HINSTANCE hInstance,  		}  	} -	S32 i; -	for (i=0; i<argc; i++) -	{ -		if(!strcmp(argv[i], "-previous")) -		{ -			llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl; -			gCrashInPreviousExec = TRUE; -		} - -		if(!strcmp(argv[i], "-dialog")) -		{ -			llinfos << "Show the user dialog" << llendl; -			crash_behavior = CRASH_BEHAVIOR_ASK; -		} - -		if(!strcmp(argv[i], "-user")) -		{ -			if ((i + 1) < argc) -			{ -				i++; -				gUserserver = argv[i]; -				llinfos << "Got userserver " << gUserserver << llendl; -			} -		} - -		if(!strcmp(argv[i], "-name")) -		{ -			if ((i + 1) < argc) -			{ -				i++; -				 -				mbstowcs(gProductName, argv[i], sizeof(gProductName)/sizeof(gProductName[0])); -				gProductName[ sizeof(gProductName)/sizeof(gProductName[0]) - 1 ] = 0; -				llinfos << "Got product name " << argv[i] << llendl; -			} -		} -	} - -	// If user doesn't want to send, bail out -	if (crash_behavior == CRASH_BEHAVIOR_NEVER_SEND) -	{ -		llinfos << "Crash behavior is never_send, quitting" << llendl; -		return 0; -	} - -	// Get the current time -	time(&gStartTime); - -	llinfos << "Loading dialogs" << llendl; - -	// Store instance handle in our global variable -	hInst = hInstance; - -	// Initialize global strings -	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); -	LoadString(hInstance, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING); - -	gCursorArrow = LoadCursor(NULL, IDC_ARROW); -	gCursorWait = LoadCursor(NULL, IDC_WAIT); - -	// Register a window class that will be used by our dialogs -	WNDCLASS wndclass; -	wndclass.style = CS_HREDRAW | CS_VREDRAW; -	wndclass.lpfnWndProc = WndProc; -	wndclass.cbClsExtra = 0; -	wndclass.cbWndExtra = DLGWINDOWEXTRA;  // Required, since this is used for dialogs! -	wndclass.hInstance = hInst; -	wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) ); -	wndclass.hCursor = gCursorArrow; -	wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); -	wndclass.lpszMenuName = NULL; -	wndclass.lpszClassName = szWindowClass; -	RegisterClass( &wndclass ); - -	// Note: parent hwnd is 0 (the desktop).  No dlg proc.  See Petzold (5th ed) HexCalc example, Chapter 11, p529 -	// win_crash_logger.rc has been edited by hand. -	// Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) - -	gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); -	ProcessCaption(gHwndProgress); -	ShowWindow(gHwndProgress, SW_HIDE ); - -	if (crash_behavior == CRASH_BEHAVIOR_ALWAYS_SEND) -	{ -		ShowWindow(gHwndProgress, SW_SHOW ); -		send_crash_report(); -		return 0; -	} - -	if (crash_behavior == CRASH_BEHAVIOR_ASK) -	{ -		gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_REPORT), 0, NULL); - -		// Include the product name in the caption and various dialog items. -		ProcessCaption(gHwndReport); -		ProcessDlgItemText(gHwndReport, IDC_STATIC_WHATINFO); -		ProcessDlgItemText(gHwndReport, IDC_STATIC_MOTIVATION); - -		// Update the header to include whether or not we crashed on the last run. -		WCHAR header[2048]; -		if (gCrashInPreviousExec) -		{ -			swprintf(header, L"%s appears to have crashed or frozen the last time it ran.", gProductName);		/* Flawfinder: ignore */ -		} -		else -		{ -			swprintf(header, L"%s appears to have crashed.", gProductName);		/* Flawfinder: ignore */ -		} -		SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header); -		ShowWindow(gHwndReport, SW_SHOW ); -		 -		MSG msg; -		while (GetMessage(&msg, NULL, 0, 0)) -		{ -			TranslateMessage(&msg); -			DispatchMessage(&msg); -		} -		return msg.wParam; -	} -	else -	{ -		llwarns << "Unknown crash behavior " << crash_behavior << llendl; -		return 1; -	} -} - - -LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) -{ -	switch( message ) -	{ -	case WM_CREATE: -		return 0; - -	case WM_COMMAND: -		if( gFirstDialog ) -		{ -			WORD button_id = LOWORD(wParam); -			bool handled = handle_button_click(button_id); -			if (handled) -			{ -				return 0; -			} -		} -		break; - -	case WM_DESTROY: -		// Closing the window cancels -		PostQuitMessage(0); -		return 0; -	} - -	return DefWindowProc(hwnd, message, wParam, lParam); -} - - -bool handle_button_click(WORD button_id) -{ -	// Is this something other than Send or Don't Send? -	if (button_id != IDOK -		&& button_id != IDCANCEL) -	{ -		return false; -	} - -	// See if "do this next time" is checked and save state -	S32 crash_behavior = CRASH_BEHAVIOR_ASK; -	LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0); -	if (result == BST_CHECKED) -	{ -		if (button_id == IDOK) -		{ -			crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND; -		} -		else if (button_id == IDCANCEL) -		{ -			crash_behavior = CRASH_BEHAVIOR_NEVER_SEND; -		} -	} -	bool success = save_crash_behavior_setting(crash_behavior); -	if (!success) -	{ -		llwarns << "Failed to save crash settings" << llendl; -	} - -	// We're done with this dialog. -	gFirstDialog = FALSE; - -	// Send the crash report if requested -	if (button_id == IDOK) -	{ -		// Don't let users type anything.  They believe the reports -		// get read by humans, and get angry when we don't respond. JC -		//WCHAR wbuffer[20000]; -		//GetDlgItemText(gHwndReport, // handle to dialog box -		//				IDC_EDIT1,  // control identifier -		//				wbuffer, // pointer to buffer for text -		//				20000 // maximum size of string -		//				); -		//gUserText = wstring_to_utf8str(utf16str_to_wstring(wbuffer)).c_str(); -		//llinfos << gUserText << llendl; - -		// Activate and show the window. -		ShowWindow(gHwndProgress, SW_SHOW);  -		// Try doing this second to make the progress window go frontmost. -		ShowWindow(gHwndReport, SW_HIDE); - -		send_crash_report(); -	} - -	// Quit the app -	PostQuitMessage(0); - -	return true; -} - - -class LLFileEncoder -{ -public: -	LLFileEncoder(const char *formname, const char *filename); -	~LLFileEncoder(); - -	BOOL isValid() const { return mIsValid; } -	LLString encodeURL(const S32 max_length = 0); -public: -	BOOL mIsValid; -	LLString mFilename; -	LLString mFormname; -	S32 mBufLength; -	U8 *mBuf; -}; - -LLString encode_string(const char *formname, const LLString &str); - -void update_messages() -{ -	MSG msg; -	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) -	{ -		if (msg.message == WM_QUIT) -		{ -			exit(0); -		} -		TranslateMessage(&msg); -		DispatchMessage(&msg); -	} -} - -void sleep_and_pump_messages( U32 seconds ) -{ -	const U32 CYCLES_PER_SECOND = 10; -	U32 cycles = seconds * CYCLES_PER_SECOND; -	while( cycles-- ) +	LLCrashLoggerWindows app; +	bool ok = app.parseCommandOptions(argc, argv); +	if(!ok)  	{ -		update_messages(); -		ms_sleep(1000 / CYCLES_PER_SECOND); -	} -} - - -void show_progress(const char* message) -{ -	std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message)); -	if (gHwndProgress) -	{ -		SendDlgItemMessage(gHwndProgress,       // handle to destination window  -							IDC_LOG, -							WM_SETTEXT,			// message to send -							FALSE,				// undo option -							(LPARAM)msg.c_str()); -	} -} - - -void send_crash_report() -{ -	update_messages(); -	show_progress("Starting up..."); -	update_messages(); - -	const S32 SL_MAX_SIZE = 100000;			// Maximum size of the Second Life log file. - -	update_messages(); - -	// Lots of silly variable, replicated for each log file. -	std::string db_file_name; // debug.log -	std::string sl_file_name; // SecondLife.log -	std::string md_file_name; // minidump (SecondLife.dmp) file name -	std::string st_file_name; // stats.log file -	std::string si_file_name; // settings.ini file -	std::string ml_file_name; // message.log file - -	LLFileEncoder *db_filep = NULL; -	LLFileEncoder *sl_filep = NULL; -	LLFileEncoder *st_filep = NULL; -	LLFileEncoder *md_filep = NULL; -	LLFileEncoder *si_filep = NULL; -	LLFileEncoder *ml_filep = NULL; - -	// DX hardware probe blocks, so we can't cancel during it -	SetCursor(gCursorWait); - -	// Need to do hardware detection before we grab the files, otherwise we don't send the debug log updates -	// to the server (including the list of hardware). -	update_messages(); -	show_progress("Detecting hardware, please wait..."); -	update_messages(); -	gDXHardware.setWriteDebugFunc(write_debug); -	gDXHardware.getInfo(FALSE); -	update_messages(); -	gDXHardware.dumpDevices(); -	update_messages(); -	fclose(gDebugFile); -	gDebugFile = NULL; - -	// At this point we're responsive enough the user could click the close button -	SetCursor(gCursorArrow); - -	/////////////////////////////////// -	// -	// We do the parsing for the debug_info file first, as that will -	// give us the location of the SecondLife.log file. -	// - -	// Figure out the filename of the debug log -	db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); -	db_filep = new LLFileEncoder("DB", db_file_name.c_str()); - -	// Get the filename of the SecondLife.log file -	// *NOTE: This buffer size is hard coded into scanf() below. -	char tmp_sl_name[256];		/* Flawfinder: ignore */ -	tmp_sl_name[0] = '\0'; - -	update_messages(); -	show_progress("Looking for files..."); -	update_messages(); - -	// Look for it in the debug_info.log file -	if (db_filep->isValid()) -	{ -		sscanf( -			(const char*)db_filep->mBuf, -			"SL Log: %255[^\r\n]", -			tmp_sl_name); -	} -	else -	{ -		delete db_filep; -		db_filep = NULL; -	} - -	if (gCrashInPreviousExec) -	{ -		// If we froze, the crash log this time around isn't useful.  Use the -		// old one. -		sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); -	} -	else if (tmp_sl_name[0]) -	{ -		// If debug_info.log gives us a valid log filename, use that. -		sl_file_name = tmp_sl_name; -		llinfos << "Using log file from debug log " << sl_file_name << llendl; -	} -	else -	{ -		// Figure out the filename of the default second life log -		sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log"); -	} - -	// Now we get the SecondLife.log file if it's there -	sl_filep = new LLFileEncoder("SL", sl_file_name.c_str()); -	if (!sl_filep->isValid()) -	{ -		delete sl_filep; -		sl_filep = NULL; -	} - -	update_messages(); -	show_progress("Looking for stats file..."); -	update_messages(); - -	st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log"); -	st_filep = new LLFileEncoder("ST", st_file_name.c_str()); -	if (!st_filep->isValid()) -	{ -		delete st_filep; -		st_filep = NULL; -	} - -	si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.ini"); -	si_filep = new LLFileEncoder("SI", si_file_name.c_str()); -	if (!si_filep->isValid()) -	{ -		delete si_filep; -		si_filep = NULL; -	} - -	// Now we get the minidump -	md_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.dmp"); -	md_filep = new LLFileEncoder("MD", md_file_name.c_str()); -	if (!md_filep->isValid()) -	{		 -		delete md_filep; -		md_filep = NULL; -	} - -	// Now we get the message log -	ml_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"message.log"); -	ml_filep = new LLFileEncoder("ML", ml_file_name.c_str()); -	if (!ml_filep->isValid()) -	{		 -		delete ml_filep; -		ml_filep = NULL; -	} - -	LLString post_data; -	LLString tmp_url_buf; - -	// Append the userserver -	tmp_url_buf = encode_string("USER", gUserserver); -	post_data += tmp_url_buf; -	llinfos << "PostData:" << post_data << llendl; - -	if (gCrashInPreviousExec) -	{ -		post_data.append(1, '&'); -		tmp_url_buf = encode_string("EF", "Y"); -		post_data += tmp_url_buf; -	} - -	update_messages(); -	show_progress("Encoding data"); -	update_messages(); -	if (db_filep) -	{ -		post_data.append(1, '&'); -		tmp_url_buf = db_filep->encodeURL(); -		post_data += tmp_url_buf; -		llinfos << "Sending DB log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending DB log file" << llendl; -	} -	show_progress("Encoding data."); -	update_messages(); - -	if (sl_filep) -	{ -		post_data.append(1, '&'); -		tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE); -		post_data += tmp_url_buf; -		llinfos << "Sending SL log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending SL log file" << llendl; -	} -	show_progress("Encoding data.."); -	update_messages(); - -	if (st_filep) -	{ -		post_data.append(1, '&'); -		tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE); -		post_data += tmp_url_buf; -		llinfos << "Sending stats log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending stats log file" << llendl; -	} -	show_progress("Encoding data..."); -	update_messages(); - -	if (md_filep) -	{ -		post_data.append(1, '&'); -		tmp_url_buf = md_filep->encodeURL(); -		post_data += tmp_url_buf; -		llinfos << "Sending minidump log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending minidump log file" << llendl; -	} -	show_progress("Encoding data...."); -	update_messages(); - -	if (si_filep) -	{ -		post_data.append(1, '&'); -		tmp_url_buf = si_filep->encodeURL(); -		post_data += tmp_url_buf; -		llinfos << "Sending settings log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending settings.ini file" << llendl; -	} -	show_progress("Encoding data...."); -	update_messages(); - -	if (ml_filep) -	{ -		post_data.append(1, '&'); -		tmp_url_buf = ml_filep->encodeURL(SL_MAX_SIZE); -		post_data += tmp_url_buf; -		llinfos << "Sending message log file" << llendl; -	} -	else -	{ -		llinfos << "Not sending message.log file" << llendl; -	} -	show_progress("Encoding data...."); -	update_messages(); - -	if (gUserText.size()) -	{ -		post_data.append(1, '&'); -		tmp_url_buf = encode_string("UN", gUserText); -		post_data += tmp_url_buf; -	} - -	delete db_filep; -	db_filep = NULL; -	delete sl_filep; -	sl_filep = NULL; -	delete md_filep; -	md_filep = NULL; - -	// Post data to web server -	const S32 BUFSIZE = 65536; -	HINTERNET hinet, hsession, hrequest; -	char data[BUFSIZE];		/* Flawfinder: ignore */ -	unsigned long bytes_read; - -	llinfos << "Connecting to crash report server" << llendl; -	update_messages(); -	show_progress("Connecting to server..."); -	update_messages(); - -	// Init wininet subsystem -	hinet = InternetOpen(L"LindenCrashReporter", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); -	if (hinet == NULL) -	{ -		llinfos << "Couldn't open connection" << llendl; -		sleep_and_pump_messages( 5 ); -//		return FALSE; -	} - -	hsession = InternetConnect(hinet, -								L"secondlife.com", -								INTERNET_DEFAULT_HTTP_PORT, -								NULL, -								NULL, -								INTERNET_SERVICE_HTTP, -								NULL, -								NULL); - -	if (!hsession) -	{ -		llinfos << "Couldn't talk to crash report server" << llendl; -	} - -	hrequest = HttpOpenRequest(hsession, L"POST", L"/cgi-bin/viewer_crash_reporter2", NULL, L"", NULL, 0, 0); -	if (!hrequest) -	{ -		llinfos << "Couldn't open crash report URL!" << llendl; +		llwarns << "Unable to parse command line." << llendl;  	} -	llinfos << "Transmitting data" << llendl; -	llinfos << "Bytes: " << (post_data.size()) << llendl; - -	update_messages(); -	show_progress("Transmitting data..."); -	update_messages(); - -	BOOL ok = HttpSendRequest(hrequest, NULL, 0, (void *)(post_data.c_str()), post_data.size()); -	if (!ok) -	{ -		llinfos << "Error posting data!" << llendl; -		sleep_and_pump_messages( 5 ); -	} - -	llinfos << "Response from crash report server:" << llendl; -	do -	{ -		if (InternetReadFile(hrequest, data, BUFSIZE, &bytes_read)) -		{ -			if (bytes_read == 0) -			{ -				// If InternetFileRead returns TRUE AND bytes_read == 0 -				// we've successfully downloaded the entire file -				break; -			} -			else -			{ -				data[bytes_read] = 0; -				llinfos << data << llendl; -			} -		} -		else -		{ -			llinfos << "Couldn't read file!" << llendl; -			sleep_and_pump_messages( 5 ); -//			return FALSE; -		} -	} while(TRUE); - -	InternetCloseHandle(hrequest); -	InternetCloseHandle(hsession); -	InternetCloseHandle(hinet); -	update_messages(); -	show_progress("Done."); -	sleep_and_pump_messages( 3 ); -//	return TRUE; -} - -LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename) -{ -	mFormname = form_name; -	mFilename = filename; -	mIsValid = FALSE; -	mBuf = NULL; - -	int res; -	 -	llstat stat_data; -	res = LLFile::stat(mFilename.c_str(), &stat_data); -	if (res) -	{ -		llwarns << "File " << mFilename << " is missing!" << llendl; -		return; -	} - -	FILE *fp = NULL; -	S32 buf_size = 0; -	S32 count = 0; -	while (count < 5) -	{ -		buf_size = stat_data.st_size; -		fp = LLFile::fopen(mFilename.c_str(), "rb");		/* Flawfinder: ignore */ -		if (!fp) -		{ -			llwarns << "Can't open file " << mFilename << ", wait for a second" << llendl; -			// Couldn't open the file, wait a bit and try again -			count++; -			ms_sleep(1000); -		} -		else -		{ -			break; -		} -	} -	if (!fp) -	{ -		return; -	} -	U8 *buf = new U8[buf_size + 1]; -	fread(buf, 1, buf_size, fp); -	fclose(fp); - -	mBuf = buf; -	mBufLength = buf_size; - -	mIsValid = TRUE; -} - -LLFileEncoder::~LLFileEncoder() -{ -	if (mBuf) -	{ -		delete mBuf; -		mBuf = NULL; -	} -} - -LLString LLFileEncoder::encodeURL(const S32 max_length) -{ -	LLString result = mFormname; -	result.append(1, '='); - -	S32 i = 0; - -	if (max_length) -	{ -		if (mBufLength > max_length) -		{ -			i = mBufLength - max_length; -		} -	} - -	S32 url_buf_size = 3*mBufLength + 1; -	char *url_buf = new char[url_buf_size]; - -	S32 cur_pos = 0; -	for (; i < mBufLength; i++) +	app.setHandle(hInstance); +	ok = app.init(); +	if(!ok)  	{ -		S32 byte_val = mBuf[i]; -		sprintf(url_buf + cur_pos, "%%%02x", byte_val); -		cur_pos += 3; +		llwarns << "Unable to initialize application." << llendl; +		return -1;  	} -	url_buf[i*3] = 0; -	result.append(url_buf); -	delete[] url_buf; -	return result; -} - -LLString encode_string(const char *formname, const LLString &str) -{ -	LLString result = formname; -	result.append(1, '='); -	// Not using LLString because of bad performance issues -	S32 buf_size = str.size(); -	S32 url_buf_size = 3*str.size() + 1; -	char *url_buf = new char[url_buf_size]; +		// Run the application main loop +	if(!LLApp::isQuitting()) app.mainLoop(); -	S32 cur_pos = 0; -	S32 i; -	for (i = 0; i < buf_size; i++) +	if (!app.isError())  	{ -		sprintf(url_buf + cur_pos, "%%%02x", str[i]); -		cur_pos += 3; +		// +		// We don't want to do cleanup here if the error handler got called - +		// the assumption is that the error handler is responsible for doing +		// app cleanup if there was a problem. +		// +		app.cleanup();  	} -	url_buf[i*3] = 0; - -	result.append(url_buf); -	delete[] url_buf; -	return result; -} - -void write_debug(const char *str) -{ -	if (!gDebugFile) -	{ -		std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); -		llinfos << "Opening debug file " << debug_filename << llendl; -		gDebugFile = LLFile::fopen(debug_filename.c_str(), "a+");		/* Flawfinder: ignore */ -        if (!gDebugFile) -        { -            fprintf(stderr, "Couldn't open %s: debug log to stderr instead.\n", debug_filename.c_str()); -            gDebugFile = stderr; -        } -	} -	fprintf(gDebugFile, str);		/* Flawfinder: ignore */ -	fflush(gDebugFile); -} - -void write_debug(std::string& str) -{ -	write_debug(str.c_str()); -} - -S32 load_crash_behavior_setting() -{ -	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - -	gCrashSettings.loadFromFile(filename); -		 -	S32 value = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); -	 -	if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK; - -	return value; -} - -bool save_crash_behavior_setting(S32 crash_behavior) -{ -	if (crash_behavior < CRASH_BEHAVIOR_ASK) return false; -	if (crash_behavior > CRASH_BEHAVIOR_NEVER_SEND) return false; - -	gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior); -	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - -	gCrashSettings.saveToFile(filename, FALSE); - -	return true; +	return 0;  } diff --git a/indra/win_crash_logger/win_crash_logger.rc b/indra/win_crash_logger/win_crash_logger.rc index 2c46859b95..2819722f63 100644 --- a/indra/win_crash_logger/win_crash_logger.rc +++ b/indra/win_crash_logger/win_crash_logger.rc @@ -56,13 +56,13 @@ END  // Dialog  // -IDD_PROGRESS DIALOG  100, 100, 186, 33 +IDD_PROGRESS DIALOGEX 100, 100, 234, 33  STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU  CAPTION "%s Crash Logger"  CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x0  BEGIN -    LTEXT           "Static",IDC_LOG,7,7,172,8 +    LTEXT           "Static",IDC_LOG,7,7,220,8  END  IDD_REPORT DIALOGEX 100, 100, 297, 125 @@ -73,48 +73,33 @@ FONT 8, "MS Sans Serif", 0, 0, 0x0  BEGIN      DEFPUSHBUTTON   "Send",IDOK,198,104,45,15,WS_GROUP      PUSHBUTTON      "Don't Send",IDCANCEL,247,104,45,15,WS_GROUP -    LTEXT           "%s appears to have crashed.",IDC_STATIC_HEADER,4,4,288, -                    14 -    LTEXT           "This crash reporter collects information about your computer's hardware, operating system, and some %s logs, which are used for debugging purposes only.", -                    IDC_STATIC_WHATINFO,4,23,288,19,NOT WS_GROUP -    CONTROL         "Remember this choice",IDC_CHECK_AUTO,"Button", -                    BS_AUTOCHECKBOX | WS_TABSTOP,4,106,89,13 -    LTEXT           "Sending crash reports is the best way to help us improve the quality of %s.", -                    IDC_STATIC_MOTIVATION,4,38,288,8 -    LTEXT           "If you continue to experience this problem, please try:", -                    IDC_STATIC,4,57,251,8 -    LTEXT           "- Contacting support by visiting http://www.secondlife.com/support", -                    IDC_STATIC,4,67,231,8 +    LTEXT           "%s appears to have crashed.",IDC_STATIC_HEADER,4,4,288,14 +    LTEXT           "This crash reporter collects information about your computer's hardware, operating system, and some %s logs, which are used for debugging purposes only.",IDC_STATIC_WHATINFO,4,23,288,19,NOT WS_GROUP +    CONTROL         "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,106,89,13 +    LTEXT           "Sending crash reports is the best way to help us improve the quality of %s.",IDC_STATIC_MOTIVATION,4,43,288,8 +    LTEXT           "If you continue to experience this problem, please try:",IDC_STATIC,4,57,251,8 +    LTEXT           "- Contacting support by visiting http://www.secondlife.com/support",IDC_STATIC,4,67,231,8  END -IDD_PREVREPORTBOX DIALOG  100, 100, 232, 213 +IDD_PREVREPORTBOX DIALOGEX 100, 100, 232, 213  STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU  CAPTION "%s Crash Logger"  CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x0  BEGIN -    DEFPUSHBUTTON   "OK",IDOK,131,193,45,15,WS_GROUP -    EDITTEXT        IDC_EDIT1,4,102,223,89,ES_MULTILINE | ES_WANTRETURN |  -                    WS_VSCROLL -    PUSHBUTTON      "Cancel",IDCANCEL,181,193,45,15,WS_GROUP -    LTEXT           "%s appears to have crashed or frozen the last time it ran.", -                    IDC_STATIC,4,4,214,8 -    LTEXT           "This crash reporter collects information about your computer's", -                    IDC_STATIC,4,17,201,8 -    LTEXT           "hardware configuration, operating system, and some %s", -                    IDC_STATIC,4,25,212,8 -    LTEXT           "logs, all of which are used for debugging purposes only.", -                    IDC_STATIC,4,33,210,8 -    LTEXT           "In the space below, please briefly describe what you were doing", -                    IDC_STATIC,3,48,208,8 -    LTEXT           "or trying to do just prior to the crash.",IDC_STATIC,3, -                    56,204,8 -    LTEXT           "If you don't wish to send Linden Lab a crash report, press Cancel.", -                    IDC_STATIC,3,90,214,8 -    LTEXT           "This report is NOT read by customer support.  If you have billing or", -                    IDC_STATIC,3,68,208,8 -    LTEXT           "other questions, please go to: www.secondlife.com/support", -                    IDC_STATIC,3,76,206,8 +    DEFPUSHBUTTON   "Send Report",IDOK,131,193,45,15,WS_GROUP +    EDITTEXT        IDC_EDIT1,3,100,223,89,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL +    PUSHBUTTON      "Don't Send",IDCANCEL,181,193,45,15,WS_GROUP +    LTEXT           "%s appears to have crashed or frozen the last time it ran.",IDC_STATIC_HEADER,4,4,214,8 +    LTEXT           "This crash reporter collects information about your computer's",IDC_STATIC,4,17,201,8 +    LTEXT           "hardware configuration, operating system, and some %s",IDC_STATIC_MSG,4,25,212,8 +    LTEXT           "logs, all of which are used for debugging purposes only.",IDC_STATIC,4,33,210,8 +    LTEXT           "In the space below, please briefly describe what you were doing",IDC_STATIC,3,48,208,8 +    LTEXT           "or trying to do just prior to the crash.",IDC_STATIC,3,56,204,8 +    LTEXT           "If you don't wish to send Linden Lab a crash report, press Don't Send.",IDC_STATIC,3,90,223,8 +    LTEXT           "This report is NOT read by customer support.  If you have billing or",IDC_STATIC,3,68,208,8 +    LTEXT           "other questions, please go to: www.secondlife.com/support",IDC_STATIC,3,76,206,8 +    CONTROL         "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,193,89,13  END @@ -158,7 +143,7 @@ BEGIN      IDD_PROGRESS, DIALOG      BEGIN          LEFTMARGIN, 7 -        RIGHTMARGIN, 179 +        RIGHTMARGIN, 227          TOPMARGIN, 7          BOTTOMMARGIN, 26      END | 
