mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-04 23:08:39 +09:00
Merge remote-tracking branch 'origin/master' into custom
This commit is contained in:
commit
51fa1b8bdb
983 changed files with 5371 additions and 280531 deletions
|
|
@ -290,7 +290,7 @@ MAKE_SYM_STORE_PATH := $(DIST)/bin
|
|||
endif
|
||||
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
|
||||
endif
|
||||
ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
|
||||
ifeq (,$(filter-out Linux,$(OS_ARCH)))
|
||||
MAKE_SYM_STORE_ARGS := -c --vcs-info
|
||||
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
|
||||
MAKE_SYM_STORE_PATH := $(DIST)/bin
|
||||
|
|
|
|||
|
|
@ -60,11 +60,7 @@ struct GnomeAccessibilityModule
|
|||
};
|
||||
|
||||
static GnomeAccessibilityModule sAtkBridge = {
|
||||
#ifdef AIX
|
||||
"libatk-bridge.a(libatk-bridge.so.0)", nullptr,
|
||||
#else
|
||||
"libatk-bridge.so", nullptr,
|
||||
#endif
|
||||
"gnome_accessibility_module_init", nullptr,
|
||||
"gnome_accessibility_module_shutdown", nullptr
|
||||
};
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ const nsIPropertyElement = Components.interfaces.nsIPropertyElement;
|
|||
|
||||
const MAC = (navigator.platform.indexOf("Mac") != -1);
|
||||
const LINUX = (navigator.platform.indexOf("Linux") != -1);
|
||||
const SOLARIS = (navigator.platform.indexOf("SunOS") != -1);
|
||||
const WIN = (navigator.platform.indexOf("Win") != -1);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
// nsIAccessible::name
|
||||
var applicationName = "";
|
||||
if (LINUX || SOLARIS) {
|
||||
if (LINUX) {
|
||||
applicationName = appInfo.name;
|
||||
} else {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@
|
|||
*/
|
||||
function getMenuTree1()
|
||||
{
|
||||
if (LINUX || SOLARIS) {
|
||||
if (LINUX) {
|
||||
var tree = {
|
||||
role: ROLE_MENUPOPUP,
|
||||
children: [
|
||||
|
|
@ -190,7 +190,7 @@
|
|||
function getMenuTree2()
|
||||
{
|
||||
var tree = getMenuTree1();
|
||||
if (LINUX || SOLARIS) {
|
||||
if (LINUX) {
|
||||
var submenuTree =
|
||||
{
|
||||
name: "item2.0",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
children: []
|
||||
};
|
||||
|
||||
if (LINUX || SOLARIS)
|
||||
if (LINUX)
|
||||
tree.children[2].children[0].children.push(subsubmenuTree);
|
||||
else
|
||||
tree.children[2].children[0].children[0].children[0].children.push(subsubmenuTree);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
this.invoke = function openMenu_invoke()
|
||||
{
|
||||
var tree;
|
||||
if (LINUX || SOLARIS) {
|
||||
if (LINUX) {
|
||||
tree =
|
||||
{ PARENT_MENUITEM: [ ] };
|
||||
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
this.finalCheck = function openMenu_finalCheck()
|
||||
{
|
||||
var tree;
|
||||
if (LINUX || SOLARIS) {
|
||||
if (LINUX) {
|
||||
tree =
|
||||
{ PARENT_MENUITEM: [
|
||||
{ MENUITEM: [ ] },
|
||||
|
|
|
|||
|
|
@ -725,13 +725,6 @@
|
|||
@RESPATH@/components/pipnss.xpt
|
||||
@RESPATH@/components/pippki.xpt
|
||||
|
||||
; for Solaris SPARC
|
||||
#ifdef SOLARIS
|
||||
bin/libfreebl_32fpu_3.so
|
||||
bin/libfreebl_32int_3.so
|
||||
bin/libfreebl_32int64_3.so
|
||||
#endif
|
||||
|
||||
; [Updater]
|
||||
;
|
||||
#ifdef MOZ_UPDATER
|
||||
|
|
|
|||
|
|
@ -318,13 +318,6 @@
|
|||
@RESPATH@/chrome/pippki@JAREXT@
|
||||
@RESPATH@/chrome/pippki.manifest
|
||||
|
||||
; for Solaris SPARC
|
||||
#ifdef SOLARIS
|
||||
bin/libfreebl_32fpu_3.so
|
||||
bin/libfreebl_32int_3.so
|
||||
bin/libfreebl_32int64_3.so
|
||||
#endif
|
||||
|
||||
; [Updater]
|
||||
;
|
||||
#ifdef MOZ_UPDATER
|
||||
|
|
|
|||
|
|
@ -1608,7 +1608,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
}
|
||||
|
||||
/* When the tab bar is collapsed, show a 1px border in its place. */
|
||||
#TabsToolbar[collapsed="true"] {
|
||||
#TabsToolbar[tabsontop="false"][collapsed="true"] {
|
||||
visibility: visible;
|
||||
height: 1px;
|
||||
border-bottom-width: 1px;
|
||||
|
|
|
|||
|
|
@ -1631,7 +1631,7 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
|
|||
}
|
||||
|
||||
/* When the tab bar is collapsed, show a 1px border in its place. */
|
||||
#TabsToolbar[collapsed="true"] {
|
||||
#TabsToolbar[tabsontop="false"][collapsed="true"] {
|
||||
visibility: visible;
|
||||
height: 1px;
|
||||
border-bottom-width: 1px;
|
||||
|
|
|
|||
|
|
@ -1844,7 +1844,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
}
|
||||
|
||||
/* When the tab bar is collapsed, show a 1px border in its place. */
|
||||
#TabsToolbar[collapsed="true"] {
|
||||
#TabsToolbar[tabsontop="false"][collapsed="true"] {
|
||||
visibility: visible;
|
||||
height: 1px;
|
||||
border-bottom-width: 1px;
|
||||
|
|
|
|||
|
|
@ -89,7 +89,6 @@ flavors = {
|
|||
'Android': 'android',
|
||||
'Linux': 'linux',
|
||||
'Darwin': 'mac' if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa' else 'ios',
|
||||
'SunOS': 'solaris',
|
||||
'GNU/kFreeBSD': 'freebsd',
|
||||
'DragonFly': 'dragonfly',
|
||||
'FreeBSD': 'freebsd',
|
||||
|
|
|
|||
19
config/external/nss/Makefile.in
vendored
19
config/external/nss/Makefile.in
vendored
|
|
@ -43,20 +43,6 @@ endif
|
|||
# Default
|
||||
HAVE_FREEBL_LIBS = 1
|
||||
|
||||
# SunOS SPARC
|
||||
ifeq ($(OS_ARCH), SunOS)
|
||||
ifneq (86,$(findstring 86,$(OS_TEST)))
|
||||
ifdef HAVE_64BIT_BUILD
|
||||
HAVE_FREEBL_LIBS =
|
||||
HAVE_FREEBL_LIBS_64 = 1
|
||||
else
|
||||
HAVE_FREEBL_LIBS =
|
||||
HAVE_FREEBL_LIBS_32FPU = 1
|
||||
HAVE_FREEBL_LIBS_32INT64 = 1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),Linux)
|
||||
HAVE_FREEBL_LIBS =
|
||||
HAVE_FREEBL_LIBS_PRIV = 1
|
||||
|
|
@ -331,11 +317,6 @@ NSS_DIST_DLL_DEST := $(DIST)/bin
|
|||
NSS_DIST_DLL_TARGET := target
|
||||
INSTALL_TARGETS += NSS_DIST_DLL
|
||||
|
||||
ifeq ($(OS_ARCH)_$(1), SunOS_softokn3)
|
||||
# has to use copy mode on Solaris, see #665509
|
||||
$(DIST)/bin/$(DLL_PREFIX)softokn3$(DLL_SUFFIX): INSTALL := $(INSTALL) -t
|
||||
endif
|
||||
|
||||
NSS_SDK_LIB_FILES := \
|
||||
$(addprefix $(DIST)/lib/$(LIB_PREFIX),$(addsuffix .$(LIB_SUFFIX),$(SDK_LIBS))) \
|
||||
$(addprefix $(DIST)/bin/$(DLL_PREFIX),$(addsuffix $(DLL_SUFFIX),$(NSS_DLLS))) \
|
||||
|
|
|
|||
|
|
@ -386,15 +386,6 @@ endif
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),AIX)
|
||||
ifdef IS_COMPONENT
|
||||
ifneq ($(HAS_EXTRAEXPORTS),1)
|
||||
MKSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
|
||||
MKCSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
|
||||
endif # HAS_EXTRAEXPORTS
|
||||
endif # IS_COMPONENT
|
||||
endif # AIX
|
||||
|
||||
#
|
||||
# Linux: add -Bsymbolic flag for components
|
||||
#
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -123,9 +123,9 @@ extern "C" {
|
|||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.26.0"
|
||||
#define SQLITE_VERSION_NUMBER 3026000
|
||||
#define SQLITE_SOURCE_ID "2018-12-01 12:34:55 bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238b4f9"
|
||||
#define SQLITE_VERSION "3.27.2"
|
||||
#define SQLITE_VERSION_NUMBER 3027002
|
||||
#define SQLITE_SOURCE_ID "2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
|
|
@ -823,6 +823,15 @@ struct sqlite3_io_methods {
|
|||
** file space based on this hint in order to help writes to the database
|
||||
** file run faster.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_SIZE_LIMIT]]
|
||||
** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that
|
||||
** implements [sqlite3_deserialize()] to set an upper bound on the size
|
||||
** of the in-memory database. The argument is a pointer to a [sqlite3_int64].
|
||||
** If the integer pointed to is negative, then it is filled in with the
|
||||
** current limit. Otherwise the limit is set to the larger of the value
|
||||
** of the integer pointed to and the current database size. The integer
|
||||
** pointed to is set to the new limit.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_CHUNK_SIZE]]
|
||||
** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
|
||||
** extends and truncates the database file in chunks of a size specified
|
||||
|
|
@ -1131,6 +1140,7 @@ struct sqlite3_io_methods {
|
|||
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
|
||||
#define SQLITE_FCNTL_LOCK_TIMEOUT 34
|
||||
#define SQLITE_FCNTL_DATA_VERSION 35
|
||||
#define SQLITE_FCNTL_SIZE_LIMIT 36
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
|
|
@ -1972,6 +1982,17 @@ struct sqlite3_mem_methods {
|
|||
** negative value for this option restores the default behaviour.
|
||||
** This option is only available if SQLite is compiled with the
|
||||
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
|
||||
**
|
||||
** [[SQLITE_CONFIG_MEMDB_MAXSIZE]]
|
||||
** <dt>SQLITE_CONFIG_MEMDB_MAXSIZE
|
||||
** <dd>The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter
|
||||
** [sqlite3_int64] parameter which is the default maximum size for an in-memory
|
||||
** database created using [sqlite3_deserialize()]. This default maximum
|
||||
** size can be adjusted up or down for individual databases using the
|
||||
** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this
|
||||
** configuration setting is never used, then the default maximum is determined
|
||||
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
|
||||
** compile-time option is not set, then the default maximum is 1073741824.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
|
||||
|
|
@ -2002,6 +2023,7 @@ struct sqlite3_mem_methods {
|
|||
#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
|
||||
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
|
||||
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
|
||||
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Configuration Options
|
||||
|
|
@ -2347,7 +2369,7 @@ SQLITE_API int sqlite3_changes(sqlite3*);
|
|||
** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
|
||||
** are not counted.
|
||||
**
|
||||
** This the [sqlite3_total_changes(D)] interface only reports the number
|
||||
** The [sqlite3_total_changes(D)] interface only reports the number
|
||||
** of rows that changed due to SQL statement run against database
|
||||
** connection D. Any changes by other database connections are ignored.
|
||||
** To detect changes against a database file from other database
|
||||
|
|
@ -2991,9 +3013,9 @@ SQLITE_API int sqlite3_set_authorizer(
|
|||
** time is in units of nanoseconds, however the current implementation
|
||||
** is only capable of millisecond resolution so the six least significant
|
||||
** digits in the time are meaningless. Future versions of SQLite
|
||||
** might provide greater resolution on the profiler callback. The
|
||||
** sqlite3_profile() function is considered experimental and is
|
||||
** subject to change in future versions of SQLite.
|
||||
** might provide greater resolution on the profiler callback. Invoking
|
||||
** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the
|
||||
** profile callback.
|
||||
*/
|
||||
SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
|
||||
void(*xTrace)(void*,const char*), void*);
|
||||
|
|
@ -3407,6 +3429,8 @@ SQLITE_API int sqlite3_open_v2(
|
|||
** is not a database file pathname pointer that SQLite passed into the xOpen
|
||||
** VFS method, then the behavior of this routine is undefined and probably
|
||||
** undesirable.
|
||||
**
|
||||
** See the [URI filename] documentation for additional information.
|
||||
*/
|
||||
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
|
||||
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
|
||||
|
|
@ -3629,18 +3653,23 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
|||
** deplete the limited store of lookaside memory. Future versions of
|
||||
** SQLite may act on this hint differently.
|
||||
**
|
||||
** [[SQLITE_PREPARE_NORMALIZE]] ^(<dt>SQLITE_PREPARE_NORMALIZE</dt>
|
||||
** <dd>The SQLITE_PREPARE_NORMALIZE flag indicates that a normalized
|
||||
** representation of the SQL statement should be calculated and then
|
||||
** associated with the prepared statement, which can be obtained via
|
||||
** the [sqlite3_normalized_sql()] interface.)^ The semantics used to
|
||||
** normalize a SQL statement are unspecified and subject to change.
|
||||
** At a minimum, literal values will be replaced with suitable
|
||||
** placeholders.
|
||||
** [[SQLITE_PREPARE_NORMALIZE]] <dt>SQLITE_PREPARE_NORMALIZE</dt>
|
||||
** <dd>The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used
|
||||
** to be required for any prepared statement that wanted to use the
|
||||
** [sqlite3_normalized_sql()] interface. However, the
|
||||
** [sqlite3_normalized_sql()] interface is now available to all
|
||||
** prepared statements, regardless of whether or not they use this
|
||||
** flag.
|
||||
**
|
||||
** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt>
|
||||
** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
|
||||
** to return an error (error code SQLITE_ERROR) if the statement uses
|
||||
** any virtual tables.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_PREPARE_PERSISTENT 0x01
|
||||
#define SQLITE_PREPARE_NORMALIZE 0x02
|
||||
#define SQLITE_PREPARE_NO_VTAB 0x04
|
||||
|
||||
/*
|
||||
** CAPI3REF: Compiling An SQL Statement
|
||||
|
|
@ -9996,7 +10025,7 @@ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
|
|||
** sqlite3changeset_next() is called on the iterator or until the
|
||||
** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
|
||||
** set to the number of columns in the table affected by the change. If
|
||||
** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
|
||||
** pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
|
||||
** is an indirect change, or false (0) otherwise. See the documentation for
|
||||
** [sqlite3session_indirect()] for a description of direct and indirect
|
||||
** changes. Finally, if pOp is not NULL, then *pOp is set to one of
|
||||
|
|
@ -11230,12 +11259,8 @@ struct Fts5PhraseIter {
|
|||
**
|
||||
** Usually, output parameter *piPhrase is set to the phrase number, *piCol
|
||||
** to the column in which it occurs and *piOff the token offset of the
|
||||
** first token of the phrase. The exception is if the table was created
|
||||
** with the offsets=0 option specified. In this case *piOff is always
|
||||
** set to -1.
|
||||
**
|
||||
** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
|
||||
** if an error occurs.
|
||||
** first token of the phrase. Returns SQLITE_OK if successful, or an error
|
||||
** code (i.e. SQLITE_NOMEM) if an error occurs.
|
||||
**
|
||||
** This API can be quite slow if used with an FTS5 table created with the
|
||||
** "detail=none" or "detail=column" option.
|
||||
|
|
@ -11524,11 +11549,11 @@ struct Fts5ExtensionApi {
|
|||
** the tokenizer substitutes "first" for "1st" and the query works
|
||||
** as expected.
|
||||
**
|
||||
** <li> By adding multiple synonyms for a single term to the FTS index.
|
||||
** In this case, when tokenizing query text, the tokenizer may
|
||||
** provide multiple synonyms for a single term within the document.
|
||||
** FTS5 then queries the index for each synonym individually. For
|
||||
** example, faced with the query:
|
||||
** <li> By querying the index for all synonyms of each query term
|
||||
** separately. In this case, when tokenizing query text, the
|
||||
** tokenizer may provide multiple synonyms for a single term
|
||||
** within the document. FTS5 then queries the index for each
|
||||
** synonym individually. For example, faced with the query:
|
||||
**
|
||||
** <codeblock>
|
||||
** ... MATCH 'first place'</codeblock>
|
||||
|
|
@ -11552,7 +11577,7 @@ struct Fts5ExtensionApi {
|
|||
** "place".
|
||||
**
|
||||
** This way, even if the tokenizer does not provide synonyms
|
||||
** when tokenizing query text (it should not - to do would be
|
||||
** when tokenizing query text (it should not - to do so would be
|
||||
** inefficient), it doesn't matter if the user queries for
|
||||
** 'first + place' or '1st + place', as there are entries in the
|
||||
** FTS index corresponding to both forms of the first token.
|
||||
|
|
|
|||
|
|
@ -78,15 +78,8 @@ GetIndexFromCache(const nsAttrAndChildArray* aArray)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Due to a compiler bug in VisualAge C++ for AIX, we need to return the
|
||||
* address of the first index into mBuffer here, instead of simply returning
|
||||
* mBuffer itself.
|
||||
*
|
||||
* See Bug 231104 for more information.
|
||||
*/
|
||||
#define ATTRS(_impl) \
|
||||
reinterpret_cast<InternalAttr*>(&((_impl)->mBuffer[0]))
|
||||
reinterpret_cast<InternalAttr*>((_impl)->mBuffer)
|
||||
|
||||
|
||||
#define NS_IMPL_EXTRA_SIZE \
|
||||
|
|
|
|||
|
|
@ -13,10 +13,6 @@
|
|||
#include <float.h>
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
#include <ieeefp.h>
|
||||
#endif
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Value.h"
|
||||
#include "js/RootingAPI.h"
|
||||
|
|
|
|||
|
|
@ -93,20 +93,13 @@ private:
|
|||
nsAttrValue mValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Due to a compiler bug in VisualAge C++ for AIX, we need to return the
|
||||
* address of the first index into mAttrs here, instead of simply
|
||||
* returning mAttrs itself.
|
||||
*
|
||||
* See Bug 231104 for more information.
|
||||
*/
|
||||
const InternalAttr* Attrs() const
|
||||
{
|
||||
return reinterpret_cast<const InternalAttr*>(&(mAttrs[0]));
|
||||
return reinterpret_cast<const InternalAttr*>(mAttrs);
|
||||
}
|
||||
InternalAttr* Attrs()
|
||||
{
|
||||
return reinterpret_cast<InternalAttr*>(&(mAttrs[0]));
|
||||
return reinterpret_cast<InternalAttr*>(mAttrs);
|
||||
}
|
||||
|
||||
uint16_t mAttrCount;
|
||||
|
|
|
|||
|
|
@ -22,18 +22,6 @@
|
|||
typedef unsigned int uint32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX)
|
||||
/*
|
||||
* AIX and SunOS ship a inttypes.h header that defines [u]int32_t,
|
||||
* but not bool for C.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD)
|
||||
/*
|
||||
* BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and
|
||||
|
|
|
|||
|
|
@ -19,17 +19,7 @@
|
|||
#include "nsIPrefService.h"
|
||||
|
||||
#define LOCAL_PLUGIN_DLL_SUFFIX ".so"
|
||||
#if defined(__hpux)
|
||||
#define DEFAULT_X11_PATH "/usr/lib/X11R6/"
|
||||
#undef LOCAL_PLUGIN_DLL_SUFFIX
|
||||
#define LOCAL_PLUGIN_DLL_SUFFIX ".sl"
|
||||
#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".so"
|
||||
#elif defined(_AIX)
|
||||
#define DEFAULT_X11_PATH "/usr/lib"
|
||||
#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".a"
|
||||
#elif defined(SOLARIS)
|
||||
#define DEFAULT_X11_PATH "/usr/openwin/lib/"
|
||||
#elif defined(LINUX)
|
||||
#if defined(LINUX)
|
||||
#define DEFAULT_X11_PATH "/usr/X11R6/lib/"
|
||||
#elif defined(__APPLE__)
|
||||
#define DEFAULT_X11_PATH "/usr/X11R6/lib"
|
||||
|
|
@ -102,11 +92,7 @@ static bool LoadExtraSharedLib(const char *name, char **soname, bool tryToGetSon
|
|||
|
||||
#define PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS 32
|
||||
#define PREF_PLUGINS_SONAME "plugin.soname.list"
|
||||
#if defined(SOLARIS) || defined(HPUX)
|
||||
#define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX ":libXm" LOCAL_PLUGIN_DLL_SUFFIX
|
||||
#else
|
||||
#define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX
|
||||
#endif
|
||||
/*
|
||||
this function looks for
|
||||
user_pref("plugin.soname.list", "/usr/X11R6/lib/libXt.so.6:libXext.so");
|
||||
|
|
@ -280,15 +266,9 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
|
|||
// work fine.
|
||||
|
||||
|
||||
#if defined(SOLARIS) || defined(HPUX)
|
||||
// Acrobat/libXm: Lazy resolving might cause crash later (bug 211587)
|
||||
*outLibrary = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW);
|
||||
pLibrary = *outLibrary;
|
||||
#else
|
||||
// Some dlopen() doesn't recover from a failed PR_LD_NOW (bug 223744)
|
||||
*outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
|
||||
pLibrary = *outLibrary;
|
||||
#endif
|
||||
if (!pLibrary) {
|
||||
LoadExtraSharedLibs();
|
||||
// try reload plugin once more
|
||||
|
|
|
|||
|
|
@ -23,16 +23,7 @@ UnaryExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
double value = exprRes->numberValue();
|
||||
#ifdef HPUX
|
||||
/*
|
||||
* Negation of a zero doesn't produce a negative
|
||||
* zero on HPUX. Perform the operation by multiplying with
|
||||
* -1.
|
||||
*/
|
||||
return aContext->recycler()->getNumberResult(-1 * value, aResult);
|
||||
#else
|
||||
return aContext->recycler()->getNumberResult(-value, aResult);
|
||||
#endif
|
||||
}
|
||||
|
||||
TX_IMPL_EXPR_STUBS_1(UnaryExpr, NODESET_RESULT, expr)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ var htmlEditor = document.getElementById("htmlEditor");
|
|||
|
||||
const kIsMac = navigator.platform.indexOf("Mac") == 0;
|
||||
const kIsWin = navigator.platform.indexOf("Win") == 0;
|
||||
const kIsLinux = navigator.platform.indexOf("Linux") == 0 || navigator.platform.indexOf("SunOS") == 0 ;
|
||||
const kIsLinux = navigator.platform.indexOf("Linux") == 0;
|
||||
|
||||
function runTests()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@ if (/Windows/.test(ua)) {
|
|||
}
|
||||
else if (/Linux/.test(ua))
|
||||
id = "linux";
|
||||
else if (/SunOS/.test(ua))
|
||||
id = "linux";
|
||||
else if (/Mac OS X/.test(ua))
|
||||
id = "mac";
|
||||
|
||||
|
|
|
|||
|
|
@ -488,6 +488,9 @@ public:
|
|||
/**
|
||||
* Returns a DataSourceSurface with the same data as this one, but
|
||||
* guaranteed to have surface->GetType() == SurfaceType::DATA.
|
||||
*
|
||||
* The returning surface might be null, because of OOM or gfx device reset.
|
||||
* The caller needs to do null-check before using it.
|
||||
*/
|
||||
virtual already_AddRefed<DataSourceSurface> GetDataSurface() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -104,8 +104,6 @@ typedef __int32 int32_t;
|
|||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#elif defined (_AIX)
|
||||
# include <sys/inttypes.h>
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
#include "mozilla/dom/VideoDecoderManagerChild.h"
|
||||
#include "mozilla/layers/LayerTreeOwnerTracker.h"
|
||||
#include "nsDebugImpl.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "prenv.h"
|
||||
#include "ProcessUtils.h"
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ IPDL_SOURCES = [
|
|||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/ipc',
|
||||
'/toolkit/crashreporter',
|
||||
'/xpcom/threads',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@ typedef unsigned __int64 uintptr_t;
|
|||
typedef unsigned long uintptr_t;
|
||||
#endif
|
||||
|
||||
#elif defined (_AIX)
|
||||
# include <sys/inttypes.h>
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1096,15 +1096,8 @@ gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
|
|||
|
||||
FcFontSet *sets[1] = { fontSet };
|
||||
FcResult result;
|
||||
#ifdef SOLARIS
|
||||
// Get around a crash of FcFontSetSort when FcConfig is nullptr
|
||||
// Solaris's FcFontSetSort needs an FcConfig (bug 474758)
|
||||
fontSet.own(FcFontSetSort(FcConfigGetCurrent(), sets, 1, mSortPattern,
|
||||
FcFalse, nullptr, &result));
|
||||
#else
|
||||
fontSet.own(FcFontSetSort(nullptr, sets, 1, mSortPattern,
|
||||
FcFalse, nullptr, &result));
|
||||
#endif
|
||||
|
||||
if (truncateMarker != nullptr && fontSet) {
|
||||
nsAutoRef<FcFontSet> truncatedSet(FcFontSetCreate());
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
#include "prenv.h"
|
||||
#include "nsXPCOMPrivate.h"
|
||||
|
||||
#include "nsExceptionHandler.h"
|
||||
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
|
|
|||
|
|
@ -177,7 +177,6 @@ IPDL_SOURCES = [
|
|||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/ipc',
|
||||
'/toolkit/crashreporter',
|
||||
'/toolkit/xre',
|
||||
'/xpcom/threads',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -31,20 +31,10 @@ typedef uint16_t uint16;
|
|||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
/*
|
||||
* On AIX 4.3, sys/inttypes.h (which is included by sys/types.h, a very
|
||||
* common header file) defines the types int8, int16, int32, and int64.
|
||||
* So we don't define these four types here to avoid conflicts in case
|
||||
* the code also includes sys/types.h.
|
||||
*/
|
||||
#if defined(AIX) && defined(HAVE_SYS_INTTYPES_H)
|
||||
#include <sys/inttypes.h>
|
||||
#else
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
#endif /* AIX && HAVE_SYS_INTTYPES_H */
|
||||
|
||||
typedef uint8_t JSUint8;
|
||||
typedef uint16_t JSUint16;
|
||||
|
|
|
|||
|
|
@ -138,27 +138,6 @@ distclean::
|
|||
|
||||
CFLAGS += $(MOZ_ZLIB_CFLAGS)
|
||||
|
||||
# Silence warnings on AIX/HP-UX from non-GNU compilers
|
||||
ifndef GNU_CC
|
||||
ifeq ($(OS_ARCH),AIX)
|
||||
# Suppress warnings from xlC
|
||||
# 1540-1281: offsetof() on null non-POD types
|
||||
# 1540-1608: anonymous unions using static data members
|
||||
CFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608
|
||||
CXXFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608
|
||||
endif
|
||||
endif
|
||||
ifeq ($(OS_ARCH),SunOS)
|
||||
ifeq ($(TARGET_CPU),sparc)
|
||||
|
||||
ifdef GNU_CC
|
||||
CFLAGS += -mcpu=v9
|
||||
CXXFLAGS += -mcpu=v9
|
||||
endif # GNU_CC
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
$(LIBRARY_NAME).pc: js.pc
|
||||
cp $^ $@
|
||||
|
||||
|
|
|
|||
|
|
@ -240,11 +240,7 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!JS_SetProperty(cx, info, "intl-api", value))
|
||||
return false;
|
||||
|
||||
#if defined(SOLARIS)
|
||||
value = BooleanValue(false);
|
||||
#else
|
||||
value = BooleanValue(true);
|
||||
#endif
|
||||
if (!JS_SetProperty(cx, info, "mapped-array-buffer", value))
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,6 @@
|
|||
#include <float.h>
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
#include <ieeefp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SSIZE_T
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,21 +32,11 @@ int main (void)
|
|||
|
||||
f = 3.14159;
|
||||
|
||||
#if 1
|
||||
/* This is ifdef'd out for now. long double support under SunOS/gcc
|
||||
is pretty much non-existent. You'll get the odd bus error in library
|
||||
routines like printf(). */
|
||||
printf ("%Lf\n", ldblit(f));
|
||||
#endif
|
||||
ld = 666;
|
||||
ffi_call(&cif, FFI_FN(ldblit), &ld, values);
|
||||
|
||||
#if 1
|
||||
/* This is ifdef'd out for now. long double support under SunOS/gcc
|
||||
is pretty much non-existent. You'll get the odd bus error in library
|
||||
routines like printf(). */
|
||||
printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON);
|
||||
#endif
|
||||
|
||||
/* These are not always the same!! Check for a reasonable delta */
|
||||
if (ld - ldblit(f) < LDBL_EPSILON)
|
||||
|
|
|
|||
|
|
@ -17,11 +17,6 @@
|
|||
#include "jswin.h"
|
||||
#include <psapi.h>
|
||||
|
||||
#elif defined(SOLARIS)
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#elif defined(XP_UNIX)
|
||||
|
||||
#include <algorithm>
|
||||
|
|
@ -408,86 +403,6 @@ DeallocateMappedContent(void* p, size_t length)
|
|||
|
||||
# endif
|
||||
|
||||
#elif defined(SOLARIS)
|
||||
|
||||
#ifndef MAP_NOSYNC
|
||||
# define MAP_NOSYNC 0
|
||||
#endif
|
||||
|
||||
void
|
||||
InitMemorySubsystem()
|
||||
{
|
||||
if (pageSize == 0)
|
||||
pageSize = allocGranularity = size_t(sysconf(_SC_PAGESIZE));
|
||||
}
|
||||
|
||||
void*
|
||||
MapAlignedPages(size_t size, size_t alignment)
|
||||
{
|
||||
MOZ_ASSERT(size >= alignment);
|
||||
MOZ_ASSERT(size >= allocGranularity);
|
||||
MOZ_ASSERT(size % alignment == 0);
|
||||
MOZ_ASSERT(size % pageSize == 0);
|
||||
MOZ_ASSERT_IF(alignment < allocGranularity, allocGranularity % alignment == 0);
|
||||
MOZ_ASSERT_IF(alignment > allocGranularity, alignment % allocGranularity == 0);
|
||||
|
||||
int prot = PROT_READ | PROT_WRITE;
|
||||
int flags = MAP_PRIVATE | MAP_ANON | MAP_ALIGN | MAP_NOSYNC;
|
||||
|
||||
void* p = mmap((caddr_t)alignment, size, prot, flags, -1, 0);
|
||||
if (p == MAP_FAILED)
|
||||
return nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void*
|
||||
MapAlignedPagesLastDitch(size_t size, size_t alignment)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
UnmapPages(void* p, size_t size)
|
||||
{
|
||||
MOZ_ALWAYS_TRUE(0 == munmap((caddr_t)p, size));
|
||||
}
|
||||
|
||||
bool
|
||||
MarkPagesUnused(void* p, size_t size)
|
||||
{
|
||||
MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MarkPagesInUse(void* p, size_t size)
|
||||
{
|
||||
if (!DecommitEnabled())
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
|
||||
}
|
||||
|
||||
size_t
|
||||
GetPageFaultCount()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment)
|
||||
{
|
||||
// Not implemented.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Deallocate mapped memory for object.
|
||||
void
|
||||
DeallocateMappedContent(void* p, size_t length)
|
||||
{
|
||||
// Not implemented.
|
||||
}
|
||||
|
||||
#elif defined(XP_UNIX)
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@
|
|||
#if defined(XP_WIN)
|
||||
#include "jswin.h"
|
||||
#include <psapi.h>
|
||||
#elif defined(SOLARIS)
|
||||
// This test doesn't apply to Solaris.
|
||||
#elif defined(XP_UNIX)
|
||||
#include <algorithm>
|
||||
#include <errno.h>
|
||||
|
|
@ -39,8 +37,6 @@ BEGIN_TEST(testGCAllocator)
|
|||
# else // Various APIs are unavailable. This test is disabled.
|
||||
return true;
|
||||
# endif
|
||||
#elif defined(SOLARIS)
|
||||
return true;
|
||||
#elif defined(XP_UNIX)
|
||||
PageSize = size_t(sysconf(_SC_PAGESIZE));
|
||||
#else
|
||||
|
|
@ -301,12 +297,6 @@ void* mapMemory(size_t length) { return nullptr; }
|
|||
void unmapPages(void* p, size_t size) { }
|
||||
|
||||
# endif
|
||||
#elif defined(SOLARIS) // This test doesn't apply to Solaris.
|
||||
|
||||
void* mapMemoryAt(void* desired, size_t length) { return nullptr; }
|
||||
void* mapMemory(size_t length) { return nullptr; }
|
||||
void unmapPages(void* p, size_t size) { }
|
||||
|
||||
#elif defined(XP_UNIX)
|
||||
|
||||
void*
|
||||
|
|
@ -377,7 +367,7 @@ unmapPages(void* p, size_t size)
|
|||
MOZ_RELEASE_ASSERT(errno == ENOMEM);
|
||||
}
|
||||
|
||||
#else // !defined(XP_WIN) && !defined(SOLARIS) && !defined(XP_UNIX)
|
||||
#else // !defined(XP_WIN) && !defined(XP_UNIX)
|
||||
#error "Memory mapping functions are not defined for your OS."
|
||||
#endif
|
||||
END_TEST(testGCAllocator)
|
||||
|
|
|
|||
|
|
@ -71,35 +71,6 @@ js::GetNativeStackBaseImpl()
|
|||
# endif
|
||||
}
|
||||
|
||||
#elif defined(SOLARIS)
|
||||
|
||||
#include <ucontext.h>
|
||||
|
||||
JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0);
|
||||
|
||||
void*
|
||||
js::GetNativeStackBaseImpl()
|
||||
{
|
||||
stack_t st;
|
||||
stack_getbounds(&st);
|
||||
return static_cast<char*>(st.ss_sp) + st.ss_size;
|
||||
}
|
||||
|
||||
#elif defined(AIX)
|
||||
|
||||
#include <ucontext.h>
|
||||
|
||||
JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0);
|
||||
|
||||
void*
|
||||
js::GetNativeStackBaseImpl()
|
||||
{
|
||||
ucontext_t context;
|
||||
getcontext(&context);
|
||||
return static_cast<char*>(context.uc_stack.ss_sp) +
|
||||
context.uc_stack.ss_size;
|
||||
}
|
||||
|
||||
#elif defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__)
|
||||
void*
|
||||
js::GetNativeStackBaseImpl()
|
||||
|
|
|
|||
|
|
@ -147,13 +147,7 @@
|
|||
# define JS_64BIT
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
/* Additional GCC defines are when running on Solaris, AIX, and HPUX */
|
||||
# if defined(__x86_64__) || defined(__sparcv9) || \
|
||||
defined(__64BIT__) || defined(__LP64__)
|
||||
# define JS_64BIT
|
||||
# endif
|
||||
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Sun Studio C/C++ */
|
||||
# if defined(__x86_64) || defined(__sparcv9)
|
||||
# if defined(__x86_64__) || defined(__64BIT__)
|
||||
# define JS_64BIT
|
||||
# endif
|
||||
#elif defined(__xlc__) || defined(__xlC__) /* IBM XL C/C++ */
|
||||
|
|
|
|||
|
|
@ -722,14 +722,6 @@ if CONFIG['OS_ARCH'] == 'Linux':
|
|||
'dl',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'SunOS':
|
||||
OS_LIBS += [
|
||||
'posix4',
|
||||
'dl',
|
||||
'nsl',
|
||||
'socket',
|
||||
]
|
||||
|
||||
OS_LIBS += CONFIG['REALTIME_LIBS']
|
||||
|
||||
CFLAGS += CONFIG['MOZ_ICU_CFLAGS']
|
||||
|
|
|
|||
|
|
@ -11,9 +11,6 @@
|
|||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#ifdef SOLARIS
|
||||
#define _REENTRANT 1
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
|
@ -33,10 +30,6 @@
|
|||
|
||||
#ifdef XP_UNIX
|
||||
|
||||
#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
|
||||
extern int gettimeofday(struct timeval* tv);
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#endif /* XP_UNIX */
|
||||
|
|
@ -49,11 +42,7 @@ PRMJ_Now()
|
|||
{
|
||||
struct timeval tv;
|
||||
|
||||
#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
|
||||
gettimeofday(&tv);
|
||||
#else
|
||||
gettimeofday(&tv, 0);
|
||||
#endif /* _SVID_GETTOD */
|
||||
|
||||
return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ class AutoSetHandlingSegFault
|
|||
# define EPC_sig(p) ((p)->sc_pc)
|
||||
# define RFP_sig(p) ((p)->sc_regs[30])
|
||||
# endif
|
||||
#elif defined(__linux__) || defined(SOLARIS)
|
||||
#elif defined(__linux__)
|
||||
# if defined(__linux__)
|
||||
# define XMM_sig(p,i) ((p)->uc_mcontext.fpregs->_xmm[i])
|
||||
# define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_EIP])
|
||||
|
|
|
|||
|
|
@ -644,7 +644,6 @@ env_setProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue
|
|||
ObjectOpResult& result)
|
||||
{
|
||||
/* XXX porting may be easy, but these don't seem to supply setenv by default */
|
||||
#if !defined SOLARIS
|
||||
RootedString valstr(cx);
|
||||
RootedString idstr(cx);
|
||||
int rv;
|
||||
|
|
@ -663,7 +662,7 @@ env_setProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue
|
|||
JSAutoByteString value(cx, valstr);
|
||||
if (!value)
|
||||
return false;
|
||||
#if defined XP_WIN || defined HPUX || defined OSF1 || defined SCO
|
||||
#if defined XP_WIN || defined SCO
|
||||
{
|
||||
char* waste = JS_smprintf("%s=%s", name.ptr(), value.ptr());
|
||||
if (!waste) {
|
||||
|
|
@ -671,16 +670,7 @@ env_setProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue
|
|||
return false;
|
||||
}
|
||||
rv = putenv(waste);
|
||||
#ifdef XP_WIN
|
||||
/*
|
||||
* HPUX9 at least still has the bad old non-copying putenv.
|
||||
*
|
||||
* Per mail from <s.shanmuganathan@digital.com>, OSF1 also has a putenv
|
||||
* that will crash if you pass it an auto char array (so it must place
|
||||
* its argument directly in the char* environ[] array).
|
||||
*/
|
||||
free(waste);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
rv = setenv(name.ptr(), value.ptr(), 1);
|
||||
|
|
@ -696,7 +686,6 @@ env_setProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue
|
|||
return false;
|
||||
}
|
||||
vp.setString(valstr);
|
||||
#endif /* !defined SOLARIS */
|
||||
return result.succeed();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -857,29 +857,47 @@ class nsLineList_iterator {
|
|||
return --copy;
|
||||
}
|
||||
|
||||
// Passing by value rather than by reference and reference to const
|
||||
// to keep AIX happy.
|
||||
bool operator==(const iterator_self_type aOther) const
|
||||
bool operator==(const iterator_self_type& aOther) const
|
||||
{
|
||||
MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(const iterator_self_type aOther) const
|
||||
bool operator!=(const iterator_self_type& aOther) const
|
||||
{
|
||||
MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
bool operator==(const iterator_self_type aOther)
|
||||
bool operator==(const iterator_self_type& aOther)
|
||||
{
|
||||
MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(const iterator_self_type aOther)
|
||||
bool operator!=(const iterator_self_type& aOther)
|
||||
{
|
||||
MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
|
||||
bool operator==(iterator_self_type& aOther) const
|
||||
{
|
||||
MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(iterator_self_type& aOther) const
|
||||
{
|
||||
MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
bool operator==(iterator_self_type& aOther)
|
||||
{
|
||||
MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(iterator_self_type& aOther)
|
||||
{
|
||||
MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
|
||||
private:
|
||||
link_type *mCurrent;
|
||||
#ifdef DEBUG
|
||||
|
|
@ -992,24 +1010,42 @@ class nsLineList_reverse_iterator {
|
|||
}
|
||||
#endif /* !__MWERKS__ */
|
||||
|
||||
// Passing by value rather than by reference and reference to const
|
||||
// to keep AIX happy.
|
||||
bool operator==(const iterator_self_type aOther) const
|
||||
bool operator==(const iterator_self_type& aOther) const
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(const iterator_self_type aOther) const
|
||||
bool operator!=(const iterator_self_type& aOther) const
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
bool operator==(const iterator_self_type aOther)
|
||||
bool operator==(const iterator_self_type& aOther)
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(const iterator_self_type aOther)
|
||||
bool operator!=(const iterator_self_type& aOther)
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
bool operator==(iterator_self_type& aOther) const
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(iterator_self_type& aOther) const
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
bool operator==(iterator_self_type& aOther)
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(iterator_self_type& aOther)
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
|
|
@ -1126,24 +1162,42 @@ class nsLineList_const_iterator {
|
|||
return --copy;
|
||||
}
|
||||
|
||||
// Passing by value rather than by reference and reference to const
|
||||
// to keep AIX happy.
|
||||
bool operator==(const iterator_self_type aOther) const
|
||||
bool operator==(const iterator_self_type& aOther) const
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(const iterator_self_type aOther) const
|
||||
bool operator!=(const iterator_self_type& aOther) const
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
bool operator==(const iterator_self_type aOther)
|
||||
bool operator==(const iterator_self_type& aOther)
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(const iterator_self_type aOther)
|
||||
bool operator!=(const iterator_self_type& aOther)
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
bool operator==(iterator_self_type& aOther) const
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(iterator_self_type& aOther) const
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
}
|
||||
bool operator==(iterator_self_type& aOther)
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent == aOther.mCurrent;
|
||||
}
|
||||
bool operator!=(iterator_self_type& aOther)
|
||||
{
|
||||
NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
|
||||
return mCurrent != aOther.mCurrent;
|
||||
|
|
|
|||
|
|
@ -67,9 +67,6 @@
|
|||
#define alloca _alloca
|
||||
#endif
|
||||
#endif
|
||||
#ifdef SOLARIS
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
using std::max;
|
||||
using std::min;
|
||||
|
|
|
|||
|
|
@ -274,7 +274,8 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(gfxContext* aContext,
|
|||
}
|
||||
RefPtr<DataSourceSurface> maskSurface = maskSnapshot->GetDataSurface();
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!maskSurface->Map(DataSourceSurface::MapType::READ, &map)) {
|
||||
if (!maskSurface ||
|
||||
!maskSurface->Map(DataSourceSurface::MapType::READ, &map)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -685,7 +685,7 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
|
|||
bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
|
||||
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
|
||||
nsSVGMaskFrame *maskFrame = effectProperties.GetFirstMaskFrame(&isOK);
|
||||
if (!isOK) {
|
||||
if (!isOK || !maskFrame) {
|
||||
// Some resource is invalid. We shouldn't paint anything.
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,9 +283,7 @@ typedef long ssize_t;
|
|||
#define JEMALLOC_RECYCLE
|
||||
|
||||
#ifndef MOZ_MEMORY_WINDOWS
|
||||
#ifndef MOZ_MEMORY_SOLARIS
|
||||
#include <sys/cdefs.h>
|
||||
#endif
|
||||
#ifndef __DECONST
|
||||
# define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
|
||||
#endif
|
||||
|
|
@ -311,7 +309,7 @@ __FBSDID("$FreeBSD: head/lib/libc/stdlib/malloc.c 180599 2008-07-18 19:35:44Z ja
|
|||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#if !defined(MOZ_MEMORY_SOLARIS) && !defined(MOZ_MEMORY_ANDROID)
|
||||
#if !defined(MOZ_MEMORY_ANDROID)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <sys/uio.h>
|
||||
|
|
@ -413,10 +411,6 @@ void *_mmap(void *addr, size_t length, int prot, int flags,
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_MEMORY_SOLARIS) && defined(MAP_ALIGN) && !defined(JEMALLOC_NEVER_USES_MAP_ALIGN)
|
||||
#define JEMALLOC_USES_MAP_ALIGN /* Required on Solaris 10. Might improve performance elsewhere. */
|
||||
#endif
|
||||
|
||||
#ifndef __DECONST
|
||||
#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
|
||||
#endif
|
||||
|
|
@ -1043,7 +1037,7 @@ static const bool config_recycle = false;
|
|||
* will abort.
|
||||
* Platform specific page size conditions copied from js/public/HeapAPI.h
|
||||
*/
|
||||
#if (defined(SOLARIS) || defined(__FreeBSD__)) && \
|
||||
#if (defined(__FreeBSD__)) && \
|
||||
(defined(__sparc) || defined(__sparcv9) || defined(__ia64))
|
||||
#define pagesize_2pow ((size_t) 13)
|
||||
#elif defined(__powerpc64__)
|
||||
|
|
@ -5131,13 +5125,6 @@ malloc_ncpus(void)
|
|||
else
|
||||
return (n);
|
||||
}
|
||||
#elif (defined(MOZ_MEMORY_SOLARIS))
|
||||
|
||||
static inline unsigned
|
||||
malloc_ncpus(void)
|
||||
{
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
}
|
||||
#elif (defined(MOZ_MEMORY_WINDOWS))
|
||||
static inline unsigned
|
||||
malloc_ncpus(void)
|
||||
|
|
@ -5934,19 +5921,9 @@ RETURN:
|
|||
#define MOZ_MEMORY_ELF
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_MEMORY_SOLARIS
|
||||
# ifdef __SUNPRO_C
|
||||
void *
|
||||
memalign_impl(size_t alignment, size_t size);
|
||||
#pragma no_inline(memalign_impl)
|
||||
# elif (defined(__GNUC__))
|
||||
__attribute__((noinline))
|
||||
# endif
|
||||
#else
|
||||
#if (defined(MOZ_MEMORY_ELF))
|
||||
__attribute__((visibility ("hidden")))
|
||||
#endif
|
||||
#endif
|
||||
#endif /* MOZ_REPLACE_MALLOC */
|
||||
|
||||
#ifdef MOZ_MEMORY_ELF
|
||||
|
|
|
|||
|
|
@ -13,11 +13,6 @@ SOURCES += [
|
|||
]
|
||||
FINAL_LIBRARY = 'memory'
|
||||
|
||||
# See bug 422055.
|
||||
if CONFIG['OS_ARCH'] == 'SunOS' and not CONFIG['GNU_CC'] \
|
||||
and CONFIG['MOZ_OPTIMIZE']:
|
||||
CFLAGS += ['-xO5']
|
||||
|
||||
# For non release/esr builds, enable (some) fatal jemalloc assertions. This
|
||||
# helps us catch memory errors.
|
||||
if CONFIG['MOZ_UPDATE_CHANNEL'] not in ('release', 'esr'):
|
||||
|
|
|
|||
|
|
@ -1306,9 +1306,6 @@ static nsresult pref_InitInitialObjects()
|
|||
"winpref.js"
|
||||
#elif defined(XP_UNIX)
|
||||
"unix.js"
|
||||
#if defined(_AIX)
|
||||
, "aix.js"
|
||||
#endif
|
||||
#elif defined(XP_BEOS)
|
||||
"beos.js"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ public:
|
|||
static void InitGlobalObjects();
|
||||
static void ShutdownGlobalObjects();
|
||||
|
||||
public: /* internal -- HPUX compiler can't handle this being private */
|
||||
//
|
||||
// location and length of an url segment relative to mSpec
|
||||
//
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ GNOMEUI_VERSION=2.2.0
|
|||
GCONF_VERSION=1.2.1
|
||||
STARTUP_NOTIFICATION_VERSION=0.8
|
||||
DBUS_VERSION=0.60
|
||||
SQLITE_VERSION=3.26.0
|
||||
SQLITE_VERSION=3.27.2
|
||||
|
||||
dnl Set various checks
|
||||
dnl ========================================================
|
||||
|
|
|
|||
|
|
@ -585,17 +585,10 @@
|
|||
} else if (Const._STAT_VER != undefined) {
|
||||
const ver = Const._STAT_VER;
|
||||
let xstat_name, lxstat_name, fxstat_name;
|
||||
if (OS.Constants.Sys.Name == "SunOS") {
|
||||
// Solaris
|
||||
xstat_name = "_xstat";
|
||||
lxstat_name = "_lxstat";
|
||||
fxstat_name = "_fxstat";
|
||||
} else {
|
||||
// Linux, all widths
|
||||
xstat_name = "__xstat";
|
||||
lxstat_name = "__lxstat";
|
||||
fxstat_name = "__fxstat";
|
||||
}
|
||||
// Linux, all widths
|
||||
xstat_name = "__xstat";
|
||||
lxstat_name = "__lxstat";
|
||||
fxstat_name = "__fxstat";
|
||||
|
||||
let Stat = {};
|
||||
libc.declareLazyFFI(Stat, "xstat",
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"CrashReports"
|
||||
];
|
||||
|
||||
this.CrashReports = {
|
||||
pendingDir: null,
|
||||
reportsDir: null,
|
||||
submittedDir: null,
|
||||
getReports: function CrashReports_getReports()
|
||||
{
|
||||
let reports = [];
|
||||
|
||||
try {
|
||||
// Ignore any non http/https urls
|
||||
if (!/^https?:/i.test(Services.prefs.getCharPref("breakpad.reportURL")))
|
||||
return reports;
|
||||
}
|
||||
catch (e) { }
|
||||
|
||||
if (this.submittedDir.exists() && this.submittedDir.isDirectory()) {
|
||||
let entries = this.submittedDir.directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let file = entries.getNext().QueryInterface(Components.interfaces.nsIFile);
|
||||
let leaf = file.leafName;
|
||||
if (leaf.startsWith("bp-") &&
|
||||
leaf.endsWith(".txt")) {
|
||||
let entry = {
|
||||
id: leaf.slice(0, -4),
|
||||
date: file.lastModifiedTime,
|
||||
pending: false
|
||||
};
|
||||
reports.push(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pendingDir.exists() && this.pendingDir.isDirectory()) {
|
||||
let uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
let entries = this.pendingDir.directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let file = entries.getNext().QueryInterface(Components.interfaces.nsIFile);
|
||||
let leaf = file.leafName;
|
||||
let id = leaf.slice(0, -4);
|
||||
if (leaf.endsWith(".dmp") && uuidRegex.test(id)) {
|
||||
let entry = {
|
||||
id: id,
|
||||
date: file.lastModifiedTime,
|
||||
pending: true
|
||||
};
|
||||
reports.push(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort reports descending by date
|
||||
return reports.sort( (a, b) => b.date - a.date);
|
||||
}
|
||||
}
|
||||
|
||||
function CrashReports_pendingDir()
|
||||
{
|
||||
let pendingDir = Services.dirsvc.get("UAppData", Components.interfaces.nsIFile);
|
||||
pendingDir.append("Crash Reports");
|
||||
pendingDir.append("pending");
|
||||
return pendingDir;
|
||||
}
|
||||
|
||||
function CrashReports_reportsDir()
|
||||
{
|
||||
let reportsDir = Services.dirsvc.get("UAppData", Components.interfaces.nsIFile);
|
||||
reportsDir.append("Crash Reports");
|
||||
return reportsDir;
|
||||
}
|
||||
|
||||
function CrashReports_submittedDir()
|
||||
{
|
||||
let submittedDir = Services.dirsvc.get("UAppData", Components.interfaces.nsIFile);
|
||||
submittedDir.append("Crash Reports");
|
||||
submittedDir.append("submitted");
|
||||
return submittedDir;
|
||||
}
|
||||
|
||||
this.CrashReports.pendingDir = CrashReports_pendingDir();
|
||||
this.CrashReports.reportsDir = CrashReports_reportsDir();
|
||||
this.CrashReports.submittedDir = CrashReports_submittedDir();
|
||||
|
|
@ -1,570 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/KeyValueParser.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.importGlobalProperties(['File']);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
|
||||
"resource://gre/modules/PromiseUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"CrashSubmit"
|
||||
];
|
||||
|
||||
const STATE_START = Ci.nsIWebProgressListener.STATE_START;
|
||||
const STATE_STOP = Ci.nsIWebProgressListener.STATE_STOP;
|
||||
|
||||
const SUCCESS = "success";
|
||||
const FAILED = "failed";
|
||||
const SUBMITTING = "submitting";
|
||||
|
||||
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
|
||||
function parseINIStrings(file) {
|
||||
var factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
|
||||
getService(Ci.nsIINIParserFactory);
|
||||
var parser = factory.createINIParser(file);
|
||||
var obj = {};
|
||||
var en = parser.getKeys("Strings");
|
||||
while (en.hasMore()) {
|
||||
var key = en.getNext();
|
||||
obj[key] = parser.getString("Strings", key);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Since we're basically re-implementing part of the crashreporter
|
||||
// client here, we'll just steal the strings we need from crashreporter.ini
|
||||
function getL10nStrings() {
|
||||
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
let path = dirSvc.get("GreD", Ci.nsIFile);
|
||||
path.append("crashreporter.ini");
|
||||
if (!path.exists()) {
|
||||
// see if we're on a mac
|
||||
path = path.parent;
|
||||
path = path.parent;
|
||||
path.append("MacOS");
|
||||
path.append("crashreporter.app");
|
||||
path.append("Contents");
|
||||
path.append("Resources");
|
||||
path.append("crashreporter.ini");
|
||||
if (!path.exists()) {
|
||||
// very bad, but I don't know how to recover
|
||||
return null;
|
||||
}
|
||||
}
|
||||
let crstrings = parseINIStrings(path);
|
||||
let strings = {
|
||||
'crashid': crstrings.CrashID,
|
||||
'reporturl': crstrings.CrashDetailsURL
|
||||
};
|
||||
|
||||
path = dirSvc.get("XCurProcD", Ci.nsIFile);
|
||||
path.append("crashreporter-override.ini");
|
||||
if (path.exists()) {
|
||||
crstrings = parseINIStrings(path);
|
||||
if ('CrashID' in crstrings)
|
||||
strings['crashid'] = crstrings.CrashID;
|
||||
if ('CrashDetailsURL' in crstrings)
|
||||
strings['reporturl'] = crstrings.CrashDetailsURL;
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "strings", getL10nStrings);
|
||||
|
||||
function getDir(name) {
|
||||
let directoryService = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
let dir = directoryService.get("UAppData", Ci.nsIFile);
|
||||
dir.append("Crash Reports");
|
||||
dir.append(name);
|
||||
return dir;
|
||||
}
|
||||
|
||||
function writeFile(dirName, fileName, data) {
|
||||
let path = getDir(dirName);
|
||||
if (!path.exists())
|
||||
path.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0700', 8));
|
||||
path.append(fileName);
|
||||
var fs = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
// open, write, truncate
|
||||
fs.init(path, -1, -1, 0);
|
||||
var os = Cc["@mozilla.org/intl/converter-output-stream;1"].
|
||||
createInstance(Ci.nsIConverterOutputStream);
|
||||
os.init(fs, "UTF-8", 0, 0x0000);
|
||||
os.writeString(data);
|
||||
os.close();
|
||||
fs.close();
|
||||
}
|
||||
|
||||
function getPendingMinidump(id) {
|
||||
let pendingDir = getDir("pending");
|
||||
let dump = pendingDir.clone();
|
||||
let extra = pendingDir.clone();
|
||||
let memory = pendingDir.clone();
|
||||
dump.append(id + ".dmp");
|
||||
extra.append(id + ".extra");
|
||||
memory.append(id + ".memory.json.gz");
|
||||
return [dump, extra, memory];
|
||||
}
|
||||
|
||||
function getAllPendingMinidumpsIDs() {
|
||||
let minidumps = [];
|
||||
let pendingDir = getDir("pending");
|
||||
|
||||
if (!(pendingDir.exists() && pendingDir.isDirectory()))
|
||||
return [];
|
||||
let entries = pendingDir.directoryEntries;
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
if (entry.isFile()) {
|
||||
let matches = entry.leafName.match(/(.+)\.extra$/);
|
||||
if (matches)
|
||||
minidumps.push(matches[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return minidumps;
|
||||
}
|
||||
|
||||
function pruneSavedDumps() {
|
||||
const KEEP = 10;
|
||||
|
||||
let pendingDir = getDir("pending");
|
||||
if (!(pendingDir.exists() && pendingDir.isDirectory()))
|
||||
return;
|
||||
let entries = pendingDir.directoryEntries;
|
||||
let entriesArray = [];
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
if (entry.isFile()) {
|
||||
let matches = entry.leafName.match(/(.+)\.extra$/);
|
||||
if (matches)
|
||||
entriesArray.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
entriesArray.sort(function(a, b) {
|
||||
let dateA = a.lastModifiedTime;
|
||||
let dateB = b.lastModifiedTime;
|
||||
if (dateA < dateB)
|
||||
return -1;
|
||||
if (dateB < dateA)
|
||||
return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (entriesArray.length > KEEP) {
|
||||
for (let i = 0; i < entriesArray.length - KEEP; ++i) {
|
||||
let extra = entriesArray[i];
|
||||
let matches = extra.leafName.match(/(.+)\.extra$/);
|
||||
if (matches) {
|
||||
let dump = extra.clone();
|
||||
dump.leafName = matches[1] + '.dmp';
|
||||
dump.remove(false);
|
||||
|
||||
let memory = extra.clone();
|
||||
memory.leafName = matches[1] + '.memory.json.gz';
|
||||
if (memory.exists()) {
|
||||
memory.remove(false);
|
||||
}
|
||||
|
||||
extra.remove(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addFormEntry(doc, form, name, value) {
|
||||
var input = doc.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = name;
|
||||
input.value = value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
function writeSubmittedReport(crashID, viewURL) {
|
||||
var data = strings.crashid.replace("%s", crashID);
|
||||
if (viewURL)
|
||||
data += "\n" + strings.reporturl.replace("%s", viewURL);
|
||||
|
||||
writeFile("submitted", crashID + ".txt", data);
|
||||
}
|
||||
|
||||
// the Submitter class represents an individual submission.
|
||||
function Submitter(id, recordSubmission, noThrottle, extraExtraKeyVals) {
|
||||
this.id = id;
|
||||
this.recordSubmission = recordSubmission;
|
||||
this.noThrottle = noThrottle;
|
||||
this.additionalDumps = [];
|
||||
this.extraKeyVals = extraExtraKeyVals || {};
|
||||
this.deferredSubmit = PromiseUtils.defer();
|
||||
}
|
||||
|
||||
Submitter.prototype = {
|
||||
submitSuccess: function Submitter_submitSuccess(ret)
|
||||
{
|
||||
// Write out the details file to submitted/
|
||||
writeSubmittedReport(ret.CrashID, ret.ViewURL);
|
||||
|
||||
// Delete from pending dir
|
||||
try {
|
||||
this.dump.remove(false);
|
||||
this.extra.remove(false);
|
||||
|
||||
if (this.memory) {
|
||||
this.memory.remove(false);
|
||||
}
|
||||
|
||||
for (let i of this.additionalDumps) {
|
||||
i.dump.remove(false);
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
// report an error? not much the user can do here.
|
||||
}
|
||||
|
||||
this.notifyStatus(SUCCESS, ret);
|
||||
this.cleanup();
|
||||
},
|
||||
|
||||
cleanup: function Submitter_cleanup() {
|
||||
// drop some references just to be nice
|
||||
this.iframe = null;
|
||||
this.dump = null;
|
||||
this.extra = null;
|
||||
this.memory = null;
|
||||
this.additionalDumps = null;
|
||||
// remove this object from the list of active submissions
|
||||
let idx = CrashSubmit._activeSubmissions.indexOf(this);
|
||||
if (idx != -1)
|
||||
CrashSubmit._activeSubmissions.splice(idx, 1);
|
||||
},
|
||||
|
||||
submitForm: function Submitter_submitForm()
|
||||
{
|
||||
if (!('ServerURL' in this.extraKeyVals)) {
|
||||
return false;
|
||||
}
|
||||
let serverURL = this.extraKeyVals.ServerURL;
|
||||
|
||||
// Override the submission URL from the environment
|
||||
|
||||
var envOverride = Cc['@mozilla.org/process/environment;1'].
|
||||
getService(Ci.nsIEnvironment).get("MOZ_CRASHREPORTER_URL");
|
||||
if (envOverride != '') {
|
||||
serverURL = envOverride;
|
||||
}
|
||||
|
||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
xhr.open("POST", serverURL, true);
|
||||
|
||||
let formData = Cc["@mozilla.org/files/formdata;1"]
|
||||
.createInstance(Ci.nsIDOMFormData);
|
||||
// add the data
|
||||
for (let [name, value] of Object.entries(this.extraKeyVals)) {
|
||||
if (name != "ServerURL") {
|
||||
formData.append(name, value);
|
||||
}
|
||||
}
|
||||
if (this.noThrottle) {
|
||||
// tell the server not to throttle this, since it was manually submitted
|
||||
formData.append("Throttleable", "0");
|
||||
}
|
||||
// add the minidumps
|
||||
formData.append("upload_file_minidump", File.createFromFileName(this.dump.path));
|
||||
if (this.memory) {
|
||||
formData.append("memory_report", File.createFromFileName(this.memory.path));
|
||||
}
|
||||
if (this.additionalDumps.length > 0) {
|
||||
let names = [];
|
||||
for (let i of this.additionalDumps) {
|
||||
names.push(i.name);
|
||||
formData.append("upload_file_minidump_"+i.name,
|
||||
File.createFromFileName(i.dump.path));
|
||||
}
|
||||
}
|
||||
|
||||
let manager = Services.crashmanager;
|
||||
let submissionID = manager.generateSubmissionID();
|
||||
|
||||
xhr.addEventListener("readystatechange", (evt) => {
|
||||
if (xhr.readyState == 4) {
|
||||
let ret =
|
||||
xhr.status == 200 ? parseKeyValuePairs(xhr.responseText) : {};
|
||||
let submitted = !!ret.CrashID;
|
||||
|
||||
if (this.recordSubmission) {
|
||||
let result = submitted ? manager.SUBMISSION_RESULT_OK :
|
||||
manager.SUBMISSION_RESULT_FAILED;
|
||||
manager.addSubmissionResult(this.id, submissionID, new Date(),
|
||||
result);
|
||||
if (submitted) {
|
||||
manager.setRemoteCrashID(this.id, ret.CrashID);
|
||||
}
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
this.submitSuccess(ret);
|
||||
}
|
||||
else {
|
||||
this.notifyStatus(FAILED);
|
||||
this.cleanup();
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
if (this.recordSubmission) {
|
||||
manager.addSubmissionAttempt(this.id, submissionID, new Date());
|
||||
}
|
||||
xhr.send(formData);
|
||||
return true;
|
||||
},
|
||||
|
||||
notifyStatus: function Submitter_notify(status, ret)
|
||||
{
|
||||
let propBag = Cc["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Ci.nsIWritablePropertyBag2);
|
||||
propBag.setPropertyAsAString("minidumpID", this.id);
|
||||
if (status == SUCCESS) {
|
||||
propBag.setPropertyAsAString("serverCrashID", ret.CrashID);
|
||||
}
|
||||
|
||||
let extraKeyValsBag = Cc["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Ci.nsIWritablePropertyBag2);
|
||||
for (let key in this.extraKeyVals) {
|
||||
extraKeyValsBag.setPropertyAsAString(key, this.extraKeyVals[key]);
|
||||
}
|
||||
propBag.setPropertyAsInterface("extra", extraKeyValsBag);
|
||||
|
||||
Services.obs.notifyObservers(propBag, "crash-report-status", status);
|
||||
|
||||
switch (status) {
|
||||
case SUCCESS:
|
||||
this.deferredSubmit.resolve(ret.CrashID);
|
||||
break;
|
||||
case FAILED:
|
||||
this.deferredSubmit.reject();
|
||||
break;
|
||||
default:
|
||||
// no callbacks invoked.
|
||||
}
|
||||
},
|
||||
|
||||
submit: function Submitter_submit()
|
||||
{
|
||||
let [dump, extra, memory] = getPendingMinidump(this.id);
|
||||
|
||||
if (!dump.exists() || !extra.exists()) {
|
||||
this.notifyStatus(FAILED);
|
||||
this.cleanup();
|
||||
return this.deferredSubmit.promise;
|
||||
}
|
||||
this.dump = dump;
|
||||
this.extra = extra;
|
||||
|
||||
// The memory file may or may not exist
|
||||
if (memory.exists()) {
|
||||
this.memory = memory;
|
||||
}
|
||||
|
||||
let extraKeyVals = parseKeyValuePairsFromFile(extra);
|
||||
for (let key in extraKeyVals) {
|
||||
if (!(key in this.extraKeyVals)) {
|
||||
this.extraKeyVals[key] = extraKeyVals[key];
|
||||
}
|
||||
}
|
||||
|
||||
let additionalDumps = [];
|
||||
if ("additional_minidumps" in this.extraKeyVals) {
|
||||
let names = this.extraKeyVals.additional_minidumps.split(',');
|
||||
for (let name of names) {
|
||||
let [dump, extra, memory] = getPendingMinidump(this.id + "-" + name);
|
||||
if (!dump.exists()) {
|
||||
this.notifyStatus(FAILED);
|
||||
this.cleanup();
|
||||
return this.deferredSubmit.promise;
|
||||
}
|
||||
additionalDumps.push({'name': name, 'dump': dump});
|
||||
}
|
||||
}
|
||||
|
||||
this.notifyStatus(SUBMITTING);
|
||||
|
||||
this.additionalDumps = additionalDumps;
|
||||
|
||||
if (!this.submitForm()) {
|
||||
this.notifyStatus(FAILED);
|
||||
this.cleanup();
|
||||
}
|
||||
return this.deferredSubmit.promise;
|
||||
}
|
||||
};
|
||||
|
||||
// ===================================
|
||||
// External API goes here
|
||||
this.CrashSubmit = {
|
||||
/**
|
||||
* Submit the crash report named id.dmp from the "pending" directory.
|
||||
*
|
||||
* @param id
|
||||
* Filename (minus .dmp extension) of the minidump to submit.
|
||||
* @param params
|
||||
* An object containing any of the following optional parameters:
|
||||
* - recordSubmission
|
||||
* If true, a submission event is recorded in CrashManager.
|
||||
* - noThrottle
|
||||
* If true, this crash report should be submitted with
|
||||
* an extra parameter of "Throttleable=0" indicating that
|
||||
* it should be processed right away. This should be set
|
||||
* when the report is being submitted and the user expects
|
||||
* to see the results immediately. Defaults to false.
|
||||
* - extraExtraKeyVals
|
||||
* An object whose key-value pairs will be merged with the data from
|
||||
* the ".extra" file submitted with the report. The properties of
|
||||
* this object will override properties of the same name in the
|
||||
* .extra file.
|
||||
*
|
||||
* @return a Promise that is fulfilled with the server crash ID when the
|
||||
* submission succeeds and rejected otherwise.
|
||||
*/
|
||||
submit: function CrashSubmit_submit(id, params)
|
||||
{
|
||||
params = params || {};
|
||||
let recordSubmission = false;
|
||||
let submitSuccess = null;
|
||||
let submitError = null;
|
||||
let noThrottle = false;
|
||||
let extraExtraKeyVals = null;
|
||||
|
||||
if ('recordSubmission' in params)
|
||||
recordSubmission = params.recordSubmission;
|
||||
if ('noThrottle' in params)
|
||||
noThrottle = params.noThrottle;
|
||||
if ('extraExtraKeyVals' in params)
|
||||
extraExtraKeyVals = params.extraExtraKeyVals;
|
||||
|
||||
let submitter = new Submitter(id, recordSubmission,
|
||||
noThrottle, extraExtraKeyVals);
|
||||
CrashSubmit._activeSubmissions.push(submitter);
|
||||
return submitter.submit();
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete the minidup from the "pending" directory.
|
||||
*
|
||||
* @param id
|
||||
* Filename (minus .dmp extension) of the minidump to delete.
|
||||
*/
|
||||
delete: function CrashSubmit_delete(id) {
|
||||
let [dump, extra, memory] = getPendingMinidump(id);
|
||||
dump.remove(false);
|
||||
extra.remove(false);
|
||||
if (memory.exists()) {
|
||||
memory.remove(false);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a .dmg.ignore file along side the .dmp file to indicate that the user
|
||||
* shouldn't be prompted to submit this crash report again.
|
||||
*
|
||||
* @param id
|
||||
* Filename (minus .dmp extension) of the report to ignore
|
||||
*/
|
||||
|
||||
ignore: function CrashSubmit_ignore(id) {
|
||||
let [dump, extra, mem] = getPendingMinidump(id);
|
||||
return OS.File.open(dump.path + ".ignore", {create: true},
|
||||
{unixFlags: OS.Constants.libc.O_CREAT})
|
||||
.then((file) => { file.close(); });
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the list of pending crash IDs.
|
||||
*
|
||||
* @return an array of string, each being an ID as
|
||||
* expected to be passed to submit()
|
||||
*/
|
||||
pendingIDs: function CrashSubmit_pendingIDs() {
|
||||
return getAllPendingMinidumpsIDs();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the list of pending crash IDs, excluding those marked to be ignored
|
||||
* @param maxFileDate
|
||||
* A Date object. Any files last modified before that date will be ignored
|
||||
*
|
||||
* @return a Promise that is fulfilled with an array of string, each
|
||||
* being an ID as expected to be passed to submit() or ignore()
|
||||
*/
|
||||
pendingIDsAsync: Task.async(function* CrashSubmit_pendingIDsAsync(maxFileDate) {
|
||||
let ids = [];
|
||||
let info = null;
|
||||
try {
|
||||
info = yield OS.File.stat(getDir("pending").path)
|
||||
} catch (ex) {
|
||||
/* pending dir doesn't exist, ignore */
|
||||
return ids;
|
||||
}
|
||||
|
||||
if (info.isDir) {
|
||||
let iterator = new OS.File.DirectoryIterator(getDir("pending").path);
|
||||
try {
|
||||
yield iterator.forEach(
|
||||
function onEntry(file) {
|
||||
if (file.name.endsWith(".dmp")) {
|
||||
return OS.File.exists(file.path + ".ignore")
|
||||
.then(ignoreExists => {
|
||||
if (!ignoreExists) {
|
||||
let id = file.name.slice(0, -4);
|
||||
if (UUID_REGEX.test(id)) {
|
||||
return OS.File.stat(file.path)
|
||||
.then(info => {
|
||||
if (info.lastAccessDate.valueOf() >
|
||||
maxFileDate.valueOf()) {
|
||||
ids.push(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Prune the saved dumps.
|
||||
*/
|
||||
pruneSavedDumps: function CrashSubmit_pruneSavedDumps() {
|
||||
pruneSavedDumps();
|
||||
},
|
||||
|
||||
// List of currently active submit objects
|
||||
_activeSubmissions: []
|
||||
};
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "InjectCrashReporter.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "client/windows/crash_generation/crash_generation_client.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "LoadLibraryRemote.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
using google_breakpad::CrashGenerationClient;
|
||||
using CrashReporter::GetChildNotificationPipe;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
InjectCrashRunnable::InjectCrashRunnable(DWORD pid)
|
||||
: mPID(pid)
|
||||
{
|
||||
nsCOMPtr<nsIFile> dll;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(dll));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
dll->Append(NS_LITERAL_STRING("breakpadinjector.dll"));
|
||||
dll->GetPath(mInjectorPath);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InjectCrashRunnable::Run()
|
||||
{
|
||||
if (mInjectorPath.IsEmpty())
|
||||
return NS_OK;
|
||||
|
||||
nsAutoHandle hProcess(
|
||||
OpenProcess(PROCESS_CREATE_THREAD |
|
||||
PROCESS_QUERY_INFORMATION |
|
||||
PROCESS_DUP_HANDLE |
|
||||
PROCESS_VM_OPERATION |
|
||||
PROCESS_VM_WRITE |
|
||||
PROCESS_VM_READ, FALSE, mPID));
|
||||
if (!hProcess) {
|
||||
NS_WARNING("Unable to open remote process handle for crashreporter injection.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void* proc = LoadRemoteLibraryAndGetAddress(hProcess, mInjectorPath.get(),
|
||||
"Start");
|
||||
if (!proc) {
|
||||
NS_WARNING("Unable to inject crashreporter DLL.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
HANDLE hRemotePipe =
|
||||
CrashGenerationClient::DuplicatePipeToClientProcess(
|
||||
NS_ConvertASCIItoUTF16(GetChildNotificationPipe()).get(),
|
||||
hProcess);
|
||||
if (INVALID_HANDLE_VALUE == hRemotePipe) {
|
||||
NS_WARNING("Unable to duplicate crash reporter pipe to process.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoHandle hThread(CreateRemoteThread(hProcess, nullptr, 0,
|
||||
(LPTHREAD_START_ROUTINE) proc,
|
||||
(void*) hRemotePipe, 0, nullptr));
|
||||
if (!hThread) {
|
||||
NS_WARNING("Unable to CreateRemoteThread");
|
||||
|
||||
// We have to close the remote pipe or else our crash generation client
|
||||
// will be stuck unable to accept other remote requests.
|
||||
HANDLE toClose = INVALID_HANDLE_VALUE;
|
||||
if (DuplicateHandle(hProcess, hRemotePipe, ::GetCurrentProcess(),
|
||||
&toClose, 0, FALSE,
|
||||
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
|
||||
CloseHandle(toClose);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef InjectCrashReporter_h
|
||||
#define InjectCrashReporter_h
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include <windows.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class InjectCrashRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
InjectCrashRunnable(DWORD pid);
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
private:
|
||||
DWORD mPID;
|
||||
nsString mInjectorPath;
|
||||
};
|
||||
|
||||
} // Namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"parseKeyValuePairsFromLines",
|
||||
"parseKeyValuePairs",
|
||||
"parseKeyValuePairsFromFile"
|
||||
];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
this.parseKeyValuePairsFromLines = function(lines) {
|
||||
let data = {};
|
||||
for (let line of lines) {
|
||||
if (line == '')
|
||||
continue;
|
||||
|
||||
// can't just .split() because the value might contain = characters
|
||||
let eq = line.indexOf('=');
|
||||
if (eq != -1) {
|
||||
let [key, value] = [line.substring(0, eq),
|
||||
line.substring(eq + 1)];
|
||||
if (key && value)
|
||||
data[key] = value.replace(/\\n/g, "\n").replace(/\\\\/g, "\\");
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
this.parseKeyValuePairs = function parseKeyValuePairs(text) {
|
||||
let lines = text.split('\n');
|
||||
return parseKeyValuePairsFromLines(lines);
|
||||
};
|
||||
|
||||
this.parseKeyValuePairsFromFile = function parseKeyValuePairsFromFile(file) {
|
||||
let fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
let is = Cc["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Ci.nsIConverterInputStream);
|
||||
is.init(fstream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
let str = {};
|
||||
let contents = '';
|
||||
while (is.readString(4096, str) != 0) {
|
||||
contents += str.value;
|
||||
}
|
||||
is.close();
|
||||
fstream.close();
|
||||
return parseKeyValuePairs(contents);
|
||||
}
|
||||
|
|
@ -1,454 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __GNUC__
|
||||
// disable warnings about pointer <-> DWORD conversions
|
||||
#pragma warning( disable : 4311 4312 )
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
#define POINTER_TYPE ULONGLONG
|
||||
#else
|
||||
#define POINTER_TYPE DWORD
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef DEBUG_OUTPUT
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
typedef const unsigned char* FileView;
|
||||
|
||||
template<>
|
||||
class nsAutoRefTraits<FileView>
|
||||
{
|
||||
public:
|
||||
typedef FileView RawRef;
|
||||
static FileView Void()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void Release(RawRef aView)
|
||||
{
|
||||
if (nullptr != aView)
|
||||
UnmapViewOfFile(aView);
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef IMAGE_SIZEOF_BASE_RELOCATION
|
||||
// Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!?
|
||||
#define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION))
|
||||
#endif
|
||||
|
||||
#include "LoadLibraryRemote.h"
|
||||
|
||||
typedef struct {
|
||||
PIMAGE_NT_HEADERS headers;
|
||||
unsigned char *localCodeBase;
|
||||
unsigned char *remoteCodeBase;
|
||||
HMODULE *modules;
|
||||
int numModules;
|
||||
} MEMORYMODULE, *PMEMORYMODULE;
|
||||
|
||||
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
|
||||
|
||||
#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
static void
|
||||
OutputLastError(const char *msg)
|
||||
{
|
||||
char* tmp;
|
||||
char *tmpmsg;
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR) &tmp, 0, nullptr);
|
||||
tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3);
|
||||
sprintf(tmpmsg, "%s: %s", msg, tmp);
|
||||
OutputDebugStringA(tmpmsg);
|
||||
LocalFree(tmpmsg);
|
||||
LocalFree(tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
|
||||
{
|
||||
int i;
|
||||
unsigned char *codeBase = module->localCodeBase;
|
||||
unsigned char *dest;
|
||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
|
||||
for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
|
||||
dest = codeBase + section->VirtualAddress;
|
||||
memset(dest, 0, section->Misc.VirtualSize);
|
||||
if (section->SizeOfRawData) {
|
||||
memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData);
|
||||
}
|
||||
// section->Misc.PhysicalAddress = (POINTER_TYPE) module->remoteCodeBase + section->VirtualAddress;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
CopyRegion(HANDLE hRemoteProcess, void* remoteAddress, void* localAddress, DWORD size, DWORD protect)
|
||||
{
|
||||
if (size > 0) {
|
||||
// Copy the data from local->remote and set the memory protection
|
||||
if (!VirtualAllocEx(hRemoteProcess, remoteAddress, size, MEM_COMMIT, PAGE_READWRITE))
|
||||
return false;
|
||||
|
||||
if (!WriteProcessMemory(hRemoteProcess,
|
||||
remoteAddress,
|
||||
localAddress,
|
||||
size,
|
||||
nullptr)) {
|
||||
#ifdef DEBUG_OUTPUT
|
||||
OutputLastError("Error writing remote memory.\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD oldProtect;
|
||||
if (VirtualProtectEx(hRemoteProcess, remoteAddress, size, protect, &oldProtect) == 0) {
|
||||
#ifdef DEBUG_OUTPUT
|
||||
OutputLastError("Error protecting memory page");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Protection flags for memory pages (Executable, Readable, Writeable)
|
||||
static int ProtectionFlags[2][2][2] = {
|
||||
{
|
||||
// not executable
|
||||
{PAGE_NOACCESS, PAGE_WRITECOPY},
|
||||
{PAGE_READONLY, PAGE_READWRITE},
|
||||
}, {
|
||||
// executable
|
||||
{PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY},
|
||||
{PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE},
|
||||
},
|
||||
};
|
||||
|
||||
static bool
|
||||
FinalizeSections(PMEMORYMODULE module, HANDLE hRemoteProcess)
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
fprintf(stderr, "Finalizing sections: local base %p, remote base %p\n",
|
||||
module->localCodeBase, module->remoteCodeBase);
|
||||
#endif
|
||||
|
||||
int i;
|
||||
int numSections = module->headers->FileHeader.NumberOfSections;
|
||||
|
||||
if (numSections < 1)
|
||||
return false;
|
||||
|
||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
|
||||
|
||||
// Copy any data before the first section (i.e. the image header)
|
||||
if (!CopyRegion(hRemoteProcess, module->remoteCodeBase, module->localCodeBase, section->VirtualAddress, PAGE_READONLY))
|
||||
return false;
|
||||
|
||||
// loop through all sections and change access flags
|
||||
for (i=0; i<numSections; i++, section++) {
|
||||
DWORD protect, size;
|
||||
int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
|
||||
int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0;
|
||||
int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
|
||||
|
||||
// determine protection flags based on characteristics
|
||||
protect = ProtectionFlags[executable][readable][writeable];
|
||||
if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) {
|
||||
protect |= PAGE_NOCACHE;
|
||||
}
|
||||
|
||||
void* remoteAddress = module->remoteCodeBase + section->VirtualAddress;
|
||||
void* localAddress = module->localCodeBase + section->VirtualAddress;
|
||||
|
||||
// determine size of region
|
||||
size = section->Misc.VirtualSize;
|
||||
#ifdef DEBUG_OUTPUT
|
||||
fprintf(stderr, "Copying section %s to %p, size %x, executable %i readable %i writeable %i\n",
|
||||
section->Name, remoteAddress, size, executable, readable, writeable);
|
||||
#endif
|
||||
if (!CopyRegion(hRemoteProcess, remoteAddress, localAddress, size, protect))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta)
|
||||
{
|
||||
DWORD i;
|
||||
unsigned char *codeBase = module->localCodeBase;
|
||||
|
||||
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
||||
if (directory->Size > 0) {
|
||||
PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress);
|
||||
for (; relocation->VirtualAddress > 0; ) {
|
||||
unsigned char *dest = codeBase + relocation->VirtualAddress;
|
||||
unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION);
|
||||
for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) {
|
||||
DWORD *patchAddrHL;
|
||||
#ifdef _WIN64
|
||||
ULONGLONG *patchAddr64;
|
||||
#endif
|
||||
int type, offset;
|
||||
|
||||
// the upper 4 bits define the type of relocation
|
||||
type = *relInfo >> 12;
|
||||
// the lower 12 bits define the offset
|
||||
offset = *relInfo & 0xfff;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case IMAGE_REL_BASED_ABSOLUTE:
|
||||
// skip relocation
|
||||
break;
|
||||
|
||||
case IMAGE_REL_BASED_HIGHLOW:
|
||||
// change complete 32 bit address
|
||||
patchAddrHL = (DWORD *) (dest + offset);
|
||||
*patchAddrHL += delta;
|
||||
break;
|
||||
|
||||
#ifdef _WIN64
|
||||
case IMAGE_REL_BASED_DIR64:
|
||||
patchAddr64 = (ULONGLONG *) (dest + offset);
|
||||
*patchAddr64 += delta;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
//printf("Unknown relocation: %d\n", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// advance to next relocation block
|
||||
relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
BuildImportTable(PMEMORYMODULE module)
|
||||
{
|
||||
int result=1;
|
||||
unsigned char *codeBase = module->localCodeBase;
|
||||
|
||||
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
if (directory->Size > 0) {
|
||||
PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress);
|
||||
PIMAGE_IMPORT_DESCRIPTOR importEnd = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress + directory->Size);
|
||||
|
||||
for (; importDesc < importEnd && importDesc->Name; importDesc++) {
|
||||
POINTER_TYPE *thunkRef;
|
||||
FARPROC *funcRef;
|
||||
HMODULE handle = GetModuleHandleA((LPCSTR) (codeBase + importDesc->Name));
|
||||
if (handle == nullptr) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Can't load library");
|
||||
#endif
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
module->modules = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE)));
|
||||
if (module->modules == nullptr) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
module->modules[module->numModules++] = handle;
|
||||
if (importDesc->OriginalFirstThunk) {
|
||||
thunkRef = (POINTER_TYPE *) (codeBase + importDesc->OriginalFirstThunk);
|
||||
funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
|
||||
} else {
|
||||
// no hint table
|
||||
thunkRef = (POINTER_TYPE *) (codeBase + importDesc->FirstThunk);
|
||||
funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
|
||||
}
|
||||
for (; *thunkRef; thunkRef++, funcRef++) {
|
||||
if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) {
|
||||
*funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef));
|
||||
} else {
|
||||
PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef));
|
||||
*funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)&thunkData->Name);
|
||||
}
|
||||
if (*funcRef == 0) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void* MemoryGetProcAddress(PMEMORYMODULE module, const char *name);
|
||||
|
||||
void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess,
|
||||
const WCHAR* library,
|
||||
const char* symbol)
|
||||
{
|
||||
// Map the DLL into memory
|
||||
nsAutoHandle hLibrary(
|
||||
CreateFile(library, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
if (INVALID_HANDLE_VALUE == hLibrary) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Couldn't CreateFile the library.\n");
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoHandle hMapping(
|
||||
CreateFileMapping(hLibrary, nullptr, PAGE_READONLY, 0, 0, nullptr));
|
||||
if (!hMapping) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Couldn't CreateFileMapping.\n");
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoRef<FileView> data(
|
||||
(const unsigned char*) MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (!data) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Couldn't MapViewOfFile.\n");
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SIZE_T locationDelta;
|
||||
|
||||
PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)data.get();
|
||||
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputDebugStringA("Not a valid executable file.\n");
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS old_header = (PIMAGE_NT_HEADERS)(data + dos_header->e_lfanew);
|
||||
if (old_header->Signature != IMAGE_NT_SIGNATURE) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputDebugStringA("No PE header found.\n");
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// reserve memory for image of library in this process and the target process
|
||||
unsigned char* localCode = (unsigned char*) VirtualAlloc(nullptr,
|
||||
old_header->OptionalHeader.SizeOfImage,
|
||||
MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
if (!localCode) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Can't reserve local memory.");
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned char* remoteCode = (unsigned char*) VirtualAllocEx(hRemoteProcess, nullptr,
|
||||
old_header->OptionalHeader.SizeOfImage,
|
||||
MEM_RESERVE,
|
||||
PAGE_EXECUTE_READ);
|
||||
if (!remoteCode) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Can't reserve remote memory.");
|
||||
#endif
|
||||
}
|
||||
|
||||
MEMORYMODULE result;
|
||||
result.localCodeBase = localCode;
|
||||
result.remoteCodeBase = remoteCode;
|
||||
result.numModules = 0;
|
||||
result.modules = nullptr;
|
||||
|
||||
// copy PE header to code
|
||||
memcpy(localCode, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders);
|
||||
result.headers = reinterpret_cast<PIMAGE_NT_HEADERS>(localCode + dos_header->e_lfanew);
|
||||
|
||||
// update position
|
||||
result.headers->OptionalHeader.ImageBase = (POINTER_TYPE)remoteCode;
|
||||
|
||||
// copy sections from DLL file block to new memory location
|
||||
CopySections(data, old_header, &result);
|
||||
|
||||
// adjust base address of imported data
|
||||
locationDelta = (SIZE_T)(remoteCode - old_header->OptionalHeader.ImageBase);
|
||||
if (locationDelta != 0) {
|
||||
PerformBaseRelocation(&result, locationDelta);
|
||||
}
|
||||
|
||||
// load required dlls and adjust function table of imports
|
||||
if (!BuildImportTable(&result)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// mark memory pages depending on section headers and release
|
||||
// sections that are marked as "discardable"
|
||||
if (!FinalizeSections(&result, hRemoteProcess)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return MemoryGetProcAddress(&result, symbol);
|
||||
}
|
||||
|
||||
static void* MemoryGetProcAddress(PMEMORYMODULE module, const char *name)
|
||||
{
|
||||
unsigned char *localCodeBase = module->localCodeBase;
|
||||
int idx=-1;
|
||||
DWORD i, *nameRef;
|
||||
WORD *ordinal;
|
||||
PIMAGE_EXPORT_DIRECTORY exports;
|
||||
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT);
|
||||
if (directory->Size == 0) {
|
||||
// no export table found
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
exports = (PIMAGE_EXPORT_DIRECTORY) (localCodeBase + directory->VirtualAddress);
|
||||
if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) {
|
||||
// DLL doesn't export anything
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// search function name in list of exported names
|
||||
nameRef = (DWORD *) (localCodeBase + exports->AddressOfNames);
|
||||
ordinal = (WORD *) (localCodeBase + exports->AddressOfNameOrdinals);
|
||||
for (i=0; i<exports->NumberOfNames; i++, nameRef++, ordinal++) {
|
||||
if (stricmp(name, (const char *) (localCodeBase + (*nameRef))) == 0) {
|
||||
idx = *ordinal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx == -1) {
|
||||
// exported symbol not found
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((DWORD)idx > exports->NumberOfFunctions) {
|
||||
// name <-> ordinal number don't match
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// AddressOfFunctions contains the RVAs to the "real" functions
|
||||
return module->remoteCodeBase + (*(DWORD *) (localCodeBase + exports->AddressOfFunctions + (idx*4)));
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef LoadLibraryRemote_h
|
||||
#define LoadLibraryRemote_h
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/**
|
||||
* Inject a library into a remote process. This injection has the following
|
||||
* restrictions:
|
||||
*
|
||||
* - The DLL being injected must only depend on kernel32 and user32.
|
||||
* - The entry point of the DLL is not run. If the DLL uses the CRT, it is
|
||||
* the responsibility of the caller to make sure that _CRT_INIT is called.
|
||||
* - There is no support for unloading a library once it has been loaded.
|
||||
* - The symbol must be a named symbol and not an ordinal.
|
||||
*/
|
||||
void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess,
|
||||
const WCHAR* library,
|
||||
const char* symbol);
|
||||
|
||||
#endif // LoadLibraryRemote_h
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +0,0 @@
|
|||
Do not land local patches to Breakpad without the approval of
|
||||
Ted Mielczarek <ted@mielczarek.org>
|
||||
|
||||
All local patches must be in the process of being upstreamed.
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
SOURCES += [
|
||||
'../google-breakpad/src/common/windows/http_upload.cc',
|
||||
]
|
||||
|
||||
Library('google_breakpad_libxul_s')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
for var in ('UNICODE', 'UNICODE_', 'BREAKPAD_NO_TERMINATE_THREAD'):
|
||||
DEFINES[var] = True
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/toolkit/crashreporter/google-breakpad/src',
|
||||
]
|
||||
|
||||
include('/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild')
|
||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild')
|
||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/sender/objs.mozbuild')
|
||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/objs.mozbuild')
|
||||
|
||||
SOURCES += objs_common
|
||||
SOURCES += objs_crash_generation
|
||||
SOURCES += objs_handler
|
||||
SOURCES += objs_sender
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
FINAL_LIBRARY = 'breakpadinjector'
|
||||
|
||||
for var in ('UNICODE', 'UNICODE_', 'BREAKPAD_NO_TERMINATE_THREAD'):
|
||||
DEFINES[var] = True
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/toolkit/crashreporter/google-breakpad/src',
|
||||
]
|
||||
|
||||
include('/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild')
|
||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild')
|
||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/objs.mozbuild')
|
||||
|
||||
SOURCES += objs_common
|
||||
SOURCES += objs_crash_generation
|
||||
SOURCES += objs_handler
|
||||
|
||||
USE_STATIC_LIBS = True
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
# vim:set ts=8 sw=8 sts=8 noet:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
MOZ_WINCONSOLE = 0
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
ifeq ($(OS_ARCH),Darwin)
|
||||
libs::
|
||||
$(NSINSTALL) -D $(DIST)/bin/crashreporter.app
|
||||
rsync -a -C --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/bin/crashreporter.app
|
||||
sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \
|
||||
iconv -f UTF-8 -t UTF-16 > $(DIST)/bin/crashreporter.app/Contents/Resources/English.lproj/InfoPlist.strings
|
||||
$(NSINSTALL) -D $(DIST)/bin/crashreporter.app/Contents/MacOS
|
||||
$(NSINSTALL) $(DIST)/bin/crashreporter $(DIST)/bin/crashreporter.app/Contents/MacOS
|
||||
endif
|
||||
Binary file not shown.
|
|
@ -1,759 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "crashreporter.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Disable exception handler warnings.
|
||||
# pragma warning( disable : 4530 )
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
using std::string;
|
||||
using std::istream;
|
||||
using std::ifstream;
|
||||
using std::istringstream;
|
||||
using std::ostringstream;
|
||||
using std::ostream;
|
||||
using std::ofstream;
|
||||
using std::vector;
|
||||
using std::auto_ptr;
|
||||
|
||||
namespace CrashReporter {
|
||||
|
||||
StringTable gStrings;
|
||||
string gSettingsPath;
|
||||
string gEventsPath;
|
||||
int gArgc;
|
||||
char** gArgv;
|
||||
|
||||
enum SubmissionResult {Succeeded, Failed};
|
||||
|
||||
static auto_ptr<ofstream> gLogStream(nullptr);
|
||||
static string gReporterDumpFile;
|
||||
static string gExtraFile;
|
||||
static string gMemoryFile;
|
||||
|
||||
static const char kExtraDataExtension[] = ".extra";
|
||||
static const char kMemoryReportExtension[] = ".memory.json.gz";
|
||||
|
||||
void UIError(const string& message)
|
||||
{
|
||||
string errorMessage;
|
||||
if (!gStrings[ST_CRASHREPORTERERROR].empty()) {
|
||||
char buf[2048];
|
||||
UI_SNPRINTF(buf, 2048,
|
||||
gStrings[ST_CRASHREPORTERERROR].c_str(),
|
||||
message.c_str());
|
||||
errorMessage = buf;
|
||||
} else {
|
||||
errorMessage = message;
|
||||
}
|
||||
|
||||
UIError_impl(errorMessage);
|
||||
}
|
||||
|
||||
static string Unescape(const string& str)
|
||||
{
|
||||
string ret;
|
||||
for (string::const_iterator iter = str.begin();
|
||||
iter != str.end();
|
||||
iter++) {
|
||||
if (*iter == '\\') {
|
||||
iter++;
|
||||
if (*iter == '\\'){
|
||||
ret.push_back('\\');
|
||||
} else if (*iter == 'n') {
|
||||
ret.push_back('\n');
|
||||
} else if (*iter == 't') {
|
||||
ret.push_back('\t');
|
||||
}
|
||||
} else {
|
||||
ret.push_back(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static string Escape(const string& str)
|
||||
{
|
||||
string ret;
|
||||
for (string::const_iterator iter = str.begin();
|
||||
iter != str.end();
|
||||
iter++) {
|
||||
if (*iter == '\\') {
|
||||
ret += "\\\\";
|
||||
} else if (*iter == '\n') {
|
||||
ret += "\\n";
|
||||
} else if (*iter == '\t') {
|
||||
ret += "\\t";
|
||||
} else {
|
||||
ret.push_back(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ReadStrings(istream& in, StringTable& strings, bool unescape)
|
||||
{
|
||||
string currentSection;
|
||||
while (!in.eof()) {
|
||||
string line;
|
||||
std::getline(in, line);
|
||||
int sep = line.find('=');
|
||||
if (sep >= 0) {
|
||||
string key, value;
|
||||
key = line.substr(0, sep);
|
||||
value = line.substr(sep + 1);
|
||||
if (unescape)
|
||||
value = Unescape(value);
|
||||
strings[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadStringsFromFile(const string& path,
|
||||
StringTable& strings,
|
||||
bool unescape)
|
||||
{
|
||||
ifstream* f = UIOpenRead(path);
|
||||
bool success = false;
|
||||
if (f->is_open()) {
|
||||
success = ReadStrings(*f, strings, unescape);
|
||||
f->close();
|
||||
}
|
||||
|
||||
delete f;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool WriteStrings(ostream& out,
|
||||
const string& header,
|
||||
StringTable& strings,
|
||||
bool escape)
|
||||
{
|
||||
out << "[" << header << "]" << std::endl;
|
||||
for (StringTable::iterator iter = strings.begin();
|
||||
iter != strings.end();
|
||||
iter++) {
|
||||
out << iter->first << "=";
|
||||
if (escape)
|
||||
out << Escape(iter->second);
|
||||
else
|
||||
out << iter->second;
|
||||
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteStringsToFile(const string& path,
|
||||
const string& header,
|
||||
StringTable& strings,
|
||||
bool escape)
|
||||
{
|
||||
ofstream* f = UIOpenWrite(path.c_str());
|
||||
bool success = false;
|
||||
if (f->is_open()) {
|
||||
success = WriteStrings(*f, header, strings, escape);
|
||||
f->close();
|
||||
}
|
||||
|
||||
delete f;
|
||||
return success;
|
||||
}
|
||||
|
||||
static string Basename(const string& file)
|
||||
{
|
||||
string::size_type slashIndex = file.rfind(UI_DIR_SEPARATOR);
|
||||
if (slashIndex != string::npos)
|
||||
return file.substr(slashIndex + 1);
|
||||
else
|
||||
return file;
|
||||
}
|
||||
|
||||
static string GetDumpLocalID()
|
||||
{
|
||||
string localId = Basename(gReporterDumpFile);
|
||||
string::size_type dot = localId.rfind('.');
|
||||
|
||||
if (dot == string::npos)
|
||||
return "";
|
||||
|
||||
return localId.substr(0, dot);
|
||||
}
|
||||
|
||||
// This appends the StackTraces entry generated by the minidump analyzer to the
|
||||
// main crash event so that it can be picked up by Firefox once it restarts
|
||||
static void AppendStackTracesToEventFile(const string& aStackTraces)
|
||||
{
|
||||
if (gEventsPath.empty()) {
|
||||
// If there is no path for finding the crash event, skip this step.
|
||||
return;
|
||||
}
|
||||
|
||||
string localId = GetDumpLocalID();
|
||||
string path = gEventsPath + UI_DIR_SEPARATOR + localId;
|
||||
ofstream* f = UIOpenWrite(path.c_str(), true);
|
||||
|
||||
if (f->is_open()) {
|
||||
*f << "StackTraces=" << aStackTraces;
|
||||
f->close();
|
||||
}
|
||||
|
||||
delete f;
|
||||
}
|
||||
|
||||
static void WriteSubmissionEvent(SubmissionResult result,
|
||||
const string& remoteId)
|
||||
{
|
||||
if (gEventsPath.empty()) {
|
||||
// If there is no path for writing the submission event, skip it.
|
||||
return;
|
||||
}
|
||||
|
||||
string localId = GetDumpLocalID();
|
||||
string fpath = gEventsPath + UI_DIR_SEPARATOR + localId + "-submission";
|
||||
ofstream* f = UIOpenWrite(fpath.c_str(), false, true);
|
||||
time_t tm;
|
||||
time(&tm);
|
||||
|
||||
if (f->is_open()) {
|
||||
*f << "crash.submission.1\n";
|
||||
*f << tm << "\n";
|
||||
*f << localId << "\n";
|
||||
*f << (result == Succeeded ? "true" : "false") << "\n";
|
||||
*f << remoteId;
|
||||
|
||||
f->close();
|
||||
}
|
||||
|
||||
delete f;
|
||||
}
|
||||
|
||||
void LogMessage(const std::string& message)
|
||||
{
|
||||
if (gLogStream.get()) {
|
||||
char date[64];
|
||||
time_t tm;
|
||||
time(&tm);
|
||||
if (strftime(date, sizeof(date) - 1, "%c", localtime(&tm)) == 0)
|
||||
date[0] = '\0';
|
||||
(*gLogStream) << "[" << date << "] " << message << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void OpenLogFile()
|
||||
{
|
||||
string logPath = gSettingsPath + UI_DIR_SEPARATOR + "submit.log";
|
||||
gLogStream.reset(UIOpenWrite(logPath.c_str(), true));
|
||||
}
|
||||
|
||||
static bool ReadConfig()
|
||||
{
|
||||
string iniPath;
|
||||
if (!UIGetIniPath(iniPath))
|
||||
return false;
|
||||
|
||||
if (!ReadStringsFromFile(iniPath, gStrings, true))
|
||||
return false;
|
||||
|
||||
// See if we have a string override file, if so process it
|
||||
char* overrideEnv = getenv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE");
|
||||
if (overrideEnv && *overrideEnv && UIFileExists(overrideEnv))
|
||||
ReadStringsFromFile(overrideEnv, gStrings, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static string
|
||||
GetAdditionalFilename(const string& dumpfile, const char* extension)
|
||||
{
|
||||
string filename(dumpfile);
|
||||
int dot = filename.rfind('.');
|
||||
if (dot < 0)
|
||||
return "";
|
||||
|
||||
filename.replace(dot, filename.length() - dot, extension);
|
||||
return filename;
|
||||
}
|
||||
|
||||
static bool MoveCrashData(const string& toDir,
|
||||
string& dumpfile,
|
||||
string& extrafile,
|
||||
string& memoryfile)
|
||||
{
|
||||
if (!UIEnsurePathExists(toDir)) {
|
||||
UIError(gStrings[ST_ERROR_CREATEDUMPDIR]);
|
||||
return false;
|
||||
}
|
||||
|
||||
string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile);
|
||||
string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile);
|
||||
string newMemory = toDir + UI_DIR_SEPARATOR + Basename(memoryfile);
|
||||
|
||||
if (!UIMoveFile(dumpfile, newDump)) {
|
||||
UIError(gStrings[ST_ERROR_DUMPFILEMOVE]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!UIMoveFile(extrafile, newExtra)) {
|
||||
UIError(gStrings[ST_ERROR_EXTRAFILEMOVE]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!memoryfile.empty()) {
|
||||
// Ignore errors from moving the memory file
|
||||
if (!UIMoveFile(memoryfile, newMemory)) {
|
||||
UIDeleteFile(memoryfile);
|
||||
newMemory.erase();
|
||||
}
|
||||
memoryfile = newMemory;
|
||||
}
|
||||
|
||||
dumpfile = newDump;
|
||||
extrafile = newExtra;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool AddSubmittedReport(const string& serverResponse)
|
||||
{
|
||||
StringTable responseItems;
|
||||
istringstream in(serverResponse);
|
||||
ReadStrings(in, responseItems, false);
|
||||
|
||||
if (responseItems.find("StopSendingReportsFor") != responseItems.end()) {
|
||||
// server wants to tell us to stop sending reports for a certain version
|
||||
string reportPath =
|
||||
gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" +
|
||||
responseItems["StopSendingReportsFor"];
|
||||
|
||||
ofstream* reportFile = UIOpenWrite(reportPath);
|
||||
if (reportFile->is_open()) {
|
||||
// don't really care about the contents
|
||||
*reportFile << 1 << "\n";
|
||||
reportFile->close();
|
||||
}
|
||||
delete reportFile;
|
||||
}
|
||||
|
||||
if (responseItems.find("Discarded") != responseItems.end()) {
|
||||
// server discarded this report... save it so the user can resubmit it
|
||||
// manually
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseItems.find("CrashID") == responseItems.end())
|
||||
return false;
|
||||
|
||||
string submittedDir =
|
||||
gSettingsPath + UI_DIR_SEPARATOR + "submitted";
|
||||
if (!UIEnsurePathExists(submittedDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string path = submittedDir + UI_DIR_SEPARATOR +
|
||||
responseItems["CrashID"] + ".txt";
|
||||
|
||||
ofstream* file = UIOpenWrite(path);
|
||||
if (!file->is_open()) {
|
||||
delete file;
|
||||
return false;
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
UI_SNPRINTF(buf, 1024,
|
||||
gStrings["CrashID"].c_str(),
|
||||
responseItems["CrashID"].c_str());
|
||||
*file << buf << "\n";
|
||||
|
||||
if (responseItems.find("ViewURL") != responseItems.end()) {
|
||||
UI_SNPRINTF(buf, 1024,
|
||||
gStrings["CrashDetailsURL"].c_str(),
|
||||
responseItems["ViewURL"].c_str());
|
||||
*file << buf << "\n";
|
||||
}
|
||||
|
||||
file->close();
|
||||
delete file;
|
||||
|
||||
WriteSubmissionEvent(Succeeded, responseItems["CrashID"]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeleteDump()
|
||||
{
|
||||
const char* noDelete = getenv("MOZ_CRASHREPORTER_NO_DELETE_DUMP");
|
||||
if (!noDelete || *noDelete == '\0') {
|
||||
if (!gReporterDumpFile.empty())
|
||||
UIDeleteFile(gReporterDumpFile);
|
||||
if (!gExtraFile.empty())
|
||||
UIDeleteFile(gExtraFile);
|
||||
if (!gMemoryFile.empty())
|
||||
UIDeleteFile(gMemoryFile);
|
||||
}
|
||||
}
|
||||
|
||||
void SendCompleted(bool success, const string& serverResponse)
|
||||
{
|
||||
if (success) {
|
||||
if (AddSubmittedReport(serverResponse)) {
|
||||
DeleteDump();
|
||||
}
|
||||
else {
|
||||
string directory = gReporterDumpFile;
|
||||
int slashpos = directory.find_last_of("/\\");
|
||||
if (slashpos < 2)
|
||||
return;
|
||||
directory.resize(slashpos);
|
||||
UIPruneSavedDumps(directory);
|
||||
WriteSubmissionEvent(Failed, "");
|
||||
}
|
||||
} else {
|
||||
WriteSubmissionEvent(Failed, "");
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldEnableSending()
|
||||
{
|
||||
srand(time(0));
|
||||
return ((rand() % 100) < MOZ_CRASHREPORTER_ENABLE_PERCENT);
|
||||
}
|
||||
|
||||
} // namespace CrashReporter
|
||||
|
||||
using namespace CrashReporter;
|
||||
|
||||
void RewriteStrings(StringTable& queryParameters)
|
||||
{
|
||||
// rewrite some UI strings with the values from the query parameters
|
||||
string product = queryParameters["ProductName"];
|
||||
string vendor = queryParameters["Vendor"];
|
||||
if (vendor.empty()) {
|
||||
// Assume Mozilla if no vendor is specified
|
||||
vendor = "Mozilla";
|
||||
}
|
||||
|
||||
char buf[4096];
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_CRASHREPORTERVENDORTITLE].c_str(),
|
||||
vendor.c_str());
|
||||
gStrings[ST_CRASHREPORTERTITLE] = buf;
|
||||
|
||||
|
||||
string str = gStrings[ST_CRASHREPORTERPRODUCTERROR];
|
||||
// Only do the replacement here if the string has two
|
||||
// format specifiers to start. Otherwise
|
||||
// we assume it has the product name hardcoded.
|
||||
string::size_type pos = str.find("%s");
|
||||
if (pos != string::npos)
|
||||
pos = str.find("%s", pos+2);
|
||||
if (pos != string::npos) {
|
||||
// Leave a format specifier for UIError to fill in
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_CRASHREPORTERPRODUCTERROR].c_str(),
|
||||
product.c_str(),
|
||||
"%s");
|
||||
gStrings[ST_CRASHREPORTERERROR] = buf;
|
||||
}
|
||||
else {
|
||||
// product name is hardcoded
|
||||
gStrings[ST_CRASHREPORTERERROR] = str;
|
||||
}
|
||||
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(),
|
||||
product.c_str());
|
||||
gStrings[ST_CRASHREPORTERDESCRIPTION] = buf;
|
||||
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_CHECKSUBMIT].c_str(),
|
||||
vendor.c_str());
|
||||
gStrings[ST_CHECKSUBMIT] = buf;
|
||||
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_CHECKEMAIL].c_str(),
|
||||
vendor.c_str());
|
||||
gStrings[ST_CHECKEMAIL] = buf;
|
||||
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_RESTART].c_str(),
|
||||
product.c_str());
|
||||
gStrings[ST_RESTART] = buf;
|
||||
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_QUIT].c_str(),
|
||||
product.c_str());
|
||||
gStrings[ST_QUIT] = buf;
|
||||
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_ERROR_ENDOFLIFE].c_str(),
|
||||
product.c_str());
|
||||
gStrings[ST_ERROR_ENDOFLIFE] = buf;
|
||||
}
|
||||
|
||||
bool CheckEndOfLifed(string version)
|
||||
{
|
||||
string reportPath =
|
||||
gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + version;
|
||||
return UIFileExists(reportPath);
|
||||
}
|
||||
|
||||
#ifndef RELEASE_OR_BETA
|
||||
|
||||
static string
|
||||
GetMinidumpAnalyzerPath()
|
||||
{
|
||||
string path = gArgv[0];
|
||||
size_t pos = path.rfind(UI_CRASH_REPORTER_FILENAME BIN_SUFFIX);
|
||||
path.erase(pos);
|
||||
path.append(UI_MINIDUMP_ANALYZER_FILENAME BIN_SUFFIX);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
gArgc = argc;
|
||||
gArgv = argv;
|
||||
|
||||
if (!ReadConfig()) {
|
||||
UIError("Couldn't read configuration.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!UIInit())
|
||||
return 0;
|
||||
|
||||
if (argc > 1) {
|
||||
gReporterDumpFile = argv[1];
|
||||
}
|
||||
|
||||
if (gReporterDumpFile.empty()) {
|
||||
// no dump file specified, run the default UI
|
||||
UIShowDefaultUI();
|
||||
} else {
|
||||
#ifndef RELEASE_OR_BETA
|
||||
// start by running minidump analyzer, this is currently enabled only in
|
||||
// nightly and aurora
|
||||
UIRunMinidumpAnalyzer(GetMinidumpAnalyzerPath(), gReporterDumpFile);
|
||||
#endif
|
||||
|
||||
// go ahead with the crash reporter
|
||||
gExtraFile = GetAdditionalFilename(gReporterDumpFile, kExtraDataExtension);
|
||||
if (gExtraFile.empty()) {
|
||||
UIError(gStrings[ST_ERROR_BADARGUMENTS]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!UIFileExists(gExtraFile)) {
|
||||
UIError(gStrings[ST_ERROR_EXTRAFILEEXISTS]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gMemoryFile = GetAdditionalFilename(gReporterDumpFile,
|
||||
kMemoryReportExtension);
|
||||
if (!UIFileExists(gMemoryFile)) {
|
||||
gMemoryFile.erase();
|
||||
}
|
||||
|
||||
StringTable queryParameters;
|
||||
if (!ReadStringsFromFile(gExtraFile, queryParameters, true)) {
|
||||
UIError(gStrings[ST_ERROR_EXTRAFILEREAD]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (queryParameters.find("ProductName") == queryParameters.end()) {
|
||||
UIError(gStrings[ST_ERROR_NOPRODUCTNAME]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// There is enough information in the extra file to rewrite strings
|
||||
// to be product specific
|
||||
RewriteStrings(queryParameters);
|
||||
|
||||
if (queryParameters.find("ServerURL") == queryParameters.end()) {
|
||||
UIError(gStrings[ST_ERROR_NOSERVERURL]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Hopefully the settings path exists in the environment. Try that before
|
||||
// asking the platform-specific code to guess.
|
||||
#ifdef XP_WIN32
|
||||
static const wchar_t kDataDirKey[] = L"MOZ_CRASHREPORTER_DATA_DIRECTORY";
|
||||
const wchar_t *settingsPath = _wgetenv(kDataDirKey);
|
||||
if (settingsPath && *settingsPath) {
|
||||
gSettingsPath = WideToUTF8(settingsPath);
|
||||
}
|
||||
#else
|
||||
static const char kDataDirKey[] = "MOZ_CRASHREPORTER_DATA_DIRECTORY";
|
||||
const char *settingsPath = getenv(kDataDirKey);
|
||||
if (settingsPath && *settingsPath) {
|
||||
gSettingsPath = settingsPath;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
string product = queryParameters["ProductName"];
|
||||
string vendor = queryParameters["Vendor"];
|
||||
if (!UIGetSettingsPath(vendor, product, gSettingsPath)) {
|
||||
gSettingsPath.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (gSettingsPath.empty() || !UIEnsurePathExists(gSettingsPath)) {
|
||||
UIError(gStrings[ST_ERROR_NOSETTINGSPATH]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
OpenLogFile();
|
||||
|
||||
#ifdef XP_WIN32
|
||||
static const wchar_t kEventsDirKey[] = L"MOZ_CRASHREPORTER_EVENTS_DIRECTORY";
|
||||
const wchar_t *eventsPath = _wgetenv(kEventsDirKey);
|
||||
if (eventsPath && *eventsPath) {
|
||||
gEventsPath = WideToUTF8(eventsPath);
|
||||
}
|
||||
#else
|
||||
static const char kEventsDirKey[] = "MOZ_CRASHREPORTER_EVENTS_DIRECTORY";
|
||||
const char *eventsPath = getenv(kEventsDirKey);
|
||||
if (eventsPath && *eventsPath) {
|
||||
gEventsPath = eventsPath;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
gEventsPath.clear();
|
||||
}
|
||||
|
||||
// Update the crash event with stacks if they are present
|
||||
auto stackTracesItr = queryParameters.find("StackTraces");
|
||||
if (stackTracesItr != queryParameters.end()) {
|
||||
AppendStackTracesToEventFile(stackTracesItr->second);
|
||||
}
|
||||
|
||||
if (!UIFileExists(gReporterDumpFile)) {
|
||||
UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending";
|
||||
if (!MoveCrashData(pendingDir, gReporterDumpFile, gExtraFile,
|
||||
gMemoryFile)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
string sendURL = queryParameters["ServerURL"];
|
||||
// we don't need to actually send this
|
||||
queryParameters.erase("ServerURL");
|
||||
|
||||
queryParameters["Throttleable"] = "1";
|
||||
|
||||
// re-set XUL_APP_FILE for xulrunner wrapped apps
|
||||
const char *appfile = getenv("MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE");
|
||||
if (appfile && *appfile) {
|
||||
const char prefix[] = "XUL_APP_FILE=";
|
||||
char *env = (char*) malloc(strlen(appfile) + strlen(prefix) + 1);
|
||||
if (!env) {
|
||||
UIError("Out of memory");
|
||||
return 0;
|
||||
}
|
||||
strcpy(env, prefix);
|
||||
strcat(env, appfile);
|
||||
putenv(env);
|
||||
free(env);
|
||||
}
|
||||
|
||||
vector<string> restartArgs;
|
||||
|
||||
ostringstream paramName;
|
||||
int i = 0;
|
||||
paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
|
||||
const char *param = getenv(paramName.str().c_str());
|
||||
while (param && *param) {
|
||||
restartArgs.push_back(param);
|
||||
|
||||
paramName.str("");
|
||||
paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
|
||||
param = getenv(paramName.str().c_str());
|
||||
}
|
||||
|
||||
// allow override of the server url via environment variable
|
||||
//XXX: remove this in the far future when our robot
|
||||
// masters force everyone to use XULRunner
|
||||
char* urlEnv = getenv("MOZ_CRASHREPORTER_URL");
|
||||
if (urlEnv && *urlEnv) {
|
||||
sendURL = urlEnv;
|
||||
}
|
||||
|
||||
// see if this version has been end-of-lifed
|
||||
if (queryParameters.find("Version") != queryParameters.end() &&
|
||||
CheckEndOfLifed(queryParameters["Version"])) {
|
||||
UIError(gStrings[ST_ERROR_ENDOFLIFE]);
|
||||
DeleteDump();
|
||||
return 0;
|
||||
}
|
||||
|
||||
StringTable files;
|
||||
files["upload_file_minidump"] = gReporterDumpFile;
|
||||
if (!gMemoryFile.empty()) {
|
||||
files["memory_report"] = gMemoryFile;
|
||||
}
|
||||
|
||||
if (!UIShowCrashUI(files, queryParameters, sendURL, restartArgs))
|
||||
DeleteDump();
|
||||
}
|
||||
|
||||
UIShutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN) && !defined(__GNUC__)
|
||||
#include <windows.h>
|
||||
|
||||
// We need WinMain in order to not be a console app. This function is unused
|
||||
// if we are a console application.
|
||||
int WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR args, int )
|
||||
{
|
||||
// Remove everything except close window from the context menu
|
||||
{
|
||||
HKEY hkApp;
|
||||
RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications", 0,
|
||||
nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr,
|
||||
&hkApp, nullptr);
|
||||
RegCloseKey(hkApp);
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER,
|
||||
L"Software\\Classes\\Applications\\crashreporter.exe",
|
||||
0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE,
|
||||
nullptr, &hkApp, nullptr) == ERROR_SUCCESS) {
|
||||
RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0);
|
||||
RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0);
|
||||
RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0);
|
||||
RegCloseKey(hkApp);
|
||||
}
|
||||
}
|
||||
|
||||
char** argv = static_cast<char**>(malloc(__argc * sizeof(char*)));
|
||||
for (int i = 0; i < __argc; i++) {
|
||||
argv[i] = strdup(WideToUTF8(__wargv[i]).c_str());
|
||||
}
|
||||
|
||||
// Do the real work.
|
||||
return main(__argc, argv);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
version="1.0.0.0"
|
||||
processorArchitecture="*"
|
||||
name="CrashReporter"
|
||||
type="win32"
|
||||
/>
|
||||
<description>Crash Reporter</description>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<ms_asmv3:security>
|
||||
<ms_asmv3:requestedPrivileges>
|
||||
<ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</ms_asmv3:requestedPrivileges>
|
||||
</ms_asmv3:security>
|
||||
</ms_asmv3:trustInfo>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef CRASHREPORTER_H__
|
||||
#define CRASHREPORTER_H__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( push )
|
||||
// Disable exception handler warnings.
|
||||
# pragma warning( disable : 4530 )
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define MAX_COMMENT_LENGTH 500
|
||||
|
||||
#if defined(XP_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define UI_SNPRINTF _snprintf
|
||||
#define UI_DIR_SEPARATOR "\\"
|
||||
|
||||
std::string WideToUTF8(const std::wstring& wide, bool* success = 0);
|
||||
|
||||
#else
|
||||
|
||||
#define UI_SNPRINTF snprintf
|
||||
#define UI_DIR_SEPARATOR "/"
|
||||
|
||||
#endif
|
||||
|
||||
#define UI_CRASH_REPORTER_FILENAME "crashreporter"
|
||||
#define UI_MINIDUMP_ANALYZER_FILENAME "minidump-analyzer"
|
||||
|
||||
typedef std::map<std::string, std::string> StringTable;
|
||||
|
||||
#define ST_CRASHREPORTERTITLE "CrashReporterTitle"
|
||||
#define ST_CRASHREPORTERVENDORTITLE "CrashReporterVendorTitle"
|
||||
#define ST_CRASHREPORTERERROR "CrashReporterErrorText"
|
||||
#define ST_CRASHREPORTERPRODUCTERROR "CrashReporterProductErrorText2"
|
||||
#define ST_CRASHREPORTERHEADER "CrashReporterSorry"
|
||||
#define ST_CRASHREPORTERDESCRIPTION "CrashReporterDescriptionText2"
|
||||
#define ST_CRASHREPORTERDEFAULT "CrashReporterDefault"
|
||||
#define ST_VIEWREPORT "Details"
|
||||
#define ST_VIEWREPORTTITLE "ViewReportTitle"
|
||||
#define ST_COMMENTGRAYTEXT "CommentGrayText"
|
||||
#define ST_EXTRAREPORTINFO "ExtraReportInfo"
|
||||
#define ST_CHECKSUBMIT "CheckSendReport"
|
||||
#define ST_CHECKURL "CheckIncludeURL"
|
||||
#define ST_CHECKEMAIL "CheckAllowEmail"
|
||||
#define ST_EMAILGRAYTEXT "EmailGrayText"
|
||||
#define ST_REPORTPRESUBMIT "ReportPreSubmit2"
|
||||
#define ST_REPORTDURINGSUBMIT "ReportDuringSubmit2"
|
||||
#define ST_REPORTSUBMITSUCCESS "ReportSubmitSuccess"
|
||||
#define ST_SUBMITFAILED "ReportSubmitFailed"
|
||||
#define ST_QUIT "Quit2"
|
||||
#define ST_RESTART "Restart"
|
||||
#define ST_OK "Ok"
|
||||
#define ST_CLOSE "Close"
|
||||
|
||||
#define ST_ERROR_BADARGUMENTS "ErrorBadArguments"
|
||||
#define ST_ERROR_EXTRAFILEEXISTS "ErrorExtraFileExists"
|
||||
#define ST_ERROR_EXTRAFILEREAD "ErrorExtraFileRead"
|
||||
#define ST_ERROR_EXTRAFILEMOVE "ErrorExtraFileMove"
|
||||
#define ST_ERROR_DUMPFILEEXISTS "ErrorDumpFileExists"
|
||||
#define ST_ERROR_DUMPFILEMOVE "ErrorDumpFileMove"
|
||||
#define ST_ERROR_NOPRODUCTNAME "ErrorNoProductName"
|
||||
#define ST_ERROR_NOSERVERURL "ErrorNoServerURL"
|
||||
#define ST_ERROR_NOSETTINGSPATH "ErrorNoSettingsPath"
|
||||
#define ST_ERROR_CREATEDUMPDIR "ErrorCreateDumpDir"
|
||||
#define ST_ERROR_ENDOFLIFE "ErrorEndOfLife"
|
||||
|
||||
//=============================================================================
|
||||
// implemented in crashreporter.cpp
|
||||
//=============================================================================
|
||||
|
||||
namespace CrashReporter {
|
||||
extern StringTable gStrings;
|
||||
extern std::string gSettingsPath;
|
||||
extern std::string gEventsPath;
|
||||
extern int gArgc;
|
||||
extern char** gArgv;
|
||||
|
||||
void UIError(const std::string& message);
|
||||
|
||||
// The UI finished sending the report
|
||||
void SendCompleted(bool success, const std::string& serverResponse);
|
||||
|
||||
bool ReadStrings(std::istream& in,
|
||||
StringTable& strings,
|
||||
bool unescape);
|
||||
bool ReadStringsFromFile(const std::string& path,
|
||||
StringTable& strings,
|
||||
bool unescape);
|
||||
bool WriteStrings(std::ostream& out,
|
||||
const std::string& header,
|
||||
StringTable& strings,
|
||||
bool escape);
|
||||
bool WriteStringsToFile(const std::string& path,
|
||||
const std::string& header,
|
||||
StringTable& strings,
|
||||
bool escape);
|
||||
void LogMessage(const std::string& message);
|
||||
void DeleteDump();
|
||||
bool ShouldEnableSending();
|
||||
|
||||
static const unsigned int kSaveCount = 10;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// implemented in the platform-specific files
|
||||
//=============================================================================
|
||||
|
||||
bool UIInit();
|
||||
void UIShutdown();
|
||||
|
||||
// Run the UI for when the app was launched without a dump file
|
||||
void UIShowDefaultUI();
|
||||
|
||||
// Run the UI for when the app was launched with a dump file
|
||||
// Return true if the user sent (or tried to send) the crash report,
|
||||
// false if they chose not to, and it should be deleted.
|
||||
bool UIShowCrashUI(const StringTable& files,
|
||||
const StringTable& queryParameters,
|
||||
const std::string& sendURL,
|
||||
const std::vector<std::string>& restartArgs);
|
||||
|
||||
void UIError_impl(const std::string& message);
|
||||
|
||||
bool UIGetIniPath(std::string& path);
|
||||
bool UIGetSettingsPath(const std::string& vendor,
|
||||
const std::string& product,
|
||||
std::string& settingsPath);
|
||||
bool UIEnsurePathExists(const std::string& path);
|
||||
bool UIFileExists(const std::string& path);
|
||||
bool UIMoveFile(const std::string& oldfile, const std::string& newfile);
|
||||
bool UIDeleteFile(const std::string& oldfile);
|
||||
std::ifstream* UIOpenRead(const std::string& filename);
|
||||
std::ofstream* UIOpenWrite(const std::string& filename,
|
||||
bool append=false,
|
||||
bool binary=false);
|
||||
void UIPruneSavedDumps(const std::string& directory);
|
||||
void UIRunMinidumpAnalyzer(const std::string& exename,
|
||||
const std::string& filename);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
|
|
@ -1,148 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winresrc.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winresrc.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
1 24 "crashreporter.exe.manifest"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_MAINICON ICON "crashreporter.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AVI
|
||||
//
|
||||
|
||||
IDR_THROBBER AVI "Throbber-small.avi"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_SENDDIALOG DIALOGEX 0, 0, 241, 187
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_APPWINDOW
|
||||
CAPTION "Sending Crash Report..."
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_DESCRIPTIONTEXT,"RICHEDIT50W",ES_MULTILINE | ES_READONLY,8,7,226,12,WS_EX_TRANSPARENT
|
||||
CONTROL "tell mozilla about this crash so they can fix it",IDC_SUBMITREPORTCHECK,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,25,222,10
|
||||
CHECKBOX "details...",IDC_VIEWREPORTBUTTON,24,40,54,14,BS_PUSHLIKE
|
||||
EDITTEXT IDC_COMMENTTEXT,24,59,210,43,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL
|
||||
CONTROL "include the address of the page i was on",IDC_INCLUDEURLCHECK,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,107,210,10
|
||||
CONTROL "tell mozilla to email me with more information",IDC_EMAILMECHECK,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,120,210,10
|
||||
EDITTEXT IDC_EMAILTEXT,36,133,198,14,ES_AUTOHSCROLL
|
||||
CONTROL "",IDC_THROBBER,"SysAnimate32",ACS_TRANSPARENT | NOT WS_VISIBLE | WS_TABSTOP,4,152,16,16
|
||||
LTEXT "your crash report will be submitted when you restart",IDC_PROGRESSTEXT,24,152,210,10,SS_NOPREFIX
|
||||
DEFPUSHBUTTON "restart firefox",IDC_RESTARTBUTTON,84,166,68,14
|
||||
PUSHBUTTON "quit without sending",IDC_CLOSEBUTTON,157,166,77,14
|
||||
END
|
||||
|
||||
IDD_VIEWREPORTDIALOG DIALOGEX 0, 0, 208, 126
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
|
||||
CAPTION "view report"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_VIEWREPORTTEXT,"RICHEDIT50W",ES_MULTILINE | ES_READONLY | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,194,92
|
||||
DEFPUSHBUTTON "OK",IDOK,151,105,50,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_SENDDIALOG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 8
|
||||
RIGHTMARGIN, 234
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 180
|
||||
END
|
||||
|
||||
IDD_VIEWREPORTDIALOG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 201
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 119
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
|
|
@ -1,453 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "crashreporter.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/linux/http_upload.h"
|
||||
#include "crashreporter.h"
|
||||
#include "crashreporter_gtk_common.h"
|
||||
|
||||
#ifndef GDK_KEY_Escape
|
||||
#define GDK_KEY_Escape GDK_Escape
|
||||
#endif
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
using namespace CrashReporter;
|
||||
|
||||
GtkWidget* gWindow = 0;
|
||||
GtkWidget* gSubmitReportCheck = 0;
|
||||
GtkWidget* gIncludeURLCheck = 0;
|
||||
GtkWidget* gThrobber = 0;
|
||||
GtkWidget* gProgressLabel = 0;
|
||||
GtkWidget* gCloseButton = 0;
|
||||
GtkWidget* gRestartButton = 0;
|
||||
|
||||
bool gInitialized = false;
|
||||
bool gDidTrySend = false;
|
||||
StringTable gFiles;
|
||||
StringTable gQueryParameters;
|
||||
string gHttpProxy;
|
||||
string gAuth;
|
||||
string gCACertificateFile;
|
||||
string gSendURL;
|
||||
string gURLParameter;
|
||||
vector<string> gRestartArgs;
|
||||
GThread* gSendThreadID;
|
||||
|
||||
// From crashreporter_linux.cpp
|
||||
void SaveSettings();
|
||||
void SendReport();
|
||||
void TryInitGnome();
|
||||
void UpdateSubmit();
|
||||
|
||||
static bool RestartApplication()
|
||||
{
|
||||
char** argv = reinterpret_cast<char**>(
|
||||
malloc(sizeof(char*) * (gRestartArgs.size() + 1)));
|
||||
|
||||
if (!argv) return false;
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < gRestartArgs.size(); i++) {
|
||||
argv[i] = (char*)gRestartArgs[i].c_str();
|
||||
}
|
||||
argv[i] = 0;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == -1)
|
||||
return false;
|
||||
else if (pid == 0) {
|
||||
(void)execv(argv[0], argv);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
free(argv);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Quit the app, used as a timeout callback
|
||||
static gboolean CloseApp(gpointer data)
|
||||
{
|
||||
gtk_main_quit();
|
||||
g_thread_join(gSendThreadID);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ReportCompleted(gpointer success)
|
||||
{
|
||||
gtk_widget_hide(gThrobber);
|
||||
string str = success ? gStrings[ST_REPORTSUBMITSUCCESS]
|
||||
: gStrings[ST_SUBMITFAILED];
|
||||
gtk_label_set_text(GTK_LABEL(gProgressLabel), str.c_str());
|
||||
g_timeout_add(5000, CloseApp, 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef MOZ_ENABLE_GCONF
|
||||
#define HTTP_PROXY_DIR "/system/http_proxy"
|
||||
|
||||
void LoadProxyinfo()
|
||||
{
|
||||
class GConfClient;
|
||||
typedef GConfClient * (*_gconf_default_fn)();
|
||||
typedef gboolean (*_gconf_bool_fn)(GConfClient *, const gchar *, GError **);
|
||||
typedef gint (*_gconf_int_fn)(GConfClient *, const gchar *, GError **);
|
||||
typedef gchar * (*_gconf_string_fn)(GConfClient *, const gchar *, GError **);
|
||||
|
||||
if (getenv ("http_proxy"))
|
||||
return; // libcurl can use the value from the environment
|
||||
|
||||
static void* gconfLib = dlopen("libgconf-2.so.4", RTLD_LAZY);
|
||||
if (!gconfLib)
|
||||
return;
|
||||
|
||||
_gconf_default_fn gconf_client_get_default =
|
||||
(_gconf_default_fn)dlsym(gconfLib, "gconf_client_get_default");
|
||||
_gconf_bool_fn gconf_client_get_bool =
|
||||
(_gconf_bool_fn)dlsym(gconfLib, "gconf_client_get_bool");
|
||||
_gconf_int_fn gconf_client_get_int =
|
||||
(_gconf_int_fn)dlsym(gconfLib, "gconf_client_get_int");
|
||||
_gconf_string_fn gconf_client_get_string =
|
||||
(_gconf_string_fn)dlsym(gconfLib, "gconf_client_get_string");
|
||||
|
||||
if(!(gconf_client_get_default &&
|
||||
gconf_client_get_bool &&
|
||||
gconf_client_get_int &&
|
||||
gconf_client_get_string)) {
|
||||
dlclose(gconfLib);
|
||||
return;
|
||||
}
|
||||
|
||||
GConfClient *conf = gconf_client_get_default();
|
||||
|
||||
if (gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_http_proxy", nullptr)) {
|
||||
gint port;
|
||||
gchar *host = nullptr, *httpproxy = nullptr;
|
||||
|
||||
host = gconf_client_get_string(conf, HTTP_PROXY_DIR "/host", nullptr);
|
||||
port = gconf_client_get_int(conf, HTTP_PROXY_DIR "/port", nullptr);
|
||||
|
||||
if (port && host && *host != '\0') {
|
||||
httpproxy = g_strdup_printf("http://%s:%d/", host, port);
|
||||
gHttpProxy = httpproxy;
|
||||
}
|
||||
|
||||
g_free(host);
|
||||
g_free(httpproxy);
|
||||
|
||||
if (gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_authentication",
|
||||
nullptr)) {
|
||||
gchar *user, *password, *auth = nullptr;
|
||||
|
||||
user = gconf_client_get_string(conf,
|
||||
HTTP_PROXY_DIR "/authentication_user",
|
||||
nullptr);
|
||||
password = gconf_client_get_string(conf,
|
||||
HTTP_PROXY_DIR
|
||||
"/authentication_password",
|
||||
nullptr);
|
||||
|
||||
if (user && password) {
|
||||
auth = g_strdup_printf("%s:%s", user, password);
|
||||
gAuth = auth;
|
||||
}
|
||||
|
||||
g_free(user);
|
||||
g_free(password);
|
||||
g_free(auth);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref(conf);
|
||||
|
||||
// Don't dlclose gconfLib as libORBit-2 uses atexit().
|
||||
}
|
||||
#endif
|
||||
|
||||
gpointer SendThread(gpointer args)
|
||||
{
|
||||
string response, error;
|
||||
long response_code;
|
||||
|
||||
bool success = google_breakpad::HTTPUpload::SendRequest
|
||||
(gSendURL,
|
||||
gQueryParameters,
|
||||
gFiles,
|
||||
gHttpProxy, gAuth,
|
||||
gCACertificateFile,
|
||||
&response,
|
||||
&response_code,
|
||||
&error);
|
||||
if (success) {
|
||||
LogMessage("Crash report submitted successfully");
|
||||
}
|
||||
else {
|
||||
LogMessage("Crash report submission failed: " + error);
|
||||
}
|
||||
|
||||
SendCompleted(success, response);
|
||||
// Apparently glib is threadsafe, and will schedule this
|
||||
// on the main thread, see:
|
||||
// http://library.gnome.org/devel/gtk-faq/stable/x499.html
|
||||
g_idle_add(ReportCompleted, (gpointer)success);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gboolean WindowDeleted(GtkWidget* window,
|
||||
GdkEvent* event,
|
||||
gpointer userData)
|
||||
{
|
||||
SaveSettings();
|
||||
gtk_main_quit();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean check_escape(GtkWidget* window,
|
||||
GdkEventKey* event,
|
||||
gpointer userData)
|
||||
{
|
||||
if (event->keyval == GDK_KEY_Escape) {
|
||||
gtk_main_quit();
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void MaybeSubmitReport()
|
||||
{
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
|
||||
gDidTrySend = true;
|
||||
SendReport();
|
||||
} else {
|
||||
gtk_main_quit();
|
||||
}
|
||||
}
|
||||
|
||||
void CloseClicked(GtkButton* button,
|
||||
gpointer userData)
|
||||
{
|
||||
SaveSettings();
|
||||
MaybeSubmitReport();
|
||||
}
|
||||
|
||||
void RestartClicked(GtkButton* button,
|
||||
gpointer userData)
|
||||
{
|
||||
SaveSettings();
|
||||
RestartApplication();
|
||||
MaybeSubmitReport();
|
||||
}
|
||||
|
||||
static void UpdateURL()
|
||||
{
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))) {
|
||||
gQueryParameters["URL"] = gURLParameter;
|
||||
} else {
|
||||
gQueryParameters.erase("URL");
|
||||
}
|
||||
}
|
||||
|
||||
void SubmitReportChecked(GtkButton* sender, gpointer userData)
|
||||
{
|
||||
UpdateSubmit();
|
||||
}
|
||||
|
||||
void IncludeURLClicked(GtkButton* sender, gpointer userData)
|
||||
{
|
||||
UpdateURL();
|
||||
}
|
||||
|
||||
/* === Crashreporter UI Functions === */
|
||||
|
||||
bool UIInit()
|
||||
{
|
||||
// breakpad probably left us with blocked signals, unblock them here
|
||||
sigset_t signals, old;
|
||||
sigfillset(&signals);
|
||||
sigprocmask(SIG_UNBLOCK, &signals, &old);
|
||||
|
||||
// tell glib we're going to use threads
|
||||
g_thread_init(nullptr);
|
||||
|
||||
if (gtk_init_check(&gArgc, &gArgv)) {
|
||||
gInitialized = true;
|
||||
|
||||
if (gStrings.find("isRTL") != gStrings.end() &&
|
||||
gStrings["isRTL"] == "yes")
|
||||
gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UIShowDefaultUI()
|
||||
{
|
||||
GtkWidget* errorDialog =
|
||||
gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"%s", gStrings[ST_CRASHREPORTERDEFAULT].c_str());
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(errorDialog),
|
||||
gStrings[ST_CRASHREPORTERTITLE].c_str());
|
||||
gtk_dialog_run(GTK_DIALOG(errorDialog));
|
||||
}
|
||||
|
||||
void UIError_impl(const string& message)
|
||||
{
|
||||
if (!gInitialized) {
|
||||
// Didn't initialize, this is the best we can do
|
||||
printf("Error: %s\n", message.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
GtkWidget* errorDialog =
|
||||
gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"%s", message.c_str());
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(errorDialog),
|
||||
gStrings[ST_CRASHREPORTERTITLE].c_str());
|
||||
gtk_dialog_run(GTK_DIALOG(errorDialog));
|
||||
}
|
||||
|
||||
bool UIGetIniPath(string& path)
|
||||
{
|
||||
path = gArgv[0];
|
||||
path.append(".ini");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Settings are stored in ~/.vendor/product, or
|
||||
* ~/.product if vendor is empty.
|
||||
*/
|
||||
bool UIGetSettingsPath(const string& vendor,
|
||||
const string& product,
|
||||
string& settingsPath)
|
||||
{
|
||||
char* home = getenv("HOME");
|
||||
|
||||
if (!home)
|
||||
return false;
|
||||
|
||||
settingsPath = home;
|
||||
settingsPath += "/.";
|
||||
if (!vendor.empty()) {
|
||||
string lc_vendor;
|
||||
std::transform(vendor.begin(), vendor.end(), back_inserter(lc_vendor),
|
||||
(int(*)(int)) std::tolower);
|
||||
settingsPath += lc_vendor + "/";
|
||||
}
|
||||
string lc_product;
|
||||
std::transform(product.begin(), product.end(), back_inserter(lc_product),
|
||||
(int(*)(int)) std::tolower);
|
||||
settingsPath += lc_product + "/Crash Reports";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UIEnsurePathExists(const string& path)
|
||||
{
|
||||
int ret = mkdir(path.c_str(), S_IRWXU);
|
||||
int e = errno;
|
||||
if (ret == -1 && e != EEXIST)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UIFileExists(const string& path)
|
||||
{
|
||||
struct stat sb;
|
||||
int ret = stat(path.c_str(), &sb);
|
||||
if (ret == -1 || !(sb.st_mode & S_IFREG))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UIMoveFile(const string& file, const string& newfile)
|
||||
{
|
||||
if (!rename(file.c_str(), newfile.c_str()))
|
||||
return true;
|
||||
if (errno != EXDEV)
|
||||
return false;
|
||||
|
||||
// use system /bin/mv instead, time to fork
|
||||
pid_t pID = vfork();
|
||||
if (pID < 0) {
|
||||
// Failed to fork
|
||||
return false;
|
||||
}
|
||||
if (pID == 0) {
|
||||
char* const args[4] = {
|
||||
const_cast<char*>("mv"),
|
||||
strdup(file.c_str()),
|
||||
strdup(newfile.c_str()),
|
||||
0
|
||||
};
|
||||
if (args[1] && args[2])
|
||||
execve("/bin/mv", args, 0);
|
||||
free(args[1]);
|
||||
free(args[2]);
|
||||
exit(-1);
|
||||
}
|
||||
int status;
|
||||
waitpid(pID, &status, 0);
|
||||
return UIFileExists(newfile);
|
||||
}
|
||||
|
||||
bool UIDeleteFile(const string& file)
|
||||
{
|
||||
return (unlink(file.c_str()) != -1);
|
||||
}
|
||||
|
||||
std::ifstream* UIOpenRead(const string& filename)
|
||||
{
|
||||
return new std::ifstream(filename.c_str(), std::ios::in);
|
||||
}
|
||||
|
||||
std::ofstream* UIOpenWrite(const string& filename,
|
||||
bool append, // append=false
|
||||
bool binary) // binary=false
|
||||
{
|
||||
std::ios_base::openmode mode = std::ios::out;
|
||||
|
||||
if (append) {
|
||||
mode = mode | std::ios::app;
|
||||
}
|
||||
|
||||
if (binary) {
|
||||
mode = mode | std::ios::binary;
|
||||
}
|
||||
|
||||
return new std::ofstream(filename.c_str(), mode);
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef CRASHREPORTER_GTK_COMMON_H__
|
||||
#define CRASHREPORTER_GTK_COMMON_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
const char kIniFile[] = "crashreporter.ini";
|
||||
|
||||
extern GtkWidget* gWindow;
|
||||
extern GtkWidget* gSubmitReportCheck;
|
||||
extern GtkWidget* gIncludeURLCheck;
|
||||
extern GtkWidget* gThrobber;
|
||||
extern GtkWidget* gProgressLabel;
|
||||
extern GtkWidget* gCloseButton;
|
||||
extern GtkWidget* gRestartButton;
|
||||
|
||||
extern std::vector<std::string> gRestartArgs;
|
||||
extern GThread* gSendThreadID;
|
||||
|
||||
extern bool gInitialized;
|
||||
extern bool gDidTrySend;
|
||||
extern StringTable gFiles;
|
||||
extern StringTable gQueryParameters;
|
||||
extern std::string gHttpProxy;
|
||||
extern std::string gAuth;
|
||||
extern std::string gCACertificateFile;
|
||||
extern std::string gSendURL;
|
||||
extern std::string gURLParameter;
|
||||
|
||||
void LoadProxyinfo();
|
||||
gpointer SendThread(gpointer args);
|
||||
gboolean WindowDeleted(GtkWidget* window,
|
||||
GdkEvent* event,
|
||||
gpointer userData);
|
||||
gboolean check_escape(GtkWidget* window, GdkEventKey* event, gpointer data);
|
||||
void SubmitReportChecked(GtkButton* sender, gpointer userData);
|
||||
void IncludeURLClicked(GtkButton* sender, gpointer userData);
|
||||
void CloseClicked(GtkButton* button,
|
||||
gpointer userData);
|
||||
void RestartClicked(GtkButton* button,
|
||||
gpointer userData);
|
||||
|
||||
#endif // CRASHREPORTER_GTK_COMMON_H__
|
||||
|
|
@ -1,576 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cctype>
|
||||
|
||||
#include "crashreporter.h"
|
||||
#include "crashreporter_gtk_common.h"
|
||||
|
||||
#define LABEL_MAX_CHAR_WIDTH 48
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
using namespace CrashReporter;
|
||||
|
||||
static GtkWidget* gViewReportButton = 0;
|
||||
static GtkWidget* gCommentTextLabel = 0;
|
||||
static GtkWidget* gCommentText = 0;
|
||||
static GtkWidget* gEmailMeCheck = 0;
|
||||
static GtkWidget* gEmailEntryLabel = 0;
|
||||
static GtkWidget* gEmailEntry = 0;
|
||||
|
||||
static bool gEmailFieldHint = true;
|
||||
static bool gCommentFieldHint = true;
|
||||
|
||||
// handle from dlopen'ing libgnome
|
||||
static void* gnomeLib = nullptr;
|
||||
// handle from dlopen'ing libgnomeui
|
||||
static void* gnomeuiLib = nullptr;
|
||||
|
||||
static void LoadSettings()
|
||||
{
|
||||
/*
|
||||
* NOTE! This code needs to stay in sync with the preference checking
|
||||
* code in in nsExceptionHandler.cpp.
|
||||
*/
|
||||
|
||||
StringTable settings;
|
||||
if (ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true)) {
|
||||
if (settings.find("Email") != settings.end()) {
|
||||
gtk_entry_set_text(GTK_ENTRY(gEmailEntry), settings["Email"].c_str());
|
||||
gEmailFieldHint = false;
|
||||
}
|
||||
if (settings.find("EmailMe") != settings.end()) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gEmailMeCheck),
|
||||
settings["EmailMe"][0] != '0');
|
||||
}
|
||||
if (settings.find("IncludeURL") != settings.end() &&
|
||||
gIncludeURLCheck != 0) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck),
|
||||
settings["IncludeURL"][0] != '0');
|
||||
}
|
||||
bool enabled;
|
||||
if (settings.find("SubmitReport") != settings.end())
|
||||
enabled = settings["SubmitReport"][0] != '0';
|
||||
else
|
||||
enabled = ShouldEnableSending();
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck),
|
||||
enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveSettings()
|
||||
{
|
||||
/*
|
||||
* NOTE! This code needs to stay in sync with the preference setting
|
||||
* code in in nsExceptionHandler.cpp.
|
||||
*/
|
||||
|
||||
StringTable settings;
|
||||
|
||||
ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true);
|
||||
if (!gEmailFieldHint)
|
||||
settings["Email"] = gtk_entry_get_text(GTK_ENTRY(gEmailEntry));
|
||||
else
|
||||
settings.erase("Email");
|
||||
|
||||
settings["EmailMe"] =
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck)) ? "1" : "0";
|
||||
if (gIncludeURLCheck != 0)
|
||||
settings["IncludeURL"] =
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))
|
||||
? "1" : "0";
|
||||
settings["SubmitReport"] =
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))
|
||||
? "1" : "0";
|
||||
|
||||
WriteStringsToFile(gSettingsPath + "/" + kIniFile,
|
||||
"Crash Reporter", settings, true);
|
||||
}
|
||||
|
||||
void SendReport()
|
||||
{
|
||||
// disable all our gui controls, show the throbber + change the progress text
|
||||
gtk_widget_set_sensitive(gSubmitReportCheck, FALSE);
|
||||
gtk_widget_set_sensitive(gViewReportButton, FALSE);
|
||||
gtk_widget_set_sensitive(gCommentText, FALSE);
|
||||
if (gIncludeURLCheck)
|
||||
gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
|
||||
gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
|
||||
gtk_widget_set_sensitive(gEmailEntry, FALSE);
|
||||
gtk_widget_set_sensitive(gCloseButton, FALSE);
|
||||
if (gRestartButton)
|
||||
gtk_widget_set_sensitive(gRestartButton, FALSE);
|
||||
gtk_widget_show_all(gThrobber);
|
||||
gtk_label_set_text(GTK_LABEL(gProgressLabel),
|
||||
gStrings[ST_REPORTDURINGSUBMIT].c_str());
|
||||
|
||||
#ifdef MOZ_ENABLE_GCONF
|
||||
LoadProxyinfo();
|
||||
#endif
|
||||
|
||||
// and spawn a thread to do the sending
|
||||
GError* err;
|
||||
gSendThreadID = g_thread_create(SendThread, nullptr, TRUE, &err);
|
||||
}
|
||||
|
||||
static void ShowReportInfo(GtkTextView* viewReportTextView)
|
||||
{
|
||||
GtkTextBuffer* buffer =
|
||||
gtk_text_view_get_buffer(viewReportTextView);
|
||||
|
||||
GtkTextIter start, end;
|
||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
||||
|
||||
gtk_text_buffer_delete(buffer, &start, &end);
|
||||
|
||||
for (StringTable::iterator iter = gQueryParameters.begin();
|
||||
iter != gQueryParameters.end();
|
||||
iter++) {
|
||||
gtk_text_buffer_insert(buffer, &end, iter->first.c_str(), -1);
|
||||
gtk_text_buffer_insert(buffer, &end, ": ", -1);
|
||||
gtk_text_buffer_insert(buffer, &end, iter->second.c_str(), -1);
|
||||
gtk_text_buffer_insert(buffer, &end, "\n", -1);
|
||||
}
|
||||
|
||||
gtk_text_buffer_insert(buffer, &end, "\n", -1);
|
||||
gtk_text_buffer_insert(buffer, &end,
|
||||
gStrings[ST_EXTRAREPORTINFO].c_str(), -1);
|
||||
}
|
||||
|
||||
void UpdateSubmit()
|
||||
{
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
|
||||
gtk_widget_set_sensitive(gViewReportButton, TRUE);
|
||||
gtk_widget_set_sensitive(gCommentText, TRUE);
|
||||
if (gIncludeURLCheck)
|
||||
gtk_widget_set_sensitive(gIncludeURLCheck, TRUE);
|
||||
gtk_widget_set_sensitive(gEmailMeCheck, TRUE);
|
||||
gtk_widget_set_sensitive(gEmailEntry,
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck)));
|
||||
gtk_label_set_text(GTK_LABEL(gProgressLabel),
|
||||
gStrings[ST_REPORTPRESUBMIT].c_str());
|
||||
} else {
|
||||
gtk_widget_set_sensitive(gViewReportButton, FALSE);
|
||||
gtk_widget_set_sensitive(gCommentText, FALSE);
|
||||
if (gIncludeURLCheck)
|
||||
gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
|
||||
gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
|
||||
gtk_widget_set_sensitive(gEmailEntry, FALSE);
|
||||
gtk_label_set_text(GTK_LABEL(gProgressLabel), "");
|
||||
}
|
||||
}
|
||||
|
||||
static void ViewReportClicked(GtkButton* button,
|
||||
gpointer userData)
|
||||
{
|
||||
GtkDialog* dialog =
|
||||
GTK_DIALOG(gtk_dialog_new_with_buttons(gStrings[ST_VIEWREPORTTITLE].c_str(),
|
||||
GTK_WINDOW(gWindow),
|
||||
GTK_DIALOG_MODAL,
|
||||
GTK_STOCK_OK,
|
||||
GTK_RESPONSE_OK,
|
||||
nullptr));
|
||||
|
||||
GtkWidget* scrolled = gtk_scrolled_window_new(0, 0);
|
||||
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), scrolled);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
|
||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
|
||||
GTK_SHADOW_IN);
|
||||
#if (MOZ_WIDGET_GTK >= 3)
|
||||
gtk_widget_set_vexpand(scrolled, TRUE);
|
||||
#endif
|
||||
|
||||
GtkWidget* viewReportTextView = gtk_text_view_new();
|
||||
gtk_container_add(GTK_CONTAINER(scrolled), viewReportTextView);
|
||||
gtk_text_view_set_editable(GTK_TEXT_VIEW(viewReportTextView), FALSE);
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(viewReportTextView),
|
||||
GTK_WRAP_WORD);
|
||||
gtk_widget_set_size_request(GTK_WIDGET(viewReportTextView), -1, 100);
|
||||
|
||||
ShowReportInfo(GTK_TEXT_VIEW(viewReportTextView));
|
||||
|
||||
gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK);
|
||||
gtk_widget_set_size_request(GTK_WIDGET(dialog), 400, 200);
|
||||
gtk_widget_show_all(GTK_WIDGET(dialog));
|
||||
gtk_dialog_run(dialog);
|
||||
gtk_widget_destroy(GTK_WIDGET(dialog));
|
||||
}
|
||||
|
||||
static void CommentChanged(GtkTextBuffer* buffer, gpointer userData)
|
||||
{
|
||||
GtkTextIter start, end;
|
||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
||||
const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
|
||||
if (comment[0] == '\0' || gCommentFieldHint)
|
||||
gQueryParameters.erase("Comments");
|
||||
else
|
||||
gQueryParameters["Comments"] = comment;
|
||||
}
|
||||
|
||||
static void CommentInsert(GtkTextBuffer* buffer,
|
||||
GtkTextIter* location,
|
||||
gchar* text,
|
||||
gint len,
|
||||
gpointer userData)
|
||||
{
|
||||
GtkTextIter start, end;
|
||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
||||
const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
|
||||
|
||||
// limit to 500 bytes in utf-8
|
||||
if (strlen(comment) + len > MAX_COMMENT_LENGTH) {
|
||||
g_signal_stop_emission_by_name(buffer, "insert-text");
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateHintText(GtkWidget* widget, gboolean gainedFocus,
|
||||
bool* hintShowing, const char* hintText)
|
||||
{
|
||||
GtkTextBuffer* buffer = nullptr;
|
||||
if (GTK_IS_TEXT_VIEW(widget))
|
||||
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
|
||||
|
||||
if (gainedFocus) {
|
||||
if (*hintShowing) {
|
||||
if (buffer == nullptr) { // sort of cheating
|
||||
gtk_entry_set_text(GTK_ENTRY(widget), "");
|
||||
}
|
||||
else { // GtkTextView
|
||||
gtk_text_buffer_set_text(buffer, "", 0);
|
||||
}
|
||||
gtk_widget_modify_text(widget, GTK_STATE_NORMAL, nullptr);
|
||||
*hintShowing = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// lost focus
|
||||
const char* text = nullptr;
|
||||
if (buffer == nullptr) {
|
||||
text = gtk_entry_get_text(GTK_ENTRY(widget));
|
||||
}
|
||||
else {
|
||||
GtkTextIter start, end;
|
||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
||||
text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
|
||||
}
|
||||
|
||||
if (text == nullptr || text[0] == '\0') {
|
||||
*hintShowing = true;
|
||||
|
||||
if (buffer == nullptr) {
|
||||
gtk_entry_set_text(GTK_ENTRY(widget), hintText);
|
||||
}
|
||||
else {
|
||||
gtk_text_buffer_set_text(buffer, hintText, -1);
|
||||
}
|
||||
|
||||
gtk_widget_modify_text(widget, GTK_STATE_NORMAL,
|
||||
>k_widget_get_style(widget)->text[GTK_STATE_INSENSITIVE]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean CommentFocusChange(GtkWidget* widget, GdkEventFocus* event,
|
||||
gpointer userData)
|
||||
{
|
||||
UpdateHintText(widget, event->in, &gCommentFieldHint,
|
||||
gStrings[ST_COMMENTGRAYTEXT].c_str());
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void UpdateEmail()
|
||||
{
|
||||
const char* email = gtk_entry_get_text(GTK_ENTRY(gEmailEntry));
|
||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck))) {
|
||||
gtk_widget_set_sensitive(gEmailEntry, TRUE);
|
||||
} else {
|
||||
email = "";
|
||||
gtk_widget_set_sensitive(gEmailEntry, FALSE);
|
||||
}
|
||||
if (email[0] == '\0' || gEmailFieldHint)
|
||||
gQueryParameters.erase("Email");
|
||||
else
|
||||
gQueryParameters["Email"] = email;
|
||||
}
|
||||
|
||||
static void EmailMeClicked(GtkButton* sender, gpointer userData)
|
||||
{
|
||||
UpdateEmail();
|
||||
}
|
||||
|
||||
static void EmailChanged(GtkEditable* editable, gpointer userData)
|
||||
{
|
||||
UpdateEmail();
|
||||
}
|
||||
|
||||
static gboolean EmailFocusChange(GtkWidget* widget, GdkEventFocus* event,
|
||||
gpointer userData)
|
||||
{
|
||||
UpdateHintText(widget, event->in, &gEmailFieldHint,
|
||||
gStrings[ST_EMAILGRAYTEXT].c_str());
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
typedef struct _GnomeProgram GnomeProgram;
|
||||
typedef struct _GnomeModuleInfo GnomeModuleInfo;
|
||||
typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
|
||||
const GnomeModuleInfo *, int,
|
||||
char **, const char *, ...);
|
||||
typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
|
||||
|
||||
void TryInitGnome()
|
||||
{
|
||||
gnomeLib = dlopen("libgnome-2.so.0", RTLD_LAZY);
|
||||
if (!gnomeLib)
|
||||
return;
|
||||
|
||||
gnomeuiLib = dlopen("libgnomeui-2.so.0", RTLD_LAZY);
|
||||
if (!gnomeuiLib)
|
||||
return;
|
||||
|
||||
_gnome_program_init_fn gnome_program_init =
|
||||
(_gnome_program_init_fn)(dlsym(gnomeLib, "gnome_program_init"));
|
||||
_libgnomeui_module_info_get_fn libgnomeui_module_info_get =
|
||||
(_libgnomeui_module_info_get_fn)(dlsym(gnomeuiLib, "libgnomeui_module_info_get"));
|
||||
|
||||
if (gnome_program_init && libgnomeui_module_info_get) {
|
||||
gnome_program_init("crashreporter", "1.0", libgnomeui_module_info_get(),
|
||||
gArgc, gArgv, nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* === Crashreporter UI Functions === */
|
||||
|
||||
/*
|
||||
* Anything not listed here is in crashreporter_gtk_common.cpp:
|
||||
* UIInit
|
||||
* UIShowDefaultUI
|
||||
* UIError_impl
|
||||
* UIGetIniPath
|
||||
* UIGetSettingsPath
|
||||
* UIEnsurePathExists
|
||||
* UIFileExists
|
||||
* UIMoveFile
|
||||
* UIDeleteFile
|
||||
* UIOpenRead
|
||||
* UIOpenWrite
|
||||
*/
|
||||
|
||||
void UIShutdown()
|
||||
{
|
||||
if (gnomeuiLib)
|
||||
dlclose(gnomeuiLib);
|
||||
// Don't dlclose gnomeLib as libgnomevfs and libORBit-2 use atexit().
|
||||
}
|
||||
|
||||
bool UIShowCrashUI(const StringTable& files,
|
||||
const StringTable& queryParameters,
|
||||
const string& sendURL,
|
||||
const vector<string>& restartArgs)
|
||||
{
|
||||
gFiles = files;
|
||||
gQueryParameters = queryParameters;
|
||||
gSendURL = sendURL;
|
||||
gRestartArgs = restartArgs;
|
||||
if (gQueryParameters.find("URL") != gQueryParameters.end())
|
||||
gURLParameter = gQueryParameters["URL"];
|
||||
|
||||
gWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(gWindow),
|
||||
gStrings[ST_CRASHREPORTERTITLE].c_str());
|
||||
gtk_window_set_resizable(GTK_WINDOW(gWindow), FALSE);
|
||||
gtk_window_set_position(GTK_WINDOW(gWindow), GTK_WIN_POS_CENTER);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(gWindow), 12);
|
||||
g_signal_connect(gWindow, "delete-event", G_CALLBACK(WindowDeleted), 0);
|
||||
g_signal_connect(gWindow, "key_press_event", G_CALLBACK(check_escape), nullptr);
|
||||
|
||||
GtkWidget* vbox = gtk_vbox_new(FALSE, 6);
|
||||
gtk_container_add(GTK_CONTAINER(gWindow), vbox);
|
||||
|
||||
GtkWidget* titleLabel = gtk_label_new("");
|
||||
gtk_box_pack_start(GTK_BOX(vbox), titleLabel, FALSE, FALSE, 0);
|
||||
gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5);
|
||||
char* markup = g_strdup_printf("<b>%s</b>",
|
||||
gStrings[ST_CRASHREPORTERHEADER].c_str());
|
||||
gtk_label_set_markup(GTK_LABEL(titleLabel), markup);
|
||||
g_free(markup);
|
||||
|
||||
GtkWidget* descriptionLabel =
|
||||
gtk_label_new(gStrings[ST_CRASHREPORTERDESCRIPTION].c_str());
|
||||
gtk_box_pack_start(GTK_BOX(vbox), descriptionLabel, TRUE, TRUE, 0);
|
||||
// force the label to line wrap
|
||||
#if (MOZ_WIDGET_GTK == 2)
|
||||
gtk_widget_set_size_request(descriptionLabel, 400, -1);
|
||||
#else
|
||||
gtk_label_set_max_width_chars(GTK_LABEL(descriptionLabel), LABEL_MAX_CHAR_WIDTH);
|
||||
#endif
|
||||
gtk_label_set_line_wrap(GTK_LABEL(descriptionLabel), TRUE);
|
||||
gtk_label_set_selectable(GTK_LABEL(descriptionLabel), TRUE);
|
||||
gtk_misc_set_alignment(GTK_MISC(descriptionLabel), 0, 0.5);
|
||||
|
||||
// this is honestly how they suggest you indent a section
|
||||
GtkWidget* indentBox = gtk_hbox_new(FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), indentBox, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(indentBox), gtk_label_new(""), FALSE, FALSE, 6);
|
||||
|
||||
GtkWidget* innerVBox1 = gtk_vbox_new(FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(indentBox), innerVBox1, TRUE, TRUE, 0);
|
||||
|
||||
gSubmitReportCheck =
|
||||
gtk_check_button_new_with_label(gStrings[ST_CHECKSUBMIT].c_str());
|
||||
gtk_box_pack_start(GTK_BOX(innerVBox1), gSubmitReportCheck, FALSE, FALSE, 0);
|
||||
g_signal_connect(gSubmitReportCheck, "clicked",
|
||||
G_CALLBACK(SubmitReportChecked), 0);
|
||||
|
||||
// indent again, below the "submit report" checkbox
|
||||
GtkWidget* indentBox2 = gtk_hbox_new(FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(innerVBox1), indentBox2, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(indentBox2), gtk_label_new(""), FALSE, FALSE, 6);
|
||||
|
||||
GtkWidget* innerVBox = gtk_vbox_new(FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(indentBox2), innerVBox, TRUE, TRUE, 0);
|
||||
gtk_box_set_spacing(GTK_BOX(innerVBox), 6);
|
||||
|
||||
GtkWidget* viewReportButtonBox = gtk_hbutton_box_new();
|
||||
gtk_box_pack_start(GTK_BOX(innerVBox), viewReportButtonBox, FALSE, FALSE, 0);
|
||||
gtk_box_set_spacing(GTK_BOX(viewReportButtonBox), 6);
|
||||
gtk_button_box_set_layout(GTK_BUTTON_BOX(viewReportButtonBox), GTK_BUTTONBOX_START);
|
||||
|
||||
gViewReportButton =
|
||||
gtk_button_new_with_label(gStrings[ST_VIEWREPORT].c_str());
|
||||
gtk_box_pack_start(GTK_BOX(viewReportButtonBox), gViewReportButton, FALSE, FALSE, 0);
|
||||
g_signal_connect(gViewReportButton, "clicked", G_CALLBACK(ViewReportClicked), 0);
|
||||
|
||||
GtkWidget* scrolled = gtk_scrolled_window_new(0, 0);
|
||||
gtk_container_add(GTK_CONTAINER(innerVBox), scrolled);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
|
||||
GTK_SHADOW_IN);
|
||||
#if (MOZ_WIDGET_GTK >= 3)
|
||||
gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), 100);
|
||||
#endif
|
||||
|
||||
gCommentTextLabel = gtk_label_new(gStrings[ST_COMMENTGRAYTEXT].c_str());
|
||||
gCommentText = gtk_text_view_new();
|
||||
gtk_label_set_mnemonic_widget(GTK_LABEL(gCommentTextLabel), gCommentText);
|
||||
gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(gCommentText), FALSE);
|
||||
g_signal_connect(gCommentText, "focus-in-event", G_CALLBACK(CommentFocusChange), 0);
|
||||
g_signal_connect(gCommentText, "focus-out-event", G_CALLBACK(CommentFocusChange), 0);
|
||||
|
||||
GtkTextBuffer* commentBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gCommentText));
|
||||
g_signal_connect(commentBuffer, "changed", G_CALLBACK(CommentChanged), 0);
|
||||
g_signal_connect(commentBuffer, "insert-text", G_CALLBACK(CommentInsert), 0);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(scrolled), gCommentText);
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gCommentText),
|
||||
GTK_WRAP_WORD);
|
||||
gtk_widget_set_size_request(GTK_WIDGET(gCommentText), -1, 100);
|
||||
|
||||
if (gQueryParameters.find("URL") != gQueryParameters.end()) {
|
||||
gIncludeURLCheck =
|
||||
gtk_check_button_new_with_label(gStrings[ST_CHECKURL].c_str());
|
||||
gtk_box_pack_start(GTK_BOX(innerVBox), gIncludeURLCheck, FALSE, FALSE, 0);
|
||||
g_signal_connect(gIncludeURLCheck, "clicked", G_CALLBACK(IncludeURLClicked), 0);
|
||||
// on by default
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), TRUE);
|
||||
}
|
||||
|
||||
gEmailMeCheck =
|
||||
gtk_check_button_new_with_label(gStrings[ST_CHECKEMAIL].c_str());
|
||||
gtk_box_pack_start(GTK_BOX(innerVBox), gEmailMeCheck, FALSE, FALSE, 0);
|
||||
g_signal_connect(gEmailMeCheck, "clicked", G_CALLBACK(EmailMeClicked), 0);
|
||||
|
||||
GtkWidget* emailIndentBox = gtk_hbox_new(FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(innerVBox), emailIndentBox, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(emailIndentBox), gtk_label_new(""),
|
||||
FALSE, FALSE, 9);
|
||||
|
||||
gEmailEntryLabel = gtk_label_new(gStrings[ST_EMAILGRAYTEXT].c_str());
|
||||
gEmailEntry = gtk_entry_new();
|
||||
gtk_label_set_mnemonic_widget(GTK_LABEL(gEmailEntryLabel), gEmailEntry);
|
||||
gtk_box_pack_start(GTK_BOX(emailIndentBox), gEmailEntry, TRUE, TRUE, 0);
|
||||
g_signal_connect(gEmailEntry, "changed", G_CALLBACK(EmailChanged), 0);
|
||||
g_signal_connect(gEmailEntry, "focus-in-event", G_CALLBACK(EmailFocusChange), 0);
|
||||
g_signal_connect(gEmailEntry, "focus-out-event", G_CALLBACK(EmailFocusChange), 0);
|
||||
|
||||
GtkWidget* progressBox = gtk_hbox_new(FALSE, 6);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), progressBox, TRUE, TRUE, 0);
|
||||
|
||||
// Get the throbber image from alongside the executable
|
||||
char* dir = g_path_get_dirname(gArgv[0]);
|
||||
char* path = g_build_filename(dir, "Throbber-small.gif", nullptr);
|
||||
g_free(dir);
|
||||
gThrobber = gtk_image_new_from_file(path);
|
||||
gtk_box_pack_start(GTK_BOX(progressBox), gThrobber, FALSE, FALSE, 0);
|
||||
|
||||
gProgressLabel =
|
||||
gtk_label_new(gStrings[ST_REPORTPRESUBMIT].c_str());
|
||||
gtk_box_pack_start(GTK_BOX(progressBox), gProgressLabel, TRUE, TRUE, 0);
|
||||
// force the label to line wrap
|
||||
#if (MOZ_WIDGET_GTK == 2)
|
||||
gtk_widget_set_size_request(gProgressLabel, 400, -1);
|
||||
#else
|
||||
gtk_label_set_max_width_chars(GTK_LABEL(gProgressLabel), LABEL_MAX_CHAR_WIDTH);
|
||||
#endif
|
||||
gtk_label_set_line_wrap(GTK_LABEL(gProgressLabel), TRUE);
|
||||
|
||||
GtkWidget* buttonBox = gtk_hbutton_box_new();
|
||||
gtk_box_pack_end(GTK_BOX(vbox), buttonBox, FALSE, FALSE, 0);
|
||||
gtk_box_set_spacing(GTK_BOX(buttonBox), 6);
|
||||
gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonBox), GTK_BUTTONBOX_END);
|
||||
|
||||
gCloseButton =
|
||||
gtk_button_new_with_label(gStrings[ST_QUIT].c_str());
|
||||
gtk_box_pack_start(GTK_BOX(buttonBox), gCloseButton, FALSE, FALSE, 0);
|
||||
gtk_widget_set_can_default(gCloseButton, TRUE);
|
||||
g_signal_connect(gCloseButton, "clicked", G_CALLBACK(CloseClicked), 0);
|
||||
|
||||
gRestartButton = 0;
|
||||
if (restartArgs.size() > 0) {
|
||||
gRestartButton = gtk_button_new_with_label(gStrings[ST_RESTART].c_str());
|
||||
gtk_box_pack_start(GTK_BOX(buttonBox), gRestartButton, FALSE, FALSE, 0);
|
||||
gtk_widget_set_can_default(gRestartButton, TRUE);
|
||||
g_signal_connect(gRestartButton, "clicked", G_CALLBACK(RestartClicked), 0);
|
||||
}
|
||||
|
||||
gtk_widget_grab_focus(gSubmitReportCheck);
|
||||
|
||||
gtk_widget_grab_default(gRestartButton ? gRestartButton : gCloseButton);
|
||||
|
||||
LoadSettings();
|
||||
|
||||
UpdateEmail();
|
||||
UpdateSubmit();
|
||||
|
||||
UpdateHintText(gCommentText, FALSE, &gCommentFieldHint,
|
||||
gStrings[ST_COMMENTGRAYTEXT].c_str());
|
||||
UpdateHintText(gEmailEntry, FALSE, &gEmailFieldHint,
|
||||
gStrings[ST_EMAILGRAYTEXT].c_str());
|
||||
|
||||
gtk_widget_show_all(gWindow);
|
||||
// stick this here to avoid the show_all above...
|
||||
gtk_widget_hide(gThrobber);
|
||||
|
||||
gtk_main();
|
||||
|
||||
return gDidTrySend;
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef CRASHREPORTER_OSX_H__
|
||||
#define CRASHREPORTER_OSX_H__
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include "HTTPMultipartUpload.h"
|
||||
#include "crashreporter.h"
|
||||
|
||||
// Defined below
|
||||
@class TextViewWithPlaceHolder;
|
||||
|
||||
@interface CrashReporterUI : NSObject
|
||||
{
|
||||
IBOutlet NSWindow* mWindow;
|
||||
|
||||
/* Crash reporter view */
|
||||
IBOutlet NSTextField* mHeaderLabel;
|
||||
IBOutlet NSTextField* mDescriptionLabel;
|
||||
IBOutlet NSButton* mViewReportButton;
|
||||
IBOutlet NSScrollView* mCommentScrollView;
|
||||
IBOutlet TextViewWithPlaceHolder* mCommentText;
|
||||
IBOutlet NSButton* mSubmitReportButton;
|
||||
IBOutlet NSButton* mIncludeURLButton;
|
||||
IBOutlet NSButton* mEmailMeButton;
|
||||
IBOutlet NSTextField* mEmailText;
|
||||
IBOutlet NSButton* mCloseButton;
|
||||
IBOutlet NSButton* mRestartButton;
|
||||
IBOutlet NSProgressIndicator* mProgressIndicator;
|
||||
IBOutlet NSTextField* mProgressText;
|
||||
|
||||
/* Error view */
|
||||
IBOutlet NSView* mErrorView;
|
||||
IBOutlet NSTextField* mErrorHeaderLabel;
|
||||
IBOutlet NSTextField* mErrorLabel;
|
||||
IBOutlet NSButton* mErrorCloseButton;
|
||||
|
||||
/* For "show info" alert */
|
||||
IBOutlet NSWindow* mViewReportWindow;
|
||||
IBOutlet NSTextView* mViewReportTextView;
|
||||
IBOutlet NSButton* mViewReportOkButton;
|
||||
|
||||
HTTPMultipartUpload* mPost;
|
||||
}
|
||||
|
||||
- (void)showCrashUI:(const StringTable&)files
|
||||
queryParameters:(const StringTable&)queryParameters
|
||||
sendURL:(const std::string&)sendURL;
|
||||
- (void)showErrorUI:(const std::string&)message;
|
||||
- (void)showReportInfo;
|
||||
- (void)maybeSubmitReport;
|
||||
- (void)closeMeDown:(id)unused;
|
||||
|
||||
- (IBAction)submitReportClicked:(id)sender;
|
||||
- (IBAction)viewReportClicked:(id)sender;
|
||||
- (IBAction)viewReportOkClicked:(id)sender;
|
||||
- (IBAction)closeClicked:(id)sender;
|
||||
- (IBAction)restartClicked:(id)sender;
|
||||
- (IBAction)includeURLClicked:(id)sender;
|
||||
- (IBAction)emailMeClicked:(id)sender;
|
||||
|
||||
- (void)controlTextDidChange:(NSNotification *)note;
|
||||
- (void)textDidChange:(NSNotification *)aNotification;
|
||||
- (BOOL)textView:(NSTextView *)aTextView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(NSString *)replacementString;
|
||||
|
||||
- (void)doInitialResizing;
|
||||
- (float)setStringFitVertically:(NSControl*)control
|
||||
string:(NSString*)str
|
||||
resizeWindow:(BOOL)resizeWindow;
|
||||
- (void)setView:(NSView*)v animate: (BOOL) animate;
|
||||
- (void)enableControls:(BOOL)enabled;
|
||||
- (void)updateSubmit;
|
||||
- (void)updateURL;
|
||||
- (void)updateEmail;
|
||||
- (void)sendReport;
|
||||
- (bool)setupPost;
|
||||
- (void)uploadThread:(HTTPMultipartUpload*)post;
|
||||
- (void)uploadComplete:(NSData*)data;
|
||||
|
||||
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication;
|
||||
-(void)applicationWillTerminate:(NSNotification *)aNotification;
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
* Subclass NSTextView to provide a text view with placeholder text.
|
||||
* Also provide a setEnabled implementation.
|
||||
*/
|
||||
@interface TextViewWithPlaceHolder : NSTextView {
|
||||
NSMutableAttributedString *mPlaceHolderString;
|
||||
}
|
||||
|
||||
- (BOOL)becomeFirstResponder;
|
||||
- (void)drawRect:(NSRect)rect;
|
||||
- (BOOL)resignFirstResponder;
|
||||
- (void)setPlaceholder:(NSString*)placeholder;
|
||||
- (void)insertTab:(id)sender;
|
||||
- (void)insertBacktab:(id)sender;
|
||||
- (void)setEnabled:(BOOL)enabled;
|
||||
- (void)dealloc;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
@ -1,922 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#include "crashreporter.h"
|
||||
#include "crashreporter_osx.h"
|
||||
#include <crt_externs.h>
|
||||
#include <spawn.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sstream>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::ostringstream;
|
||||
|
||||
using namespace CrashReporter;
|
||||
|
||||
static NSAutoreleasePool* gMainPool;
|
||||
static CrashReporterUI* gUI = 0;
|
||||
static StringTable gFiles;
|
||||
static StringTable gQueryParameters;
|
||||
static string gURLParameter;
|
||||
static string gSendURL;
|
||||
static vector<string> gRestartArgs;
|
||||
static bool gDidTrySend = false;
|
||||
static bool gRTLlayout = false;
|
||||
|
||||
static cpu_type_t pref_cpu_types[2] = {
|
||||
#if defined(__i386__)
|
||||
CPU_TYPE_X86,
|
||||
#elif defined(__x86_64__)
|
||||
CPU_TYPE_X86_64,
|
||||
#elif defined(__ppc__)
|
||||
CPU_TYPE_POWERPC,
|
||||
#endif
|
||||
CPU_TYPE_ANY };
|
||||
|
||||
#define NSSTR(s) [NSString stringWithUTF8String:(s).c_str()]
|
||||
|
||||
static NSString* Str(const char* aName)
|
||||
{
|
||||
string str = gStrings[aName];
|
||||
if (str.empty()) str = "?";
|
||||
return NSSTR(str);
|
||||
}
|
||||
|
||||
static bool RestartApplication()
|
||||
{
|
||||
vector<char*> argv(gRestartArgs.size() + 1);
|
||||
|
||||
posix_spawnattr_t spawnattr;
|
||||
if (posix_spawnattr_init(&spawnattr) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set spawn attributes.
|
||||
size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]);
|
||||
size_t attr_ocount = 0;
|
||||
if (posix_spawnattr_setbinpref_np(&spawnattr,
|
||||
attr_count,
|
||||
pref_cpu_types,
|
||||
&attr_ocount) != 0 ||
|
||||
attr_ocount != attr_count) {
|
||||
posix_spawnattr_destroy(&spawnattr);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < gRestartArgs.size(); i++) {
|
||||
argv[i] = (char*)gRestartArgs[i].c_str();
|
||||
}
|
||||
argv[i] = 0;
|
||||
|
||||
char **env = NULL;
|
||||
char ***nsEnv = _NSGetEnviron();
|
||||
if (nsEnv)
|
||||
env = *nsEnv;
|
||||
int result = posix_spawnp(NULL,
|
||||
argv[0],
|
||||
NULL,
|
||||
&spawnattr,
|
||||
&argv[0],
|
||||
env);
|
||||
|
||||
posix_spawnattr_destroy(&spawnattr);
|
||||
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
@implementation CrashReporterUI
|
||||
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
gUI = self;
|
||||
[mWindow center];
|
||||
|
||||
[mWindow setTitle:[[NSBundle mainBundle]
|
||||
objectForInfoDictionaryKey:@"CFBundleName"]];
|
||||
}
|
||||
|
||||
-(void)showCrashUI:(const StringTable&)files
|
||||
queryParameters:(const StringTable&)queryParameters
|
||||
sendURL:(const string&)sendURL
|
||||
{
|
||||
gFiles = files;
|
||||
gQueryParameters = queryParameters;
|
||||
gSendURL = sendURL;
|
||||
|
||||
[mWindow setTitle:Str(ST_CRASHREPORTERTITLE)];
|
||||
[mHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
|
||||
|
||||
NSRect viewReportFrame = [mViewReportButton frame];
|
||||
[mViewReportButton setTitle:Str(ST_VIEWREPORT)];
|
||||
[mViewReportButton sizeToFit];
|
||||
if (gRTLlayout) {
|
||||
// sizeToFit will keep the left side fixed, so realign
|
||||
float oldWidth = viewReportFrame.size.width;
|
||||
viewReportFrame = [mViewReportButton frame];
|
||||
viewReportFrame.origin.x += oldWidth - viewReportFrame.size.width;
|
||||
[mViewReportButton setFrame: viewReportFrame];
|
||||
}
|
||||
|
||||
[mSubmitReportButton setTitle:Str(ST_CHECKSUBMIT)];
|
||||
[mIncludeURLButton setTitle:Str(ST_CHECKURL)];
|
||||
[mEmailMeButton setTitle:Str(ST_CHECKEMAIL)];
|
||||
[mViewReportOkButton setTitle:Str(ST_OK)];
|
||||
|
||||
[mCommentText setPlaceholder:Str(ST_COMMENTGRAYTEXT)];
|
||||
if (gRTLlayout)
|
||||
[mCommentText toggleBaseWritingDirection:self];
|
||||
[[mEmailText cell] setPlaceholderString:Str(ST_EMAILGRAYTEXT)];
|
||||
|
||||
if (gQueryParameters.find("URL") != gQueryParameters.end()) {
|
||||
// save the URL value in case the checkbox gets unchecked
|
||||
gURLParameter = gQueryParameters["URL"];
|
||||
}
|
||||
else {
|
||||
// no URL specified, hide checkbox
|
||||
[mIncludeURLButton removeFromSuperview];
|
||||
// shrink window to fit
|
||||
NSRect frame = [mWindow frame];
|
||||
NSRect includeURLFrame = [mIncludeURLButton frame];
|
||||
NSRect emailFrame = [mEmailMeButton frame];
|
||||
int buttonMask = [mViewReportButton autoresizingMask];
|
||||
int checkMask = [mSubmitReportButton autoresizingMask];
|
||||
int commentScrollMask = [mCommentScrollView autoresizingMask];
|
||||
|
||||
[mViewReportButton setAutoresizingMask:NSViewMinYMargin];
|
||||
[mSubmitReportButton setAutoresizingMask:NSViewMinYMargin];
|
||||
[mCommentScrollView setAutoresizingMask:NSViewMinYMargin];
|
||||
|
||||
// remove all the space in between
|
||||
frame.size.height -= includeURLFrame.origin.y - emailFrame.origin.y;
|
||||
[mWindow setFrame:frame display: true animate:NO];
|
||||
|
||||
[mViewReportButton setAutoresizingMask:buttonMask];
|
||||
[mSubmitReportButton setAutoresizingMask:checkMask];
|
||||
[mCommentScrollView setAutoresizingMask:commentScrollMask];
|
||||
}
|
||||
|
||||
// resize some buttons horizontally and possibly some controls vertically
|
||||
[self doInitialResizing];
|
||||
|
||||
// load default state of submit checkbox
|
||||
// we don't just do this via IB because we want the default to be
|
||||
// off a certain percentage of the time
|
||||
BOOL submitChecked = NO;
|
||||
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
if (nil != [userDefaults objectForKey:@"submitReport"]) {
|
||||
submitChecked = [userDefaults boolForKey:@"submitReport"];
|
||||
}
|
||||
else {
|
||||
// use compile-time specified enable percentage
|
||||
submitChecked = ShouldEnableSending();
|
||||
[userDefaults setBool:submitChecked forKey:@"submitReport"];
|
||||
}
|
||||
[mSubmitReportButton setState:(submitChecked ? NSOnState : NSOffState)];
|
||||
|
||||
[self updateSubmit];
|
||||
[self updateURL];
|
||||
[self updateEmail];
|
||||
|
||||
[mWindow makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
-(void)showErrorUI:(const string&)message
|
||||
{
|
||||
[self setView: mErrorView animate: NO];
|
||||
|
||||
[mErrorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
|
||||
[self setStringFitVertically:mErrorLabel
|
||||
string:NSSTR(message)
|
||||
resizeWindow:YES];
|
||||
[mErrorCloseButton setTitle:Str(ST_OK)];
|
||||
|
||||
[mErrorCloseButton setKeyEquivalent:@"\r"];
|
||||
[mWindow makeFirstResponder:mErrorCloseButton];
|
||||
[mWindow makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
-(void)showReportInfo
|
||||
{
|
||||
NSDictionary* boldAttr = [NSDictionary
|
||||
dictionaryWithObject:
|
||||
[NSFont boldSystemFontOfSize:
|
||||
[NSFont smallSystemFontSize]]
|
||||
forKey:NSFontAttributeName];
|
||||
NSDictionary* normalAttr = [NSDictionary
|
||||
dictionaryWithObject:
|
||||
[NSFont systemFontOfSize:
|
||||
[NSFont smallSystemFontSize]]
|
||||
forKey:NSFontAttributeName];
|
||||
|
||||
[mViewReportTextView setString:@""];
|
||||
for (StringTable::iterator iter = gQueryParameters.begin();
|
||||
iter != gQueryParameters.end();
|
||||
iter++) {
|
||||
NSAttributedString* key = [[NSAttributedString alloc]
|
||||
initWithString:NSSTR(iter->first + ": ")
|
||||
attributes:boldAttr];
|
||||
NSAttributedString* value = [[NSAttributedString alloc]
|
||||
initWithString:NSSTR(iter->second + "\n")
|
||||
attributes:normalAttr];
|
||||
[[mViewReportTextView textStorage] appendAttributedString: key];
|
||||
[[mViewReportTextView textStorage] appendAttributedString: value];
|
||||
[key release];
|
||||
[value release];
|
||||
}
|
||||
|
||||
NSAttributedString* extra = [[NSAttributedString alloc]
|
||||
initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO])
|
||||
attributes:normalAttr];
|
||||
[[mViewReportTextView textStorage] appendAttributedString: extra];
|
||||
[extra release];
|
||||
}
|
||||
|
||||
- (void)maybeSubmitReport
|
||||
{
|
||||
if ([mSubmitReportButton state] == NSOnState) {
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_REPORTDURINGSUBMIT)
|
||||
resizeWindow:YES];
|
||||
// disable all the controls
|
||||
[self enableControls:NO];
|
||||
[mSubmitReportButton setEnabled:NO];
|
||||
[mRestartButton setEnabled:NO];
|
||||
[mCloseButton setEnabled:NO];
|
||||
[mProgressIndicator startAnimation:self];
|
||||
gDidTrySend = true;
|
||||
[self sendReport];
|
||||
} else {
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)closeMeDown:(id)unused
|
||||
{
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
|
||||
-(IBAction)submitReportClicked:(id)sender
|
||||
{
|
||||
[self updateSubmit];
|
||||
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
[userDefaults setBool:([mSubmitReportButton state] == NSOnState)
|
||||
forKey:@"submitReport"];
|
||||
[userDefaults synchronize];
|
||||
}
|
||||
|
||||
-(IBAction)viewReportClicked:(id)sender
|
||||
{
|
||||
[self showReportInfo];
|
||||
[NSApp beginSheet:mViewReportWindow modalForWindow:mWindow
|
||||
modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
||||
}
|
||||
|
||||
- (IBAction)viewReportOkClicked:(id)sender
|
||||
{
|
||||
[mViewReportWindow orderOut:nil];
|
||||
[NSApp endSheet:mViewReportWindow];
|
||||
}
|
||||
|
||||
-(IBAction)closeClicked:(id)sender
|
||||
{
|
||||
[self maybeSubmitReport];
|
||||
}
|
||||
|
||||
-(IBAction)restartClicked:(id)sender
|
||||
{
|
||||
RestartApplication();
|
||||
[self maybeSubmitReport];
|
||||
}
|
||||
|
||||
- (IBAction)includeURLClicked:(id)sender
|
||||
{
|
||||
[self updateURL];
|
||||
}
|
||||
|
||||
-(IBAction)emailMeClicked:(id)sender
|
||||
{
|
||||
[self updateEmail];
|
||||
}
|
||||
|
||||
-(void)controlTextDidChange:(NSNotification *)note
|
||||
{
|
||||
[self updateEmail];
|
||||
}
|
||||
|
||||
- (void)textDidChange:(NSNotification *)aNotification
|
||||
{
|
||||
// update comment parameter
|
||||
if ([[[mCommentText textStorage] mutableString] length] > 0)
|
||||
gQueryParameters["Comments"] = [[[mCommentText textStorage] mutableString]
|
||||
UTF8String];
|
||||
else
|
||||
gQueryParameters.erase("Comments");
|
||||
}
|
||||
|
||||
// Limit the comment field to 500 bytes in UTF-8
|
||||
- (BOOL)textView:(NSTextView *)aTextView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(NSString *)replacementString
|
||||
{
|
||||
// current string length + replacement text length - replaced range length
|
||||
if (([[aTextView string]
|
||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding]
|
||||
+ [replacementString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]
|
||||
- [[[aTextView string] substringWithRange:affectedCharRange]
|
||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding])
|
||||
> MAX_COMMENT_LENGTH) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)doInitialResizing
|
||||
{
|
||||
NSRect windowFrame = [mWindow frame];
|
||||
NSRect restartFrame = [mRestartButton frame];
|
||||
NSRect closeFrame = [mCloseButton frame];
|
||||
// resize close button to fit text
|
||||
float oldCloseWidth = closeFrame.size.width;
|
||||
[mCloseButton setTitle:Str(ST_QUIT)];
|
||||
[mCloseButton sizeToFit];
|
||||
closeFrame = [mCloseButton frame];
|
||||
// move close button left if it grew
|
||||
if (!gRTLlayout) {
|
||||
closeFrame.origin.x -= closeFrame.size.width - oldCloseWidth;
|
||||
}
|
||||
|
||||
if (gRestartArgs.size() == 0) {
|
||||
[mRestartButton removeFromSuperview];
|
||||
if (!gRTLlayout) {
|
||||
closeFrame.origin.x = restartFrame.origin.x +
|
||||
(restartFrame.size.width - closeFrame.size.width);
|
||||
}
|
||||
else {
|
||||
closeFrame.origin.x = restartFrame.origin.x;
|
||||
}
|
||||
[mCloseButton setFrame: closeFrame];
|
||||
[mCloseButton setKeyEquivalent:@"\r"];
|
||||
} else {
|
||||
[mRestartButton setTitle:Str(ST_RESTART)];
|
||||
// resize "restart" button
|
||||
float oldRestartWidth = restartFrame.size.width;
|
||||
[mRestartButton sizeToFit];
|
||||
restartFrame = [mRestartButton frame];
|
||||
if (!gRTLlayout) {
|
||||
// move left by the amount that the button grew
|
||||
restartFrame.origin.x -= restartFrame.size.width - oldRestartWidth;
|
||||
closeFrame.origin.x -= restartFrame.size.width - oldRestartWidth;
|
||||
}
|
||||
else {
|
||||
// shift the close button right in RTL
|
||||
closeFrame.origin.x += restartFrame.size.width - oldRestartWidth;
|
||||
}
|
||||
[mRestartButton setFrame: restartFrame];
|
||||
[mCloseButton setFrame: closeFrame];
|
||||
// possibly resize window if both buttons no longer fit
|
||||
// leave 20 px from either side of the window, and 12 px
|
||||
// between the buttons
|
||||
float neededWidth = closeFrame.size.width + restartFrame.size.width +
|
||||
2*20 + 12;
|
||||
|
||||
if (neededWidth > windowFrame.size.width) {
|
||||
windowFrame.size.width = neededWidth;
|
||||
[mWindow setFrame:windowFrame display: true animate: NO];
|
||||
}
|
||||
[mRestartButton setKeyEquivalent:@"\r"];
|
||||
}
|
||||
|
||||
NSButton *checkboxes[] = {
|
||||
mSubmitReportButton,
|
||||
mIncludeURLButton,
|
||||
mEmailMeButton
|
||||
};
|
||||
|
||||
for (int i=0; i<3; i++) {
|
||||
NSRect frame = [checkboxes[i] frame];
|
||||
[checkboxes[i] sizeToFit];
|
||||
if (gRTLlayout) {
|
||||
// sizeToFit will keep the left side fixed, so realign
|
||||
float oldWidth = frame.size.width;
|
||||
frame = [checkboxes[i] frame];
|
||||
frame.origin.x += oldWidth - frame.size.width;
|
||||
[checkboxes[i] setFrame: frame];
|
||||
}
|
||||
// keep existing spacing on left side, + 20 px spare on right
|
||||
float neededWidth = frame.origin.x + frame.size.width + 20;
|
||||
if (neededWidth > windowFrame.size.width) {
|
||||
windowFrame.size.width = neededWidth;
|
||||
[mWindow setFrame:windowFrame display: true animate: NO];
|
||||
}
|
||||
}
|
||||
|
||||
// do this down here because we may have made the window wider
|
||||
// up above
|
||||
[self setStringFitVertically:mDescriptionLabel
|
||||
string:Str(ST_CRASHREPORTERDESCRIPTION)
|
||||
resizeWindow:YES];
|
||||
|
||||
// now pin all the controls (except quit/submit) in place,
|
||||
// if we lengthen the window after this, it's just to lengthen
|
||||
// the progress text, so nothing above that text should move.
|
||||
NSView* views[] = {
|
||||
mSubmitReportButton,
|
||||
mViewReportButton,
|
||||
mCommentScrollView,
|
||||
mIncludeURLButton,
|
||||
mEmailMeButton,
|
||||
mEmailText,
|
||||
mProgressIndicator,
|
||||
mProgressText
|
||||
};
|
||||
for (unsigned int i=0; i<sizeof(views)/sizeof(views[0]); i++) {
|
||||
[views[i] setAutoresizingMask:NSViewMinYMargin];
|
||||
}
|
||||
}
|
||||
|
||||
-(float)setStringFitVertically:(NSControl*)control
|
||||
string:(NSString*)str
|
||||
resizeWindow:(BOOL)resizeWindow
|
||||
{
|
||||
// hack to make the text field grow vertically
|
||||
NSRect frame = [control frame];
|
||||
float oldHeight = frame.size.height;
|
||||
|
||||
frame.size.height = 10000;
|
||||
NSSize oldCellSize = [[control cell] cellSizeForBounds: frame];
|
||||
[control setStringValue: str];
|
||||
NSSize newCellSize = [[control cell] cellSizeForBounds: frame];
|
||||
|
||||
float delta = newCellSize.height - oldCellSize.height;
|
||||
frame.origin.y -= delta;
|
||||
frame.size.height = oldHeight + delta;
|
||||
[control setFrame: frame];
|
||||
|
||||
if (resizeWindow) {
|
||||
NSRect frame = [mWindow frame];
|
||||
frame.origin.y -= delta;
|
||||
frame.size.height += delta;
|
||||
[mWindow setFrame:frame display: true animate: NO];
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
-(void)setView: (NSView*)v animate: (BOOL)animate
|
||||
{
|
||||
NSRect frame = [mWindow frame];
|
||||
|
||||
NSRect oldViewFrame = [[mWindow contentView] frame];
|
||||
NSRect newViewFrame = [v frame];
|
||||
|
||||
frame.origin.y += oldViewFrame.size.height - newViewFrame.size.height;
|
||||
frame.size.height -= oldViewFrame.size.height - newViewFrame.size.height;
|
||||
|
||||
frame.origin.x += oldViewFrame.size.width - newViewFrame.size.width;
|
||||
frame.size.width -= oldViewFrame.size.width - newViewFrame.size.width;
|
||||
|
||||
[mWindow setContentView:v];
|
||||
[mWindow setFrame:frame display:true animate:animate];
|
||||
}
|
||||
|
||||
- (void)enableControls:(BOOL)enabled
|
||||
{
|
||||
[mViewReportButton setEnabled:enabled];
|
||||
[mIncludeURLButton setEnabled:enabled];
|
||||
[mEmailMeButton setEnabled:enabled];
|
||||
[mCommentText setEnabled:enabled];
|
||||
[mCommentScrollView setHasVerticalScroller:enabled];
|
||||
[self updateEmail];
|
||||
}
|
||||
|
||||
-(void)updateSubmit
|
||||
{
|
||||
if ([mSubmitReportButton state] == NSOnState) {
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_REPORTPRESUBMIT)
|
||||
resizeWindow:YES];
|
||||
[mProgressText setHidden:NO];
|
||||
// enable all the controls
|
||||
[self enableControls:YES];
|
||||
}
|
||||
else {
|
||||
// not submitting, disable all the controls under
|
||||
// the submit checkbox, and hide the status text
|
||||
[mProgressText setHidden:YES];
|
||||
[self enableControls:NO];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)updateURL
|
||||
{
|
||||
if ([mIncludeURLButton state] == NSOnState && !gURLParameter.empty()) {
|
||||
gQueryParameters["URL"] = gURLParameter;
|
||||
} else {
|
||||
gQueryParameters.erase("URL");
|
||||
}
|
||||
}
|
||||
|
||||
-(void)updateEmail
|
||||
{
|
||||
if ([mEmailMeButton state] == NSOnState &&
|
||||
[mSubmitReportButton state] == NSOnState) {
|
||||
NSString* email = [mEmailText stringValue];
|
||||
gQueryParameters["Email"] = [email UTF8String];
|
||||
[mEmailText setEnabled:YES];
|
||||
} else {
|
||||
gQueryParameters.erase("Email");
|
||||
[mEmailText setEnabled:NO];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)sendReport
|
||||
{
|
||||
if (![self setupPost]) {
|
||||
LogMessage("Crash report submission failed: could not set up POST data");
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_SUBMITFAILED)
|
||||
resizeWindow:YES];
|
||||
// quit after 5 seconds
|
||||
[self performSelector:@selector(closeMeDown:) withObject:nil
|
||||
afterDelay:5.0];
|
||||
}
|
||||
|
||||
[NSThread detachNewThreadSelector:@selector(uploadThread:)
|
||||
toTarget:self
|
||||
withObject:mPost];
|
||||
}
|
||||
|
||||
-(bool)setupPost
|
||||
{
|
||||
NSURL* url = [NSURL URLWithString:[NSSTR(gSendURL) stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
if (!url) return false;
|
||||
|
||||
mPost = [[HTTPMultipartUpload alloc] initWithURL: url];
|
||||
if (!mPost) return false;
|
||||
|
||||
NSMutableDictionary* parameters =
|
||||
[[NSMutableDictionary alloc] initWithCapacity: gQueryParameters.size()];
|
||||
if (!parameters) return false;
|
||||
|
||||
StringTable::const_iterator end = gQueryParameters.end();
|
||||
for (StringTable::const_iterator i = gQueryParameters.begin();
|
||||
i != end;
|
||||
i++) {
|
||||
NSString* key = NSSTR(i->first);
|
||||
NSString* value = NSSTR(i->second);
|
||||
if (key && value) {
|
||||
[parameters setObject: value forKey: key];
|
||||
} else {
|
||||
ostringstream message;
|
||||
message << "Warning: skipping annotation '" << i->first
|
||||
<< "' due to malformed UTF-8 encoding";
|
||||
LogMessage(message.str());
|
||||
}
|
||||
}
|
||||
|
||||
for (StringTable::const_iterator i = gFiles.begin();
|
||||
i != gFiles.end();
|
||||
i++) {
|
||||
[mPost addFileAtPath: NSSTR(i->second) name: NSSTR(i->first)];
|
||||
}
|
||||
|
||||
[mPost setParameters: parameters];
|
||||
[parameters release];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
-(void)uploadComplete:(NSData*)data
|
||||
{
|
||||
NSHTTPURLResponse* response = [mPost response];
|
||||
[mPost release];
|
||||
|
||||
bool success;
|
||||
string reply;
|
||||
if (!data || !response || [response statusCode] != 200) {
|
||||
success = false;
|
||||
reply = "";
|
||||
|
||||
// if data is nil, we probably logged an error in uploadThread
|
||||
if (data != nil && response != nil) {
|
||||
ostringstream message;
|
||||
message << "Crash report submission failed: server returned status "
|
||||
<< [response statusCode];
|
||||
LogMessage(message.str());
|
||||
}
|
||||
} else {
|
||||
success = true;
|
||||
LogMessage("Crash report submitted successfully");
|
||||
|
||||
NSString* encodingName = [response textEncodingName];
|
||||
NSStringEncoding encoding;
|
||||
if (encodingName) {
|
||||
encoding = CFStringConvertEncodingToNSStringEncoding(
|
||||
CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName));
|
||||
} else {
|
||||
encoding = NSISOLatin1StringEncoding;
|
||||
}
|
||||
NSString* r = [[NSString alloc] initWithData: data encoding: encoding];
|
||||
reply = [r UTF8String];
|
||||
[r release];
|
||||
}
|
||||
|
||||
SendCompleted(success, reply);
|
||||
|
||||
[mProgressIndicator stopAnimation:self];
|
||||
if (success) {
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_REPORTSUBMITSUCCESS)
|
||||
resizeWindow:YES];
|
||||
} else {
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_SUBMITFAILED)
|
||||
resizeWindow:YES];
|
||||
}
|
||||
// quit after 5 seconds
|
||||
[self performSelector:@selector(closeMeDown:) withObject:nil
|
||||
afterDelay:5.0];
|
||||
}
|
||||
|
||||
-(void)uploadThread:(HTTPMultipartUpload*)post
|
||||
{
|
||||
NSAutoreleasePool* autoreleasepool = [[NSAutoreleasePool alloc] init];
|
||||
NSError* error = nil;
|
||||
NSData* data = [post send: &error];
|
||||
if (error) {
|
||||
data = nil;
|
||||
NSString* errorDesc = [error localizedDescription];
|
||||
string message = [errorDesc UTF8String];
|
||||
LogMessage("Crash report submission failed: " + message);
|
||||
}
|
||||
|
||||
[self performSelectorOnMainThread: @selector(uploadComplete:)
|
||||
withObject: data
|
||||
waitUntilDone: YES];
|
||||
|
||||
[autoreleasepool release];
|
||||
}
|
||||
|
||||
// to get auto-quit when we close the window
|
||||
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
// since we use [NSApp terminate:] we never return to main,
|
||||
// so do our cleanup here
|
||||
if (!gDidTrySend)
|
||||
DeleteDump();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation TextViewWithPlaceHolder
|
||||
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
[self setNeedsDisplay:YES];
|
||||
return [super becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
if (mPlaceHolderString && [[self string] isEqualToString:@""] &&
|
||||
self != [[self window] firstResponder])
|
||||
[mPlaceHolderString drawInRect:[self frame]];
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
[self setNeedsDisplay:YES];
|
||||
return [super resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)setPlaceholder:(NSString*)placeholder
|
||||
{
|
||||
NSColor* txtColor = [NSColor disabledControlTextColor];
|
||||
NSDictionary* txtDict = [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:txtColor,
|
||||
NSForegroundColorAttributeName, nil];
|
||||
mPlaceHolderString = [[NSMutableAttributedString alloc]
|
||||
initWithString:placeholder attributes:txtDict];
|
||||
if (gRTLlayout)
|
||||
[mPlaceHolderString setAlignment:NSRightTextAlignment
|
||||
range:NSMakeRange(0, [placeholder length])];
|
||||
|
||||
}
|
||||
|
||||
- (void)insertTab:(id)sender
|
||||
{
|
||||
// don't actually want to insert tabs, just tab to next control
|
||||
[[self window] selectNextKeyView:sender];
|
||||
}
|
||||
|
||||
- (void)insertBacktab:(id)sender
|
||||
{
|
||||
[[self window] selectPreviousKeyView:sender];
|
||||
}
|
||||
|
||||
- (void)setEnabled:(BOOL)enabled
|
||||
{
|
||||
[self setSelectable:enabled];
|
||||
[self setEditable:enabled];
|
||||
if (![[self string] isEqualToString:@""]) {
|
||||
NSAttributedString* colorString;
|
||||
NSColor* txtColor;
|
||||
if (enabled)
|
||||
txtColor = [NSColor textColor];
|
||||
else
|
||||
txtColor = [NSColor disabledControlTextColor];
|
||||
NSDictionary *txtDict = [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:txtColor,
|
||||
NSForegroundColorAttributeName, nil];
|
||||
colorString = [[NSAttributedString alloc]
|
||||
initWithString:[self string]
|
||||
attributes:txtDict];
|
||||
[[self textStorage] setAttributedString: colorString];
|
||||
[self setInsertionPointColor:txtColor];
|
||||
[colorString release];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[mPlaceHolderString release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/* === Crashreporter UI Functions === */
|
||||
|
||||
bool UIInit()
|
||||
{
|
||||
gMainPool = [[NSAutoreleasePool alloc] init];
|
||||
[NSApplication sharedApplication];
|
||||
|
||||
if (gStrings.find("isRTL") != gStrings.end() &&
|
||||
gStrings["isRTL"] == "yes")
|
||||
gRTLlayout = true;
|
||||
|
||||
[NSBundle loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu")
|
||||
owner:NSApp];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UIShutdown()
|
||||
{
|
||||
[gMainPool release];
|
||||
}
|
||||
|
||||
void UIShowDefaultUI()
|
||||
{
|
||||
[gUI showErrorUI: gStrings[ST_CRASHREPORTERDEFAULT]];
|
||||
[NSApp run];
|
||||
}
|
||||
|
||||
bool UIShowCrashUI(const StringTable& files,
|
||||
const StringTable& queryParameters,
|
||||
const string& sendURL,
|
||||
const vector<string>& restartArgs)
|
||||
{
|
||||
gRestartArgs = restartArgs;
|
||||
|
||||
[gUI showCrashUI: files
|
||||
queryParameters: queryParameters
|
||||
sendURL: sendURL];
|
||||
[NSApp run];
|
||||
|
||||
return gDidTrySend;
|
||||
}
|
||||
|
||||
void UIError_impl(const string& message)
|
||||
{
|
||||
if (!gUI) {
|
||||
// UI failed to initialize, printing is the best we can do
|
||||
printf("Error: %s\n", message.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
[gUI showErrorUI: message];
|
||||
[NSApp run];
|
||||
}
|
||||
|
||||
bool UIGetIniPath(string& path)
|
||||
{
|
||||
NSString* tmpPath = [NSString stringWithUTF8String:gArgv[0]];
|
||||
NSString* iniName = [tmpPath lastPathComponent];
|
||||
iniName = [iniName stringByAppendingPathExtension:@"ini"];
|
||||
tmpPath = [tmpPath stringByDeletingLastPathComponent];
|
||||
tmpPath = [tmpPath stringByDeletingLastPathComponent];
|
||||
tmpPath = [tmpPath stringByAppendingPathComponent:@"Resources"];
|
||||
tmpPath = [tmpPath stringByAppendingPathComponent:iniName];
|
||||
path = [tmpPath UTF8String];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UIGetSettingsPath(const string& vendor,
|
||||
const string& product,
|
||||
string& settingsPath)
|
||||
{
|
||||
FSRef foundRef;
|
||||
OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType,
|
||||
kCreateFolder, &foundRef);
|
||||
if (err != noErr)
|
||||
return false;
|
||||
|
||||
unsigned char path[PATH_MAX];
|
||||
FSRefMakePath(&foundRef, path, sizeof(path));
|
||||
NSString* destPath = [NSString stringWithUTF8String:reinterpret_cast<char*>(path)];
|
||||
|
||||
// Note that MacOS ignores the vendor when creating the profile hierarchy -
|
||||
// all application preferences directories live alongside one another in
|
||||
// ~/Library/Application Support/
|
||||
destPath = [destPath stringByAppendingPathComponent: NSSTR(product)];
|
||||
// Thunderbird stores its profile in ~/Library/Thunderbird,
|
||||
// but we're going to put stuff in ~/Library/Application Support/Thunderbird
|
||||
// anyway, so we have to ensure that path exists.
|
||||
string tempPath = [destPath UTF8String];
|
||||
if (!UIEnsurePathExists(tempPath))
|
||||
return false;
|
||||
|
||||
destPath = [destPath stringByAppendingPathComponent: @"Crash Reports"];
|
||||
|
||||
settingsPath = [destPath UTF8String];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UIEnsurePathExists(const string& path)
|
||||
{
|
||||
int ret = mkdir(path.c_str(), S_IRWXU);
|
||||
int e = errno;
|
||||
if (ret == -1 && e != EEXIST)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UIFileExists(const string& path)
|
||||
{
|
||||
struct stat sb;
|
||||
int ret = stat(path.c_str(), &sb);
|
||||
if (ret == -1 || !(sb.st_mode & S_IFREG))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UIMoveFile(const string& file, const string& newfile)
|
||||
{
|
||||
if (!rename(file.c_str(), newfile.c_str()))
|
||||
return true;
|
||||
if (errno != EXDEV)
|
||||
return false;
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSString *source = [fileManager stringWithFileSystemRepresentation:file.c_str() length:file.length()];
|
||||
NSString *dest = [fileManager stringWithFileSystemRepresentation:newfile.c_str() length:newfile.length()];
|
||||
if (!source || !dest)
|
||||
return false;
|
||||
|
||||
[fileManager moveItemAtPath:source toPath:dest error:NULL];
|
||||
return UIFileExists(newfile);
|
||||
}
|
||||
|
||||
bool UIDeleteFile(const string& file)
|
||||
{
|
||||
return (unlink(file.c_str()) != -1);
|
||||
}
|
||||
|
||||
std::ifstream* UIOpenRead(const string& filename)
|
||||
{
|
||||
return new std::ifstream(filename.c_str(), std::ios::in);
|
||||
}
|
||||
|
||||
std::ofstream* UIOpenWrite(const string& filename,
|
||||
bool append, // append=false
|
||||
bool binary) // binary=false
|
||||
{
|
||||
std::ios_base::openmode mode = std::ios::out;
|
||||
|
||||
if (append) {
|
||||
mode = mode | std::ios::app;
|
||||
}
|
||||
|
||||
if (binary) {
|
||||
mode = mode | std::ios::binary;
|
||||
}
|
||||
|
||||
return new std::ofstream(filename.c_str(), mode);
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "crashreporter.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace CrashReporter;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::sort;
|
||||
|
||||
struct FileData
|
||||
{
|
||||
time_t timestamp;
|
||||
string path;
|
||||
};
|
||||
|
||||
static bool CompareFDTime(const FileData& fd1, const FileData& fd2)
|
||||
{
|
||||
return fd1.timestamp > fd2.timestamp;
|
||||
}
|
||||
|
||||
void UIPruneSavedDumps(const std::string& directory)
|
||||
{
|
||||
DIR *dirfd = opendir(directory.c_str());
|
||||
if (!dirfd)
|
||||
return;
|
||||
|
||||
vector<FileData> dumpfiles;
|
||||
|
||||
while (dirent *dir = readdir(dirfd)) {
|
||||
FileData fd;
|
||||
fd.path = directory + '/' + dir->d_name;
|
||||
if (fd.path.size() < 5)
|
||||
continue;
|
||||
|
||||
if (fd.path.compare(fd.path.size() - 4, 4, ".dmp") != 0)
|
||||
continue;
|
||||
|
||||
struct stat st;
|
||||
if (stat(fd.path.c_str(), &st)) {
|
||||
closedir(dirfd);
|
||||
return;
|
||||
}
|
||||
|
||||
fd.timestamp = st.st_mtime;
|
||||
|
||||
dumpfiles.push_back(fd);
|
||||
}
|
||||
|
||||
sort(dumpfiles.begin(), dumpfiles.end(), CompareFDTime);
|
||||
|
||||
while (dumpfiles.size() > kSaveCount) {
|
||||
// get the path of the oldest file
|
||||
string path = dumpfiles[dumpfiles.size() - 1].path;
|
||||
UIDeleteFile(path.c_str());
|
||||
|
||||
// s/.dmp/.extra/
|
||||
path.replace(path.size() - 4, 4, ".extra");
|
||||
UIDeleteFile(path.c_str());
|
||||
|
||||
dumpfiles.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void UIRunMinidumpAnalyzer(const string& exename, const string& filename)
|
||||
{
|
||||
// Run the minidump analyzer and wait for it to finish
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == -1) {
|
||||
return; // Nothing to do upon failure
|
||||
} else if (pid == 0) {
|
||||
execl(exename.c_str(), exename.c_str(), filename.c_str(), nullptr);
|
||||
} else {
|
||||
waitpid(pid, nullptr, 0);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,32 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>crashreporter</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>crashreporter</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>crashreporter.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.mozilla.crashreporter</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>crashreporter</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>LSHasLocalizedDisplayName</key>
|
||||
<true/>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
APPL????
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
CFBundleName = "Crash Reporter";
|
||||
CFBundleDisplayName = "Crash Reporter";
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBClasses</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>ACTIONS</key>
|
||||
<dict>
|
||||
<key>closeClicked</key>
|
||||
<string>id</string>
|
||||
<key>emailMeClicked</key>
|
||||
<string>id</string>
|
||||
<key>includeURLClicked</key>
|
||||
<string>id</string>
|
||||
<key>restartClicked</key>
|
||||
<string>id</string>
|
||||
<key>submitReportClicked</key>
|
||||
<string>id</string>
|
||||
<key>viewReportClicked</key>
|
||||
<string>id</string>
|
||||
<key>viewReportOkClicked</key>
|
||||
<string>id</string>
|
||||
</dict>
|
||||
<key>CLASS</key>
|
||||
<string>CrashReporterUI</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>OUTLETS</key>
|
||||
<dict>
|
||||
<key>mCloseButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mCommentScrollView</key>
|
||||
<string>NSScrollView</string>
|
||||
<key>mCommentText</key>
|
||||
<string>TextViewWithPlaceHolder</string>
|
||||
<key>mDescriptionLabel</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mEmailMeButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mEmailText</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mErrorCloseButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mErrorHeaderLabel</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mErrorLabel</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mErrorView</key>
|
||||
<string>NSView</string>
|
||||
<key>mHeaderLabel</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mIncludeURLButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mProgressIndicator</key>
|
||||
<string>NSProgressIndicator</string>
|
||||
<key>mProgressText</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mRestartButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mSubmitReportButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mViewReportButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mViewReportOkButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mViewReportTextView</key>
|
||||
<string>NSTextView</string>
|
||||
<key>mViewReportWindow</key>
|
||||
<string>NSWindow</string>
|
||||
<key>mWindow</key>
|
||||
<string>NSWindow</string>
|
||||
</dict>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSObject</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>ACTIONS</key>
|
||||
<dict>
|
||||
<key>insertTab</key>
|
||||
<string>id</string>
|
||||
</dict>
|
||||
<key>CLASS</key>
|
||||
<string>TextViewWithPlaceHolder</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSTextView</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CLASS</key>
|
||||
<string>FirstResponder</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSObject</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>IBVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>629</string>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>5</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>9C7010</string>
|
||||
<key>targetFramework</key>
|
||||
<string>IBCocoaFramework</string>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
|
|
@ -1,102 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBClasses</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>ACTIONS</key>
|
||||
<dict>
|
||||
<key>closeClicked</key>
|
||||
<string>id</string>
|
||||
<key>emailMeClicked</key>
|
||||
<string>id</string>
|
||||
<key>includeURLClicked</key>
|
||||
<string>id</string>
|
||||
<key>restartClicked</key>
|
||||
<string>id</string>
|
||||
<key>submitReportClicked</key>
|
||||
<string>id</string>
|
||||
<key>viewReportClicked</key>
|
||||
<string>id</string>
|
||||
<key>viewReportOkClicked</key>
|
||||
<string>id</string>
|
||||
</dict>
|
||||
<key>CLASS</key>
|
||||
<string>CrashReporterUI</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>OUTLETS</key>
|
||||
<dict>
|
||||
<key>mCloseButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mCommentScrollView</key>
|
||||
<string>NSScrollView</string>
|
||||
<key>mCommentText</key>
|
||||
<string>TextViewWithPlaceHolder</string>
|
||||
<key>mDescriptionLabel</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mEmailMeButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mEmailText</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mErrorCloseButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mErrorHeaderLabel</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mErrorLabel</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mErrorView</key>
|
||||
<string>NSView</string>
|
||||
<key>mHeaderLabel</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mIncludeURLButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mProgressIndicator</key>
|
||||
<string>NSProgressIndicator</string>
|
||||
<key>mProgressText</key>
|
||||
<string>NSTextField</string>
|
||||
<key>mRestartButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mSubmitReportButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mViewReportButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mViewReportOkButton</key>
|
||||
<string>NSButton</string>
|
||||
<key>mViewReportTextView</key>
|
||||
<string>NSTextView</string>
|
||||
<key>mViewReportWindow</key>
|
||||
<string>NSWindow</string>
|
||||
<key>mWindow</key>
|
||||
<string>NSWindow</string>
|
||||
</dict>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSObject</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>ACTIONS</key>
|
||||
<dict>
|
||||
<key>insertTab</key>
|
||||
<string>id</string>
|
||||
</dict>
|
||||
<key>CLASS</key>
|
||||
<string>TextViewWithPlaceHolder</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSTextView</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CLASS</key>
|
||||
<string>FirstResponder</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSObject</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>IBVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>629</string>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>5</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>9D34</string>
|
||||
<key>targetFramework</key>
|
||||
<string>IBCocoaFramework</string>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,78 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG['OS_TARGET'] != 'Android':
|
||||
Program('crashreporter')
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'crashreporter.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
UNIFIED_SOURCES += [
|
||||
'crashreporter_win.cpp',
|
||||
]
|
||||
DEFINES['UNICODE'] = True
|
||||
DEFINES['_UNICODE'] = True
|
||||
USE_LIBS += [
|
||||
'google_breakpad_libxul_s',
|
||||
]
|
||||
OS_LIBS += [
|
||||
'comctl32',
|
||||
'shell32',
|
||||
'wininet',
|
||||
'shlwapi',
|
||||
]
|
||||
elif CONFIG['OS_ARCH'] == 'Darwin':
|
||||
UNIFIED_SOURCES += [
|
||||
'crashreporter_osx.mm',
|
||||
'crashreporter_unix_common.cpp',
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'../google-breakpad/src/common/mac',
|
||||
]
|
||||
OS_LIBS += ['-framework Cocoa']
|
||||
USE_LIBS += [
|
||||
'breakpad_common_s',
|
||||
'breakpad_mac_common_s',
|
||||
]
|
||||
elif CONFIG['OS_ARCH'] == 'SunOS':
|
||||
SOURCES += [
|
||||
'crashreporter_linux.cpp',
|
||||
'crashreporter_unix.cpp',
|
||||
]
|
||||
USE_LIBS += [
|
||||
'breakpad_solaris_common_s',
|
||||
]
|
||||
|
||||
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
||||
UNIFIED_SOURCES += [
|
||||
'crashreporter_gtk_common.cpp',
|
||||
'crashreporter_linux.cpp',
|
||||
'crashreporter_unix_common.cpp'
|
||||
]
|
||||
USE_LIBS += [
|
||||
'breakpad_linux_common_s',
|
||||
]
|
||||
OS_LIBS += CONFIG['TK_LIBS']
|
||||
OS_LIBS += CONFIG['MOZ_GTHREAD_LIBS']
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
CXXFLAGS += CONFIG['MOZ_GTHREAD_CFLAGS']
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'Linux' or CONFIG['OS_ARCH'] == 'SunOS':
|
||||
FINAL_TARGET_FILES += [
|
||||
'/toolkit/themes/windows/global/throbber/Throbber-small.gif',
|
||||
]
|
||||
|
||||
DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
|
||||
|
||||
RCINCLUDE = 'crashreporter.rc'
|
||||
|
||||
# Don't use the STL wrappers in the crashreporter clients; they don't
|
||||
# link with -lmozalloc, and it really doesn't matter here anyway.
|
||||
DISABLE_STL_WRAPPING = True
|
||||
|
||||
include('/toolkit/crashreporter/crashreporter.mozbuild')
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by crashreporter.rc
|
||||
//
|
||||
#define IDD_SENDDIALOG 102
|
||||
#define IDR_THROBBER 103
|
||||
#define IDD_VIEWREPORTDIALOG 104
|
||||
#define IDI_MAINICON 105
|
||||
#define IDC_PROGRESS 1003
|
||||
#define IDC_DESCRIPTIONTEXT 1004
|
||||
#define IDC_CLOSEBUTTON 1005
|
||||
#define IDC_VIEWREPORTBUTTON 1006
|
||||
#define IDC_SUBMITREPORTCHECK 1007
|
||||
#define IDC_EMAILMECHECK 1008
|
||||
#define IDC_EMAILTEXT 1009
|
||||
#define IDC_INCLUDEURLCHECK 1010
|
||||
#define IDC_COMMENTTEXT 1011
|
||||
#define IDC_RESTARTBUTTON 1012
|
||||
#define IDC_DESCRIPTIONLABEL 1013
|
||||
#define IDC_PROGRESSTEXT 1014
|
||||
#define IDC_THROBBER 1015
|
||||
#define IDC_VIEWREPORTTEXT 1016
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 106
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1017
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var { classes: Cc, utils: Cu, interfaces: Ci } = Components;
|
||||
|
||||
var reportURL;
|
||||
|
||||
Cu.import("resource://gre/modules/CrashReports.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
|
||||
"resource://gre/modules/CrashSubmit.jsm");
|
||||
|
||||
const buildID = Services.appinfo.appBuildID;
|
||||
|
||||
function submitPendingReport(event) {
|
||||
let link = event.target;
|
||||
let id = link.firstChild.textContent;
|
||||
link.className = "submitting";
|
||||
CrashSubmit.submit(id, { noThrottle: true }).then(
|
||||
(remoteCrashID) => {
|
||||
link.className = "";
|
||||
// Reset the link to point at our new crash report. This way, if the
|
||||
// user clicks "Back", the link will be correct.
|
||||
link.firstChild.textContent = remoteCrashID;
|
||||
link.setAttribute("id", remoteCrashID);
|
||||
link.removeEventListener("click", submitPendingReport, true);
|
||||
|
||||
if (reportURL) {
|
||||
link.setAttribute("href", reportURL + remoteCrashID);
|
||||
// redirect the user to their brand new crash report
|
||||
window.location.href = reportURL + remoteCrashID;
|
||||
}
|
||||
},
|
||||
() => {
|
||||
// XXX: do something more useful here
|
||||
link.className = "";
|
||||
|
||||
// Dispatch an event, useful for testing
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("CrashSubmitFailed", true, false);
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function populateReportList() {
|
||||
|
||||
Services.telemetry.getHistogramById("ABOUTCRASHES_OPENED_COUNT").add(1);
|
||||
|
||||
var prefService = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
|
||||
try {
|
||||
reportURL = prefService.getCharPref("breakpad.reportURL");
|
||||
// Ignore any non http/https urls
|
||||
if (!/^https?:/i.test(reportURL))
|
||||
reportURL = null;
|
||||
}
|
||||
catch (e) { }
|
||||
if (!reportURL) {
|
||||
document.getElementById("clear-reports").style.display = "none";
|
||||
document.getElementById("reportList").style.display = "none";
|
||||
document.getElementById("noConfig").style.display = "block";
|
||||
return;
|
||||
}
|
||||
let reports = CrashReports.getReports();
|
||||
|
||||
if (reports.length == 0) {
|
||||
document.getElementById("clear-reports").style.display = "none";
|
||||
document.getElementById("reportList").style.display = "none";
|
||||
document.getElementById("noReports").style.display = "block";
|
||||
return;
|
||||
}
|
||||
|
||||
const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global", true);
|
||||
var dateFormatter = new Intl.DateTimeFormat(locale, { year: '2-digit',
|
||||
month: 'numeric',
|
||||
day: 'numeric' });
|
||||
var timeFormatter = new Intl.DateTimeFormat(locale, { hour: 'numeric',
|
||||
minute: 'numeric' });
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var reportURI = ios.newURI(reportURL, null, null);
|
||||
// resolving this URI relative to /report/index
|
||||
var aboutThrottling = ios.newURI("../../about/throttling", null, reportURI);
|
||||
|
||||
for (var i = 0; i < reports.length; i++) {
|
||||
var row = document.createElement("tr");
|
||||
var cell = document.createElement("td");
|
||||
row.appendChild(cell);
|
||||
var link = document.createElement("a");
|
||||
if (reports[i].pending) {
|
||||
link.setAttribute("href", aboutThrottling.spec);
|
||||
link.addEventListener("click", submitPendingReport, true);
|
||||
}
|
||||
else {
|
||||
link.setAttribute("href", reportURL + reports[i].id);
|
||||
}
|
||||
link.setAttribute("id", reports[i].id);
|
||||
link.classList.add("crashReport");
|
||||
link.appendChild(document.createTextNode(reports[i].id));
|
||||
cell.appendChild(link);
|
||||
|
||||
var date = new Date(reports[i].date);
|
||||
cell = document.createElement("td");
|
||||
cell.appendChild(document.createTextNode(dateFormatter.format(date)));
|
||||
row.appendChild(cell);
|
||||
cell = document.createElement("td");
|
||||
cell.appendChild(document.createTextNode(timeFormatter.format(date)));
|
||||
row.appendChild(cell);
|
||||
if (reports[i].pending) {
|
||||
document.getElementById("unsubmitted").appendChild(row);
|
||||
} else {
|
||||
document.getElementById("submitted").appendChild(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var clearReports = Task.async(function*() {
|
||||
let bundle = Services.strings.createBundle("chrome://global/locale/crashes.properties");
|
||||
|
||||
if (!Services.
|
||||
prompt.confirm(window,
|
||||
bundle.GetStringFromName("deleteconfirm.title"),
|
||||
bundle.GetStringFromName("deleteconfirm.description"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cleanupFolder = Task.async(function*(path, filter) {
|
||||
let iterator = new OS.File.DirectoryIterator(path);
|
||||
try {
|
||||
yield iterator.forEach(Task.async(function*(aEntry) {
|
||||
if (!filter || (yield filter(aEntry))) {
|
||||
yield OS.File.remove(aEntry.path);
|
||||
}
|
||||
}));
|
||||
} catch (e) {
|
||||
if (!(e instanceof OS.File.Error) || !e.becauseNoSuchFile) {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
});
|
||||
|
||||
yield cleanupFolder(CrashReports.submittedDir.path, function*(aEntry) {
|
||||
return aEntry.name.startsWith("bp-") && aEntry.name.endsWith(".txt");
|
||||
});
|
||||
|
||||
let oneYearAgo = Date.now() - 31586000000;
|
||||
yield cleanupFolder(CrashReports.reportsDir.path, function*(aEntry) {
|
||||
if (!aEntry.name.startsWith("InstallTime") ||
|
||||
aEntry.name == "InstallTime" + buildID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let date = aEntry.winLastWriteDate;
|
||||
if (!date) {
|
||||
let stat = yield OS.File.stat(aEntry.path);
|
||||
date = stat.lastModificationDate;
|
||||
}
|
||||
|
||||
return (date < oneYearAgo);
|
||||
});
|
||||
|
||||
yield cleanupFolder(CrashReports.pendingDir.path);
|
||||
|
||||
document.getElementById("clear-reports").style.display = "none";
|
||||
document.getElementById("reportList").style.display = "none";
|
||||
document.getElementById("noReports").style.display = "block";
|
||||
});
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
|
||||
[
|
||||
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
|
||||
<!ENTITY % crashesDTD SYSTEM "chrome://global/locale/crashes.dtd">
|
||||
%globalDTD;
|
||||
%crashesDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<style type="text/css">
|
||||
:root {
|
||||
font-family: sans-serif;
|
||||
margin: 40px auto;
|
||||
min-width: 30em;
|
||||
max-width: 60em;
|
||||
}
|
||||
table {
|
||||
clear: both;
|
||||
width: 90%;
|
||||
margin: 0 auto;
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
th {
|
||||
font-size: 130%;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
th[chromedir="rtl"] {
|
||||
text-align: right;
|
||||
}
|
||||
/* name */
|
||||
th:first-child {
|
||||
padding-inline-end: 2em;
|
||||
}
|
||||
/* submitted */
|
||||
th:last-child {
|
||||
text-align: center;
|
||||
}
|
||||
:link, :visited {
|
||||
display: block;
|
||||
min-height: 17px;
|
||||
}
|
||||
/* date */
|
||||
td:first-child + td {
|
||||
width: 0;
|
||||
padding-inline-start: 1em;
|
||||
padding-inline-end: .5em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* time */
|
||||
td:last-child {
|
||||
width: 0;
|
||||
padding-inline-start: .5em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#clear-reports {
|
||||
float: right;
|
||||
}
|
||||
#clear-reports[chromedir="rtl"] {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.submitting {
|
||||
background-image: url(chrome://global/skin/icons/loading.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: right;
|
||||
background-size: 16px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.submitting {
|
||||
background-image: url(chrome://global/skin/icons/loading@2x.png);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" media="screen, projection" type="text/css"
|
||||
href="chrome://global/skin/in-content/common.css"/>
|
||||
<script type="application/javascript;version=1.8" src="chrome://global/content/crashes.js"/>
|
||||
|
||||
<title>&crashReports.title;</title>
|
||||
</head><body onload="populateReportList()" dir="&locale.dir;">
|
||||
<button chromedir="&locale.dir;" id="clear-reports"
|
||||
onclick="clearReports().then(null, Cu.reportError)">&clearAllReports.label;</button>
|
||||
<div id="reportList">
|
||||
<div id="reportListUnsubmitted">
|
||||
<h1>&crashesUnsubmitted.label;</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th chromedir="&locale.dir;">&id.heading;</th>
|
||||
<th chromedir="&locale.dir;" colspan="2">&dateCrashed.heading;</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="unsubmitted">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="reportListSubmitted">
|
||||
<h1>&crashesSubmitted.label;</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th chromedir="&locale.dir;">&id.heading;</th>
|
||||
<th chromedir="&locale.dir;" colspan="2">&dateSubmitted.heading;</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="submitted">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<p id="noReports" style="display: none">&noReports.label;</p>
|
||||
<p id="noConfig" style="display: none">&noConfig.label;</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/toolkit/crashreporter/google-breakpad/src',
|
||||
]
|
||||
|
||||
# Suppress warnings in third-party code.
|
||||
if CONFIG['_MSC_VER']:
|
||||
CXXFLAGS += [
|
||||
'-wd4005', # macro redefinition
|
||||
]
|
||||
elif CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-unused-local-typedefs',
|
||||
'-Wno-shadow',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += ['-Wno-implicit-fallthrough']
|
||||
|
||||
DEFINES['NO_STABS_SUPPORT'] = True
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
==============
|
||||
Crash Reporter
|
||||
==============
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
The **crash reporter** is a subsystem to record and manage application
|
||||
crash data.
|
||||
|
||||
While the subsystem is known as *crash reporter*, it helps to think of
|
||||
it more as a *process dump manager*. This is because the heart of this
|
||||
subsystem is really managing process dump files and these files are
|
||||
created not only from process crashes but also from hangs and other
|
||||
exceptional events.
|
||||
|
||||
The crash reporter subsystem is composed of a number of pieces working
|
||||
together.
|
||||
|
||||
Breakpad
|
||||
Breakpad is a library and set of tools to make collecting process
|
||||
information (notably dumps from crashes) easy. Breakpad is a 3rd
|
||||
party project (originaly developed by Google) that is imported into
|
||||
the tree.
|
||||
|
||||
Dump files
|
||||
Breakpad produces files called *dump files* that hold process data
|
||||
(stacks, heap data, etc).
|
||||
|
||||
Crash Reporter Client
|
||||
The crash reporter client is a standalone executable that is launched
|
||||
to handle dump files. This application optionally submits crashes to
|
||||
Mozilla (or the configured server).
|
||||
|
||||
Minidump Analyzer
|
||||
The minidump analyzer is a standalone executable that is launched by the
|
||||
crash reporter client or by the browser itself to extract stack traces from
|
||||
the dump files generated during a crash. It appends the stack traces to the
|
||||
.extra file associated with the crash dump.
|
||||
|
||||
How Main-Process Crash Handling Works
|
||||
=====================================
|
||||
|
||||
The crash handler is hooked up very early in the Gecko process lifetime.
|
||||
It all starts in ``XREMain::XRE_mainInit()`` from ``nsAppRunner.cpp``.
|
||||
Assuming crash reporting is enabled, this startup function registers an
|
||||
exception handler for the process and tells the crash reporter subsystem
|
||||
about basic metadata such as the application name and version.
|
||||
|
||||
The registration of the crash reporter exception handler doubles as
|
||||
initialization of the crash reporter itself. This happens in
|
||||
``CrashReporter::SetExceptionHandler()`` from ``nsExceptionHandler.cpp``.
|
||||
The crash reporter figures out what application to use for reporting
|
||||
dumped crashes and where to store these dump files on disk. The Breakpad
|
||||
exception handler (really just a mechanism for dumping process state) is
|
||||
initialized as part of this function. The Breakpad exception handler is
|
||||
a ``google_breakpad::ExceptionHandler`` instance and it's stored as
|
||||
``gExceptionHandler``.
|
||||
|
||||
As the application runs, various other systems may write *annotations*
|
||||
or *notes* to the crash reporter to indicate state of the application,
|
||||
help with possible reasons for a current or future crash, etc. These are
|
||||
performed via ``CrashReporter::AnnotateCrashReport()`` and
|
||||
``CrashReporter::AppendAppNotesToCrashReport()`` from
|
||||
``nsExceptionHandler.h``.
|
||||
|
||||
For well running applications, this is all that happens. However, if a
|
||||
crash or similar exceptional event occurs (such as a hang), we need to
|
||||
write a crash report.
|
||||
|
||||
When an event worthy of writing a dump occurs, the Breakpad exception
|
||||
handler is invoked and Breakpad does its thing. When Breakpad has
|
||||
finished, it calls back into ``CrashReporter::MinidumpCallback()`` from
|
||||
``nsExceptionHandler.cpp`` to tell the crash reporter about what was
|
||||
written.
|
||||
|
||||
``MinidumpCallback()`` performs a number of actions once a dump has been
|
||||
written. It writes a file with the time of the crash so other systems can
|
||||
easily determine the time of the last crash. It supplements the dump
|
||||
file with an *extra* file containing Mozilla-specific metadata. This data
|
||||
includes the annotations set via ``CrashReporter::AnnotateCrashReport()``
|
||||
as well as time since last crash, whether garbage collection was active at
|
||||
the time of the crash, memory statistics, etc.
|
||||
|
||||
If the *crash reporter client* is enabled, ``MinidumpCallback()`` invokes
|
||||
it. It simply tries to create a new *crash reporter client* process (e.g.
|
||||
*crashreporter.exe*) with the path to the written minidump file as an
|
||||
argument.
|
||||
|
||||
The *crash reporter client* performs a number of roles. There's a lot going
|
||||
on, so you may want to look at ``main()`` in ``crashreporter.cpp``. First,
|
||||
stack traces are extracted from the dump via the *minidump analyzer* tool.
|
||||
The resulting traces are appended to the .extra file of the crash. Then, the
|
||||
*crash reporter client* verifies that the dump data is sane. If it isn't
|
||||
(e.g. required metadata is missing), the dump data is ignored. If dump data
|
||||
looks sane, the dump data
|
||||
is moved into the *pending* directory for the configured data directory
|
||||
(defined via the ``MOZ_CRASHREPORTER_DATA_DIRECTORY`` environment variable
|
||||
or from the UI). Once this is done, the main crash reporter UI is displayed
|
||||
via ``UIShowCrashUI()``. The crash reporter UI is platform specific: there
|
||||
are separate versions for Windows, OS X, and various \*NIX presentation
|
||||
flavors (such as GTK). The basic gist is a dialog is displayed to the user
|
||||
and the user has the opportunity to submit this dump data to a remote
|
||||
server.
|
||||
|
||||
If a dump is submitted via the crash reporter, the raw dump files are
|
||||
removed from the *pending* directory and a file containing the
|
||||
crash ID from the remote server for the submitted dump is created in the
|
||||
*submitted* directory.
|
||||
|
||||
If the user chooses not to submit a dump in the crash reporter UI, the dump
|
||||
files are deleted.
|
||||
|
||||
And that's pretty much what happens when a crash/dump is written!
|
||||
|
||||
Plugin and Child Process Crashes
|
||||
================================
|
||||
|
||||
Crashes in plugin and child processes are also managed by the crash
|
||||
reporting subsystem.
|
||||
|
||||
Child process crashes are handled by the ``mozilla::dom::CrashReporterParent``
|
||||
class defined in ``dom/ipc``. When a child process crashes, the toplevel IPDL
|
||||
actor should check for it by calling TakeMinidump in its ``ActorDestroy``
|
||||
Method: see ``mozilla::plugins::PluginModuleParent::ActorDestroy`` and
|
||||
``mozilla::plugins::PluginModuleParent::ProcessFirstMinidump``. That method
|
||||
is responsible for calling
|
||||
``mozilla::dom::CrashReporterParent::GenerateCrashReportForMinidump`` with
|
||||
appropriate crash annotations specific to the crash. All child-process
|
||||
crashes are annotated with a ``ProcessType`` annotation, such as "content" or
|
||||
"plugin".
|
||||
|
||||
Submission of child process crashes is handled by application code. This
|
||||
code prompts the user to submit crashes in context-appropriate UI and then
|
||||
submits the crashes using ``CrashSubmit.jsm``.
|
||||
|
||||
Memory Reports
|
||||
==============
|
||||
|
||||
When a process detects that it is running low on memory, a memory report is
|
||||
saved. If the process crashes, the memory report will be included with the crash
|
||||
report. ``nsThread::SaveMemoryReportNearOOM()`` checks to see if the process is
|
||||
low on memory every 30 seconds at most and saves a report every 3 minutes at
|
||||
most. Since a child process cannot actually save to the hard drive, it instead
|
||||
notifies its parent process, which saves the report for it. If a crash does
|
||||
occur, the memory report is moved to the *pending* directory with the other dump
|
||||
data and an annotation is added to indicate the presence of the report. This
|
||||
happens in ``nsExceptionHandler.cpp``, but occurs in different functions
|
||||
depending on what process crashed. When the main process crashes, this happens
|
||||
in ``MinidumpCallback()``. When a child process crashes, it happens in
|
||||
``OnChildProcessDumpRequested()``, with the annotation being added in
|
||||
``WriteExtraData()``.
|
||||
|
||||
Flash Process Crashes
|
||||
=====================
|
||||
|
||||
On Windows Vista+, the Adobe Flash plugin creates two extra processes in its
|
||||
Firefox plugin to implement OS-level sandboxing. In order to catch crashes in
|
||||
these processes, Firefox injects a crash report handler into the process using the code at ``InjectCrashReporter.cpp``. When these crashes occur, the
|
||||
ProcessType=plugin annotation is present, and an additional annotation
|
||||
FlashProcessDump has the value "Sandbox" or "Broker".
|
||||
|
||||
Plugin Hangs
|
||||
============
|
||||
|
||||
Plugin hangs are handled as crash reports. If a plugin doesn't respond to an
|
||||
IPC message after 60 seconds, the plugin IPC code will take minidumps of all
|
||||
of the processes involved and then kill the plugin.
|
||||
|
||||
In this case, there will be only one .ini file with the crash report metadata,
|
||||
but there will be multiple dump files: at least one for the browser process and
|
||||
one for the plugin process, and perhaps also additional dumps for the Flash
|
||||
sandbox and broker processes. All of these files are submitted together as a
|
||||
unit. Before submission, the filenames of the files are linked:
|
||||
|
||||
- **uuid.ini** - *annotations, includes an additional_minidumps field*
|
||||
- **uuid.dmp** - *plugin process dump file*
|
||||
- **uuid-<other>.dmp** - *other process dump file as listed in additional_minidumps*
|
||||
|
||||
Browser Hangs
|
||||
=============
|
||||
|
||||
There is a feature of Firefox that will crash Firefox if it stops processing
|
||||
messages after a certain period of time. This feature doesn't work well and is
|
||||
disabled by default. See ``xpcom/threads/HangMonitor.cpp``. Hang crashes
|
||||
are annotated with ``Hang=1``.
|
||||
|
||||
about:crashes
|
||||
=============
|
||||
|
||||
If the crash reporter subsystem is enabled, the *about:crashes*
|
||||
page will be registered with the application. This page provides
|
||||
information about previous and submitted crashes.
|
||||
|
||||
It is also possible to submit crashes from *about:crashes*.
|
||||
82
toolkit/crashreporter/google-breakpad/.gitignore
vendored
82
toolkit/crashreporter/google-breakpad/.gitignore
vendored
|
|
@ -1,82 +0,0 @@
|
|||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Ignore other VCSs.
|
||||
.svn/
|
||||
|
||||
# Ignore common compiled artifacts.
|
||||
*~
|
||||
*.dwo
|
||||
*.o
|
||||
lib*.a
|
||||
/breakpad.pc
|
||||
/breakpad-client.pc
|
||||
/src/client/linux/linux_client_unittest_shlib
|
||||
/src/client/linux/linux_dumper_unittest_helper
|
||||
/src/processor/microdump_stackwalk
|
||||
/src/processor/minidump_dump
|
||||
/src/processor/minidump_stackwalk
|
||||
/src/tools/linux/core2md/core2md
|
||||
/src/tools/linux/dump_syms/dump_syms
|
||||
/src/tools/linux/md2core/minidump-2-core
|
||||
/src/tools/linux/symupload/minidump_upload
|
||||
/src/tools/linux/symupload/sym_upload
|
||||
/src/tools/mac/dump_syms/dump_syms
|
||||
|
||||
# Ignore autotools generated artifacts.
|
||||
.deps
|
||||
.dirstamp
|
||||
autom4te.cache/
|
||||
/config.cache
|
||||
config.h
|
||||
/config.log
|
||||
/config.status
|
||||
/Makefile
|
||||
stamp-h1
|
||||
|
||||
# Ignore GYP generated Visual Studio artifacts.
|
||||
*.filters
|
||||
*.sdf
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*.vcxproj
|
||||
|
||||
# Ignore GYP generated Makefiles
|
||||
src/Makefile
|
||||
*.Makefile
|
||||
*.target.mk
|
||||
|
||||
# Ignore compiled Python files.
|
||||
*.pyc
|
||||
|
||||
# Ignore directories gclient syncs.
|
||||
src/testing
|
||||
src/third_party/glog
|
||||
src/third_party/protobuf
|
||||
src/tools/gyp
|
||||
|
|
@ -1 +0,0 @@
|
|||
opensource@google.com
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
# Copyright 2010 Google Inc. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# This is used to mimic the svn:externals mechanism for gclient (both Git and
|
||||
# SVN) based checkouts of Breakpad. As such, its use is entirely optional. If
|
||||
# using a manually managed SVN checkout as opposed to a gclient managed checkout
|
||||
# you can still use the hooks mechanism for generating project files by calling
|
||||
# 'gclient runhooks' rather than 'gclient sync'.
|
||||
|
||||
deps = {
|
||||
# Logging code.
|
||||
"src/src/third_party/glog":
|
||||
"https://github.com/google/glog.git" +
|
||||
"@v0.3.4",
|
||||
|
||||
# Testing libraries and utilities.
|
||||
"src/src/testing":
|
||||
"https://github.com/google/googlemock.git" +
|
||||
"@release-1.7.0",
|
||||
"src/src/testing/gtest":
|
||||
"https://github.com/google/googletest.git" +
|
||||
"@release-1.7.0",
|
||||
|
||||
# Protobuf.
|
||||
"src/src/third_party/protobuf/protobuf":
|
||||
"https://github.com/google/protobuf.git" +
|
||||
"@cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac",
|
||||
|
||||
# GYP project generator.
|
||||
"src/src/tools/gyp":
|
||||
"https://chromium.googlesource.com/external/gyp/" +
|
||||
"@e8ab0833a42691cd2184bd4c45d779e43821d3e0",
|
||||
|
||||
# Linux syscall support.
|
||||
"src/src/third_party/lss":
|
||||
"https://chromium.googlesource.com/linux-syscall-support/" +
|
||||
"@3f6478ac95edf86cd3da300c2c0d34a438f5dbeb",
|
||||
}
|
||||
|
||||
hooks = [
|
||||
{
|
||||
# TODO(chrisha): Fix the GYP files so that they work without
|
||||
# --no-circular-check.
|
||||
"pattern": ".",
|
||||
"action": ["python",
|
||||
"src/src/tools/gyp/gyp_main.py",
|
||||
"--no-circular-check",
|
||||
"src/src/client/windows/breakpad_client.gyp"],
|
||||
},
|
||||
]
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue