Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
Roy Tam 2019-04-04 20:32:53 +08:00
commit 51fa1b8bdb
983 changed files with 5371 additions and 280531 deletions

View file

@ -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

View file

@ -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
};

View file

@ -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);
////////////////////////////////////////////////////////////////////////////////

View file

@ -32,7 +32,7 @@
// nsIAccessible::name
var applicationName = "";
if (LINUX || SOLARIS) {
if (LINUX) {
applicationName = appInfo.name;
} else {
try {

View file

@ -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);

View file

@ -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: [ ] },

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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',

View file

@ -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))) \

View file

@ -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

View file

@ -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.

View file

@ -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 \

View file

@ -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"

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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()
{

View file

@ -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";

View file

@ -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;

View file

@ -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

View file

@ -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"

View file

@ -70,7 +70,6 @@ IPDL_SOURCES = [
LOCAL_INCLUDES += [
'/dom/ipc',
'/toolkit/crashreporter',
'/xpcom/threads',
]

View file

@ -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

View file

@ -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());

View file

@ -23,8 +23,6 @@
#include "prenv.h"
#include "nsXPCOMPrivate.h"
#include "nsExceptionHandler.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIFile.h"
#include "nsPrintfCString.h"

View file

@ -177,7 +177,6 @@ IPDL_SOURCES = [
LOCAL_INCLUDES += [
'/dom/ipc',
'/toolkit/crashreporter',
'/toolkit/xre',
'/xpcom/threads',
]

View file

@ -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;

View file

@ -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 $^ $@

View file

@ -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;

View file

@ -20,10 +20,6 @@
#include <float.h>
#endif
#if defined(SOLARIS)
#include <ieeefp.h>
#endif
#ifdef HAVE_SSIZE_T
#include <sys/types.h>
#endif

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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()

View file

@ -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++ */

View file

@ -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']

View file

@ -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);
}

View file

@ -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])

View file

@ -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();
}

View file

@ -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;

View file

@ -67,9 +67,6 @@
#define alloca _alloca
#endif
#endif
#ifdef SOLARIS
#include <alloca.h>
#endif
using std::max;
using std::min;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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'):

View file

@ -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

View file

@ -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
//

View file

@ -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 ========================================================

View file

@ -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",

View file

@ -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();

View file

@ -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: []
};

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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)));
}

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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__

View file

@ -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,
&gtk_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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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>

View file

@ -1,2 +0,0 @@
APPL????

View file

@ -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";

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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')

View file

@ -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

View file

@ -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";
});

View file

@ -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>

View file

@ -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

View file

@ -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*.

View file

@ -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

View file

@ -1 +0,0 @@
opensource@google.com

View file

@ -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