Remove crashreporter toolkit files.

This commit is contained in:
Fedor 2019-05-20 09:02:01 +03:00
parent b2628357b3
commit e26c5e1e50
886 changed files with 0 additions and 273247 deletions

View File

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

View File

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

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,37 +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}"/>
</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"],
},
]

View File

@ -1 +0,0 @@
704f41ec901c419f8c321742114b415e6f5ceacc

View File

@ -1,370 +0,0 @@
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf limitation. Until the limitation is lifted, you can use
this workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View File

@ -1,50 +0,0 @@
Copyright (c) 2006, 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.
--------------------------------------------------------------------
Copyright 2001-2004 Unicode, Inc.
Disclaimer
This source code is provided as is by Unicode, Inc. No claims are
made as to fitness for any particular purpose. No warranties of any
kind are expressed or implied. The recipient agrees to determine
applicability of information provided. If this file has been
purchased on magnetic or optical media from Unicode, Inc., the
sole remedy for any claim will be exchange of defective media
within 90 days of receipt.
Limitations on Rights to Redistribute This Code
Unicode, Inc. hereby grants the right to freely use the information
supplied in this file in the creation of products supporting the
Unicode Standard, and to make copies of this file in any form
for internal or external distribution as long as this notice
remains attached.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,139 +0,0 @@
Google Breakpad for Android
===========================
This document explains how to use the Google Breakpad client library
on Android, and later generate valid stack traces from the minidumps
it generates.
This release supports ARM, x86 and MIPS based Android systems.
This release requires NDK release r11c or higher.
I. Building the client library:
===============================
The Android client is built as a static library that you can
link into your own Android native code. There are two ways to
build it:
I.1. Building with ndk-build:
-----------------------------
If you're using the ndk-build build system, you can follow
these simple steps:
1/ Include android/google_breakpad/Android.mk from your own
project's Android.mk
This can be done either directly, or using ndk-build's
import-module feature.
2/ Link the library to one of your modules by using:
LOCAL_STATIC_LIBRARIES += breakpad_client
NOTE: The client library requires a C++ STL implementation,
which you can select with APP_STL in your Application.mk
It has been tested succesfully with both STLport and GNU libstdc++
I.2. Building with a standalone Android toolchain:
--------------------------------------------------
All you need to do is configure your build with the right 'host'
value, and disable the processor and tools, as in:
$GOOGLE_BREAKPAD_PATH/configure --host=arm-linux-androideabi \
--disable-processor \
--disable-tools
make -j4
The library will be under src/client/linux/libbreakpad_client.a
You can also use 'make check' to run the test suite on a connected
Android device. This requires the Android 'adb' tool to be in your
path.
II. Using the client library in Android:
========================================
The usage instructions are very similar to the Linux ones that are
found at https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/linux_starter_guide.md
1/ You need to include "client/linux/handler/exception_handler.h" from a C++
source file.
2/ If you're not using ndk-build, you also need to:
- add the following to your compiler include search paths:
$GOOGLE_BREAKPAD_PATH/src
$GOOGLE_BREAKPAD_PATH/src/common/android/include
- add -llog to your linker flags
Note that ndk-build does that for your automatically.
3/ Keep in mind that there is no /tmp directory on Android.
If you use the library from a regular Android applications, specify a
path under your app-specific storage directory. An alternative is to
store them on the SDCard, but this requires a specific permission.
For a concrete example, see the sample test application under
android/sample_app. See its README for more information.
III. Getting a stack trace on the host:
=======================================
This process is similar to other platforms, but here's a quick example:
1/ Retrieve the minidumps on your development machine.
2/ Dump the symbols for your native libraries with the 'dump_syms' tool.
This first requires building the host version of Google Breakpad, then
calling:
dump_syms $PROJECT_PATH/obj/local/$ABI/libfoo.so > libfoo.so.sym
3/ Create the symbol directory hierarchy.
The first line of the generated libfoo.so.sym will have a "MODULE"
entry that carries a hexadecimal version number, e.g.:
MODULE Linux arm D51B4A5504974FA6ECC1869CAEE3603B0 test_google_breakpad
Note: The second field could be either 'Linux' or 'Android'.
Extract the version number, and a 'symbol' directory, for example:
$PROJECT_PATH/symbols/libfoo.so/$VERSION/
Copy/Move your libfoo.sym file there.
4/ Invoke minidump_stackwalk to create the stack trace:
minidump_stackwalk $MINIDUMP_FILE $PROJECT_PATH/symbols
Note that various helper scripts can be found on the web to automate these
steps.
IV. Verifying the Android build library:
========================================
If you modify Google Breakpad and want to check that it still works correctly
on Android, please run the android/run-checks.sh script which will do all
necessary verifications for you. This includes:
- Rebuilding the full host binaries.
- Rebuilding the full Android binaries with configure/make.
- Rebuilding the client library unit tests, and running them on a device.
- Rebuilding the client library with ndk-build.
- Building, installing and running a test crasher program on a device.
- Extracting the corresponding minidump, dumping the test program symbols
and generating a stack trace.
- Checking the generated stack trace for valid source locations.
For more details, please run:
android/run-checks.sh --help-all

View File

@ -1,82 +0,0 @@
# Breakpad
Breakpad is a set of client and server components which implement a
crash-reporting system.
* [Homepage](https://chromium.googlesource.com/breakpad/breakpad/)
* [Documentation](https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/)
* [Bugs](https://bugs.chromium.org/p/google-breakpad/)
* Discussion/Questions: [google-breakpad-discuss@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-discuss)
* Developer/Reviews: [google-breakpad-dev@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-dev)
* Tests: [![Build Status](https://travis-ci.org/google/breakpad.svg?branch=master)](https://travis-ci.org/google/breakpad)
* Coverage [![Coverity Status](https://scan.coverity.com/projects/9215/badge.svg)](https://scan.coverity.com/projects/google-breakpad)
## Getting started (from master)
1. First, [download depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools)
and ensure that theyre in your `PATH`.
2. Create a new directory for checking out the source code (it must be named
breakpad).
```sh
mkdir breakpad && cd breakpad
```
3. Run the `fetch` tool from depot_tools to download all the source repos.
```sh
fetch breakpad
cd src
```
4. Build the source.
```sh
./configure && make
```
You can also cd to another directory and run configure from there to build
outside the source tree.
This will build the processor tools (`src/processor/minidump_stackwalk`,
`src/processor/minidump_dump`, etc), and when building on Linux it will
also build the client libraries and some tools
(`src/tools/linux/dump_syms/dump_syms`,
`src/tools/linux/md2core/minidump-2-core`, etc).
5. Optionally, run tests.
```sh
make check
```
6. Optionally, install the built libraries
```sh
make install
```
If you need to reconfigure your build be sure to run `make distclean` first.
To update an existing checkout to a newer revision, you can
`git pull` as usual, but then you should run `gclient sync` to ensure that the
dependent repos are up-to-date.
## To request change review
1. Follow the steps above to get the source and build it.
2. Make changes. Build and test your changes.
For core code like processor use methods above.
For linux/mac/windows, there are test targets in each project file.
3. Commit your changes to your local repo and upload them to the server.
http://dev.chromium.org/developers/contributing-code
e.g. `git commit ... && git cl upload ...`
You will be prompted for credential and a description.
4. At https://chromium-review.googlesource.com/ you'll find your issue listed;
click on it, then “Add reviewer”, and enter in the code reviewer. Depending
on your settings, you may not see an email, but the reviewer has been
notified with google-breakpad-dev@googlegroups.com always CCd.

File diff suppressed because it is too large Load Diff

View File

@ -1,372 +0,0 @@
# Copyright (c) 2012 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.
# Collection of common shell functions for 'run-checks.sh' et 'test-shell.sh'
# All internal variables and functions use an underscore as a prefix
# (e.g. _VERBOSE, _ALL_CLEANUPS, etc..).
# Sanitize the environment
export LANG=C
export LC_ALL=C
if [ "$BASH_VERSION" ]; then
set -o posix
fi
# Utility functions
_ALL_CLEANUPS=
# Register a function to be called when the script exits, even in case of
# Ctrl-C, logout, etc.
# $1: function name.
atexit () {
if [ -z "$_ALL_CLEANUPS" ]; then
_ALL_CLEANUPS=$1
# Ensure a clean exit when the script is:
# - Exiting normally (EXIT)
# - Interrupted by Ctrl-C (INT)
# - Interrupted by log out (HUP)
# - Being asked to quit nicely (TERM)
# - Being asked to quit and dump core (QUIT)
trap "_exit_cleanups \$?" EXIT INT HUP QUIT TERM
else
_ALL_CLEANUPS="$_ALL_CLEANUPS $1"
fi
}
# Called on exit if at least one function was registered with atexit
# $1: final exit status code
_exit_cleanups () {
local CLEANUP CLEANUPS
# Ignore calls to atexit during cleanups
CLEANUPS=$_ALL_CLEANUPS
_ALL_CLEANUPS=
for CLEANUP in $CLEANUPS; do
($CLEANUP)
done
exit "$@"
}
# Dump a panic message then exit.
# $1+: message
panic () {
echo "ERROR: $@" >&2
exit 1
}
# If the previous command failed, dump a panic message then exit.
# $1+: message.
fail_panic () {
if [ $? != 0 ]; then
panic "$@"
fi;
}
_VERBOSE=0
# Increase verbosity for dump/log/run/run2 functions
increase_verbosity () {
_VERBOSE=$(( $_VERBOSE + 1 ))
}
# Decrease verbosity
decrease_verbosity () {
_VERBOSE=$(( $_VERBOSE - 1 ))
}
# Returns success iff verbosity level is higher than a specific value
# $1: verbosity level
verbosity_is_higher_than () {
[ "$_VERBOSE" -gt "$1" ]
}
# Returns success iff verbosity level is lower than a specific value
# $1: verbosity level
verbosity_is_lower_than () {
[ "$_VERBOSE" -le "$1" ]
}
# Dump message to stdout, unless verbosity is < 0, i.e. --quiet was called
# $1+: message
dump () {
if [ "$_VERBOSE" -ge 0 ]; then
printf "%s\n" "$*"
fi
}
# If --verbose was used, dump a message to stdout.
# $1+: message
log () {
if [ "$_VERBOSE" -ge 1 ]; then
printf "%s\n" "$*"
fi
}
_RUN_LOG=
# Set a run log file that can be used to collect the output of commands that
# are not displayed.
set_run_log () {
_RUN_LOG=$1
}
# Run a command. Output depends on $_VERBOSE:
# $_VERBOSE <= 0: Run command, store output into the run log
# $_VERBOSE >= 1: Dump command, run it, output goest to stdout
# Note: Ideally, the command's output would go to the run log for $_VERBOSE >= 1
# but the 'tee' tool doesn't preserve the status code of its input pipe
# in case of error.
run () {
local LOGILE
if [ "$_RUN_LOG" ]; then
LOGFILE=$_RUN_LOG
else
LOGFILE=/dev/null
fi
if [ "$_VERBOSE" -ge 1 ]; then
echo "COMMAND: $@"
"$@"
else
"$@" >>$LOGFILE 2>&1
fi
}
# Same as run(), but only dump command output for $_VERBOSE >= 2
run2 () {
local LOGILE
if [ "$_RUN_LOG" ]; then
LOGFILE=$_RUN_LOG
else
LOGFILE=/dev/null
fi
if [ "$_VERBOSE" -ge 1 ]; then
echo "COMMAND: $@"
fi
if [ "$_VERBOSE" -ge 2 ]; then
"$@"
else
"$@" >>$LOGFILE 2>&1
fi
}
# Extract number of cores to speed up the builds
# Out: number of CPU cores
get_core_count () {
case $(uname -s) in
Linux)
grep -c -e '^processor' /proc/cpuinfo
;;
Darwin)
sysctl -n hw.ncpu
;;
CYGWIN*|*_NT-*)
echo $NUMBER_OF_PROCESSORS
;;
*)
echo 1
;;
esac
}
# Check for the Android ADB program.
#
# On success, return nothing, but updates internal variables so later calls to
# adb_shell, adb_push, etc.. will work. You can get the path to the ADB program
# with adb_get_program if needed.
#
# On failure, returns 1, and updates the internal adb error message, which can
# be retrieved with adb_get_error.
#
# $1: optional ADB program path.
# Return: success or failure.
_ADB=
_ADB_STATUS=
_ADB_ERROR=
adb_check () {
# First, try to find the executable in the path, or the SDK install dir.
_ADB=$1
if [ -z "$_ADB" ]; then
_ADB=$(which adb 2>/dev/null)
if [ -z "$_ADB" -a "$ANDROID_SDK_ROOT" ]; then
_ADB=$ANDROID_SDK_ROOT/platform-tools/adb
if [ ! -f "$_ADB" ]; then
_ADB=
fi
fi
if [ -z "$_ADB" ]; then
_ADB_STATUS=1
_ADB_ERROR="The Android 'adb' tool is not in your path."
return 1
fi
fi
log "Found ADB program: $_ADB"
# Check that it works correctly
local ADB_VERSION
ADB_VERSION=$("$_ADB" version 2>/dev/null)
case $ADB_VERSION in
"Android Debug Bridge "*) # Pass
log "Found ADB version: $ADB_VERSION"
;;
*) # Fail
_ADB_ERROR="Your ADB binary reports a bad version ($ADB_VERSION): $_ADB"
_ADB_STATUS=1
return 1
esac
_ADB_STATUS=0
return 0
}
# Return the path to the Android ADB program, if correctly detected.
# On failure, return the empty string.
# Out: ADB program path (or empty on failure)
# Return: success or failure.
adb_get_program () {
# Return cached value as soon as possible.
if [ -z "$_ADB_STATUS" ]; then
adb_check $1
fi
echo "$_ADB"
return $_ADB_STATUS
}
# Return the error corresponding to the last ADB function failure.
adb_get_error () {
echo "$_ADB_ERROR"
}
# Check that there is one device connected through ADB.
# In case of failure, use adb_get_error to know why this failed.
# $1: Optional adb program path
# Return: success or failure.
_ADB_DEVICE=
_ADB_DEVICE_STATUS=
adb_check_device () {
if [ "$_ADB_DEVICE_STATUS" ]; then
return $_ADB_DEVICE_STATUS
fi
# Check for ADB.
if ! adb_check $1; then
_ADB_DEVICE_STATUS=$_ADB_STATUS
return 1
fi
local ADB_DEVICES NUM_DEVICES FINGERPRINT
# Count the number of connected devices.
ADB_DEVICES=$("$_ADB" devices 2>/dev/null | awk '$2 == "device" { print $1; }')
NUM_DEVICES=$(echo "$ADB_DEVICES" | wc -l)
case $NUM_DEVICES in
0)
_ADB_ERROR="No Android device connected. Please connect one to your machine."
_ADB_DEVICE_STATUS=1
return 1
;;
1) # Pass
# Ensure the same device will be called in later adb_shell calls.
export ANDROID_SERIAL=$ADB_DEVICES
;;
*) # 2 or more devices.
if [ "$ANDROID_SERIAL" ]; then
ADB_DEVICES=$ANDROID_SERIAL
NUM_DEVICES=1
else
_ADB_ERROR="More than one Android device connected. \
Please define ANDROID_SERIAL in your environment"
_ADB_DEVICE_STATUS=1
return 1
fi
;;
esac
_ADB_DEVICE_STATUS=0
_ADB_DEVICE=$ADB_DEVICES
FINGERPRINT=$(adb_shell getprop ro.build.fingerprint)
log "Using ADB device: $ANDROID_SERIAL ($FINGERPRINT)"
return 0
}
# The 'adb shell' command is pretty hopeless, try to make sense of it by:
# 1/ Removing trailing \r from line endings.
# 2/ Ensuring the function returns the command's status code.
#
# $1+: Command
# Out: command output (stdout + stderr combined)
# Return: command exit status
adb_shell () {
local RET ADB_LOG
# Check for ADB device.
adb_check_device || return 1
ADB_LOG=$(mktemp "${TMPDIR:-/tmp}/adb-XXXXXXXX")
"$_ADB" shell "$@" ";" echo \$? > "$ADB_LOG" 2>&1
sed -i -e 's![[:cntrl:]]!!g' "$ADB_LOG" # Remove \r.
RET=$(sed -e '$!d' "$ADB_LOG") # Last line contains status code.
sed -e '$d' "$ADB_LOG" # Print everything except last line.
rm -f "$ADB_LOG"
return $RET
}
# Push a file to a device.
# $1: source file path
# $2: device target file path
# Return: success or failure.
adb_push () {
adb_check_device || return 1
run "$_ADB" push "$1" "$2"
}
# Pull a file from a device
# $1: device file path
# $2: target host file path
# Return: success or failure.
adb_pull () {
adb_check_device || return 1
run "$_ADB" pull "$1" "$2"
}
# Same as adb_push, but will panic if the operations didn't succeed.
adb_install () {
adb_push "$@"
fail_panic "Failed to install $1 to the Android device at $2"
}

View File

@ -1,103 +0,0 @@
# Copyright (c) 2012, 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.
# ndk-build module definition for the Google Breakpad client library
#
# To use this file, do the following:
#
# 1/ Include this file from your own Android.mk, either directly
# or with through the NDK's import-module function.
#
# 2/ Use the client static library in your project with:
#
# LOCAL_STATIC_LIBRARIES += breakpad_client
#
# 3/ In your source code, include "src/client/linux/exception_handler.h"
# and use the Linux instructions to use it.
#
# This module works with either the STLport or GNU libstdc++, but you need
# to select one in your Application.mk
#
# The top Google Breakpad directory.
# We assume this Android.mk to be under 'android/google_breakpad'
LOCAL_PATH := $(call my-dir)/../..
# Defube the client library module, as a simple static library that
# exports the right include path / linker flags to its users.
include $(CLEAR_VARS)
LOCAL_MODULE := breakpad_client
LOCAL_CPP_EXTENSION := .cc
# Breakpad uses inline ARM assembly that requires the library
# to be built in ARM mode. Otherwise, the build will fail with
# cryptic assembler messages like:
# Compile++ thumb : google_breakpad_client <= crash_generation_client.cc
# /tmp/cc8aMSoD.s: Assembler messages:
# /tmp/cc8aMSoD.s:132: Error: invalid immediate: 288 is out of range
# /tmp/cc8aMSoD.s:244: Error: invalid immediate: 296 is out of range
LOCAL_ARM_MODE := arm
# List of client source files, directly taken from Makefile.am
LOCAL_SRC_FILES := \
src/client/linux/crash_generation/crash_generation_client.cc \
src/client/linux/dump_writer_common/thread_info.cc \
src/client/linux/dump_writer_common/ucontext_reader.cc \
src/client/linux/handler/exception_handler.cc \
src/client/linux/handler/minidump_descriptor.cc \
src/client/linux/log/log.cc \
src/client/linux/microdump_writer/microdump_writer.cc \
src/client/linux/minidump_writer/linux_dumper.cc \
src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
src/client/linux/minidump_writer/minidump_writer.cc \
src/client/minidump_file_writer.cc \
src/common/android/breakpad_getcontext.S \
src/common/convert_UTF.c \
src/common/md5.cc \
src/common/string_conversion.cc \
src/common/linux/elfutils.cc \
src/common/linux/file_id.cc \
src/common/linux/guid_creator.cc \
src/common/linux/linux_libc_support.cc \
src/common/linux/memory_mapped_file.cc \
src/common/linux/safe_readlink.cc
LOCAL_C_INCLUDES := $(LOCAL_PATH)/src/common/android/include \
$(LOCAL_PATH)/src
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)
# Done.

View File

@ -1,555 +0,0 @@
#!/bin/sh
# Copyright (c) 2012 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.
# Sanitize the environment
export LANG=C
export LC_ALL=C
if [ "$BASH_VERSION" ]; then
set -o posix
fi
PROGDIR=$(dirname "$0")
PROGDIR=$(cd "$PROGDIR" && pwd)
PROGNAME=$(basename "$0")
. $PROGDIR/common-functions.sh
DEFAULT_ABI="armeabi"
VALID_ABIS="armeabi armeabi-v7a x86 mips"
ABI=
ADB=
ALL_TESTS=
ENABLE_M32=
HELP=
HELP_ALL=
NDK_DIR=
NO_CLEANUP=
NO_DEVICE=
NUM_JOBS=$(get_core_count)
TMPDIR=
for opt do
# The following extracts the value if the option is like --name=<value>.
optarg=$(expr -- $opt : '^--[^=]*=\(.*\)$')
case $opt in
--abi=*) ABI=$optarg;;
--adb=*) ADB=$optarg;;
--all-tests) ALL_TESTS=true;;
--enable-m32) ENABLE_M32=true;;
--help|-h|-?) HELP=TRUE;;
--help-all) HELP_ALL=true;;
--jobs=*) NUM_JOBS=$optarg;;
--ndk-dir=*) NDK_DIR=$optarg;;
--tmp-dir=*) TMPDIR=$optarg;;
--no-cleanup) NO_CLEANUP=true;;
--no-device) NO_DEVICE=true;;
--quiet) decrease_verbosity;;
--verbose) increase_verbosity;;
-*) panic "Invalid option '$opt', see --help for details.";;
*) panic "This script doesn't take any parameters. See --help for details."
;;
esac
done
if [ "$HELP" -o "$HELP_ALL" ]; then
echo "\
Usage: $PROGNAME [options]
This script is used to check that your Google Breakpad source tree can
be properly built for Android, and that the client library and host tools
work properly together.
"
if [ "$HELP_ALL" ]; then
echo "\
In more details, this script will:
- Rebuild the host version of Google Breakpad in a temporary
directory (with the Auto-tools based build system).
- Rebuild the Android client library with the Google Breakpad build
system (using autotools/configure). This requires that you define
ANDROID_NDK_ROOT in your environment to point to a valid Android NDK
installation directory, or use the --ndk-dir=<path> option.
- Rebuild the Android client library and a test crashing program with the
Android NDK build system (ndk-build).
- Require an Android device connected to your machine, and the 'adb'
tool in your path. They are used to:
- Install and run a test crashing program.
- Extract the corresponding minidump from the device.
- Dump the symbols from the test program on the host with 'dump_syms'
- Generate a stack trace with 'minidump_stackwalk'
- Check the stack trace content for valid source file locations.
You can however skip this requirement and only test the builds by using
the --no-device flag.
By default, all generated files will be created in a temporary directory
that is removed when the script completion. If you want to inspect the
files, use the --no-cleanup option.
Finally, use --verbose to increase the verbosity level, this will help
you see which exact commands are being issues and their result. Use the
flag twice for even more output. Use --quiet to decrease verbosity
instead and run the script silently.
If you have a device connected, the script will probe it to determine
its primary CPU ABI, and build the test program for it. You can however
use the --abi=<name> option to override this (this can be useful to check
the secondary ABI, e.g. using --abi=armeabi to check that such a program
works correctly on an ARMv7-A device).
If you don't have a device connected, the test program will be built (but
not run) with the default '$DEFAULT_ABI' ABI. Again, you can use
--abi=<name> to override this. Valid ABI names are:
$VALID_ABIS
The script will only run the client library unit test on the device
by default. You can use --all-tests to also build and run the unit
tests for the Breakpad tools and processor, but be warned that this
adds several minutes of testing time. --all-tests will also run the
host unit tests suite.
"
fi # HELP_ALL
echo "\
Valid options:
--help|-h|-? Display this message.
--help-all Display extended help.
--enable-m32 Build 32-bit version of host tools.
--abi=<name> Specify target CPU ABI [auto-detected].
--jobs=<count> Run <count> build tasks in parallel [$NUM_JOBS].
--ndk-dir=<path> Specify NDK installation directory.
--tmp-dir=<path> Specify temporary directory (will be wiped-out).
--adb=<path> Specify adb program path.
--no-cleanup Don't remove temporary directory after completion.
--no-device Do not try to detect devices, nor run crash test.
--all-tests Run all unit tests (i.e. tools and processor ones too).
--verbose Increase verbosity.
--quiet Decrease verbosity."
exit 0
fi
TESTAPP_DIR=$PROGDIR/sample_app
# Select NDK install directory.
if [ -z "$NDK_DIR" ]; then
if [ -z "$ANDROID_NDK_ROOT" ]; then
panic "Please define ANDROID_NDK_ROOT in your environment, or use \
--ndk-dir=<path>."
fi
NDK_DIR="$ANDROID_NDK_ROOT"
log "Found NDK directory: $NDK_DIR"
else
log "Using NDK directory: $NDK_DIR"
fi
# Small sanity check.
NDK_BUILD="$NDK_DIR/ndk-build"
if [ ! -f "$NDK_BUILD" ]; then
panic "Your NDK directory is not valid (missing ndk-build): $NDK_DIR"
fi
# Ensure the temporary directory is deleted on exit, except if the --no-cleanup
# option is used.
clean_tmpdir () {
if [ "$TMPDIR" ]; then
if [ -z "$NO_CLEANUP" ]; then
log "Cleaning up: $TMPDIR"
rm -rf "$TMPDIR"
else
dump "Temporary directory contents preserved: $TMPDIR"
fi
fi
exit "$@"
}
atexit clean_tmpdir
# If --tmp-dir=<path> is not used, create a temporary directory.
# Otherwise, start by cleaning up the user-provided path.
if [ -z "$TMPDIR" ]; then
TMPDIR=$(mktemp -d /tmp/$PROGNAME.XXXXXXXX)
fail_panic "Can't create temporary directory!"
log "Using temporary directory: $TMPDIR"
else
if [ ! -d "$TMPDIR" ]; then
mkdir -p "$TMPDIR"
fail_panic "Can't create temporary directory: $TMPDIR"
else
log "Cleaning up temporary directory: $TMPDIR"
rm -rf "$TMPDIR"/*
fail_panic "Cannot cleanup temporary directory!"
fi
fi
if [ -z "$NO_DEVICE" ]; then
if ! adb_check_device $ADB; then
echo "$(adb_get_error)"
echo "Use --no-device to build the code without running any tests."
exit 1
fi
fi
BUILD_LOG="$TMPDIR/build.log"
RUN_LOG="$TMPDIR/run.log"
CRASH_LOG="$TMPDIR/crash.log"
set_run_log "$RUN_LOG"
TMPHOST="$TMPDIR/host-local"
cd "$TMPDIR"
# Build host version of the tools
dump "Building host binaries."
CONFIGURE_FLAGS=
if [ "$ENABLE_M32" ]; then
CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-m32"
fi
(
run mkdir "$TMPDIR/build-host" &&
run cd "$TMPDIR/build-host" &&
run2 "$PROGDIR/../configure" --prefix="$TMPHOST" $CONFIGURE_FLAGS &&
run2 make -j$NUM_JOBS install
)
fail_panic "Can't build host binaries!"
if [ "$ALL_TESTS" ]; then
dump "Running host unit tests."
(
run cd "$TMPDIR/build-host" &&
run2 make -j$NUM_JOBS check
)
fail_panic "Host unit tests failed!!"
fi
TMPBIN=$TMPHOST/bin
# Generate a stand-alone NDK toolchain
# Extract CPU ABI and architecture from device, if any.
if adb_check_device; then
DEVICE_ABI=$(adb_shell getprop ro.product.cpu.abi)
DEVICE_ABI2=$(adb_shell getprop ro.product.cpu.abi2)
if [ -z "$DEVICE_ABI" ]; then
panic "Can't extract ABI from connected device!"
fi
if [ "$DEVICE_ABI2" ]; then
dump "Found device ABIs: $DEVICE_ABI $DEVICE_ABI2"
else
dump "Found device ABI: $DEVICE_ABI"
DEVICE_ABI2=$DEVICE_ABI
fi
# If --abi=<name> is used, check that the device supports it.
if [ "$ABI" -a "$DEVICE_ABI" != "$ABI" -a "$DEVICE_ABI2" != "$ABI" ]; then
dump "ERROR: Device ABI(s) do not match --abi command-line value ($ABI)!"
panic "Please use --no-device to skip device tests."
fi
if [ -z "$ABI" ]; then
ABI=$DEVICE_ABI
dump "Using CPU ABI: $ABI (device)"
else
dump "Using CPU ABI: $ABI (command-line)"
fi
else
if [ -z "$ABI" ]; then
# No device connected, choose default ABI
ABI=$DEFAULT_ABI
dump "Using CPU ABI: $ABI (default)"
else
dump "Using CPU ABI: $ABI (command-line)"
fi
fi
# Check the ABI value
VALID=
for VALID_ABI in $VALID_ABIS; do
if [ "$ABI" = "$VALID_ABI" ]; then
VALID=true
break
fi
done
if [ -z "$VALID" ]; then
panic "Unknown CPU ABI '$ABI'. Valid values are: $VALID_ABIS"
fi
# Extract architecture name from ABI
case $ABI in
armeabi*) ARCH=arm;;
*) ARCH=$ABI;;
esac
# Extract GNU configuration name
case $ARCH in
arm)
GNU_CONFIG=arm-linux-androideabi
;;
x86)
GNU_CONFIG=i686-linux-android
;;
mips)
GNU_CONFIG=mipsel-linux-android
;;
*)
GNU_CONFIG="$ARCH-linux-android"
;;
esac
# Generate standalone NDK toolchain installation
NDK_STANDALONE="$TMPDIR/ndk-$ARCH-toolchain"
echo "Generating NDK standalone toolchain installation"
mkdir -p "$NDK_STANDALONE"
# NOTE: The --platform=android-9 is required to provide <regex.h> for GTest.
run "$NDK_DIR/build/tools/make-standalone-toolchain.sh" \
--arch="$ARCH" \
--platform=android-9 \
--install-dir="$NDK_STANDALONE"
fail_panic "Can't generate standalone NDK toolchain installation!"
# Rebuild the client library, processor and tools with the auto-tools based
# build system. Even though it's not going to be used, this checks that this
# still works correctly.
echo "Building full Android binaries with configure/make"
TMPTARGET="$TMPDIR/target-local"
(
PATH="$NDK_STANDALONE/bin:$PATH"
run mkdir "$TMPTARGET" &&
run mkdir "$TMPDIR"/build-target &&
run cd "$TMPDIR"/build-target &&
run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \
--host="$GNU_CONFIG" &&
run2 make -j$NUM_JOBS install
)
fail_panic "Could not rebuild Android binaries!"
# Build and/or run unit test suite.
# If --no-device is used, only rebuild it, otherwise, run in on the
# connected device.
if [ "$NO_DEVICE" ]; then
ACTION="Building"
# This is a trick to force the Makefile to ignore running the scripts.
TESTS_ENVIRONMENT="TESTS_ENVIRONMENT=true"
else
ACTION="Running"
TESTS_ENVIRONMENT=
fi
(
PATH="$NDK_STANDALONE/bin:$PATH"
run cd "$TMPDIR"/build-target &&
# Reconfigure to only run the client unit test suite.
# This one should _never_ fail.
dump "$ACTION Android client library unit tests."
run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \
--host="$GNU_CONFIG" \
--disable-tools \
--disable-processor &&
run make -j$NUM_JOBS check $TESTS_ENVIRONMENT || exit $?
if [ "$ALL_TESTS" ]; then
dump "$ACTION Tools and processor unit tests."
# Reconfigure to run the processor and tools tests.
# Most of these fail for now, so do not worry about it.
run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \
--host="$GNU_CONFIG" &&
run make -j$NUM_JOBS check $TESTS_ENVIRONMENT
if [ $? != 0 ]; then
dump "Tools and processor unit tests failed as expected. \
Use --verbose for results."
fi
fi
)
fail_panic "Client library unit test suite failed!"
# Copy sources to temporary directory
PROJECT_DIR=$TMPDIR/project
dump "Copying test program sources to: $PROJECT_DIR"
run cp -r "$TESTAPP_DIR" "$PROJECT_DIR" &&
run rm -rf "$PROJECT_DIR/obj" &&
run rm -rf "$PROJECT_DIR/libs"
fail_panic "Could not copy test program sources to: $PROJECT_DIR"
# Build the test program with ndk-build.
dump "Building test program with ndk-build"
export NDK_MODULE_PATH="$PROGDIR"
NDK_BUILD_FLAGS="-j$NUM_JOBS"
if verbosity_is_higher_than 1; then
NDK_BUILD_FLAGS="$NDK_BUILD_FLAGS NDK_LOG=1 V=1"
fi
run "$NDK_DIR/ndk-build" -C "$PROJECT_DIR" $NDK_BUILD_FLAGS APP_ABI=$ABI
fail_panic "Can't build test program!"
# Unless --no-device was used, stop right here if ADB isn't in the path,
# or there is no connected device.
if [ "$NO_DEVICE" ]; then
dump "Done. Please connect a device to run all tests!"
clean_exit 0
fi
# Push the program to the device.
TESTAPP=test_google_breakpad
TESTAPP_FILE="$PROJECT_DIR/libs/$ABI/test_google_breakpad"
if [ ! -f "$TESTAPP_FILE" ]; then
panic "Device requires '$ABI' binaries. None found!"
fi
# Run the program there
dump "Installing test program on device"
DEVICE_TMP=/data/local/tmp
adb_push "$TESTAPP_FILE" "$DEVICE_TMP/"
fail_panic "Cannot push test program to device!"
dump "Running test program on device"
adb_shell cd "$DEVICE_TMP" "&&" ./$TESTAPP > "$CRASH_LOG" 2>/dev/null
if [ $? = 0 ]; then
panic "Test program did *not* crash as expected!"
fi
if verbosity_is_higher_than 0; then
echo -n "Crash log: "
cat "$CRASH_LOG"
fi
# Extract minidump from device
MINIDUMP_NAME=$(awk '$1 == "Dump" && $2 == "path:" { print $3; }' "$CRASH_LOG")
MINIDUMP_NAME=$(basename "$MINIDUMP_NAME")
if [ -z "$MINIDUMP_NAME" ]; then
panic "Test program didn't write minidump properly!"
fi
dump "Extracting minidump: $MINIDUMP_NAME"
adb_pull "$DEVICE_TMP/$MINIDUMP_NAME" .
fail_panic "Can't extract minidump!"
dump "Parsing test program symbols"
if verbosity_is_higher_than 1; then
log "COMMAND: $TMPBIN/dump_syms \
$PROJECT_DIR/obj/local/$ABI/$TESTAPP >$TESTAPP.sym"
fi
"$TMPBIN/dump_syms" "$PROJECT_DIR/obj/local/$ABI/$TESTAPP" > $TESTAPP.sym
fail_panic "dump_syms doesn't work!"
VERSION=$(awk '$1 == "MODULE" { print $4; }' $TESTAPP.sym)
dump "Found module version: $VERSION"
if [ -z "$VERSION" ]; then
echo "ERROR: Can't find proper module version from symbol dump!"
head -n5 $TESTAPP.sym
clean_exit 1
fi
run mkdir -p "$TMPDIR/symbols/$TESTAPP/$VERSION"
run mv $TESTAPP.sym "$TMPDIR/symbols/$TESTAPP/$VERSION/"
dump "Generating stack trace"
# Don't use 'run' to be able to send stdout and stderr to two different files.
log "COMMAND: $TMPBIN/minidump_stackwalk $MINIDUMP_NAME symbols"
"$TMPBIN/minidump_stackwalk" $MINIDUMP_NAME \
"$TMPDIR/symbols" \
> "$BUILD_LOG" 2>>"$RUN_LOG"
fail_panic "minidump_stackwalk doesn't work!"
dump "Checking stack trace content"
if verbosity_is_higher_than 1; then
cat "$BUILD_LOG"
fi
# The generated stack trace should look like the following:
#
# Thread 0 (crashed)
# 0 test_google_breakpad!crash [test_breakpad.cpp : 17 + 0x4]
# r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c
# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000
# sp = 0xbea2cb50 lr = 0x00009025 pc = 0x00008f84
# Found by: given as instruction pointer in context
# 1 test_google_breakpad!main [test_breakpad.cpp : 25 + 0x3]
# r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c
# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000
# sp = 0xbea2cb50 pc = 0x00009025
# Found by: call frame info
# 2 libc.so + 0x164e5
# r4 = 0x00008f64 r5 = 0xbea2cc34 r6 = 0x00000001 r7 = 0xbea2cc3c
# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000
# sp = 0xbea2cc18 pc = 0x400c34e7
# Found by: call frame info
# ...
#
# The most important part for us is ensuring that the source location could
# be extracted, so look at the 'test_breakpad.cpp' references here.
#
# First, extract all the lines with test_google_breakpad! in them, and
# dump the corresponding crash location.
#
# Note that if the source location can't be extracted, the second field
# will only be 'test_google_breakpad' without the exclamation mark.
#
LOCATIONS=$(awk '$2 ~ "^test_google_breakpad!.*" { print $3; }' "$BUILD_LOG")
if [ -z "$LOCATIONS" ]; then
if verbosity_is_lower_than 1; then
cat "$BUILD_LOG"
fi
panic "No source location found in stack trace!"
fi
# Now check that they all match "[<source file>"
BAD_LOCATIONS=
for LOCATION in $LOCATIONS; do
case $LOCATION in
# Escape the opening bracket, or some shells like Dash will not
# match them properly.
\[*.cpp|\[*.cc|\[*.h) # These are valid source locations in our executable
;;
*) # Everything else is not!
BAD_LOCATIONS="$BAD_LOCATIONS $LOCATION"
;;
esac
done
if [ "$BAD_LOCATIONS" ]; then
dump "ERROR: Generated stack trace doesn't contain valid source locations:"
cat "$BUILD_LOG"
echo "Bad locations are: $BAD_LOCATIONS"
exit 1
fi
echo "All clear! Congratulations."

View File

@ -1,32 +0,0 @@
This is a sample Android executable that can be used to test the
Google Breakpad client library on Android.
Its purpose is simply to crash and generate a minidump under /data/local/tmp.
Build instructions:
cd android/sample_app
$NDK/ndk-build
Where $NDK points to a valid Android NDK installation.
Usage instructions:
After buildind the test program, send it to a device, then run it as
the shell UID:
adb push libs/armeabi/test_google_breakpad /data/local/tmp
adb shell /data/local/tmp/test_google_breakpad
This will simply crash after dumping the name of the generated minidump
file.
See jni/test_breakpad.cpp for details.
Use 'armeabi-v7a' instead of 'armeabi' above to test the ARMv7-A version
of the binary.
Note:
If you plan to use the library in a regular Android application, store
the minidump files either to your app-specific directory, or to the SDCard
(the latter requiring a specific permission).

View File

@ -1,44 +0,0 @@
# Copyright (c) 2012, 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.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test_google_breakpad
LOCAL_SRC_FILES := test_breakpad.cpp
LOCAL_STATIC_LIBRARIES += breakpad_client
include $(BUILD_EXECUTABLE)
# If NDK_MODULE_PATH is defined, import the module, otherwise do a direct
# includes. This allows us to build in all scenarios easily.
ifneq ($(NDK_MODULE_PATH),)
$(call import-module,google_breakpad)
else
include $(LOCAL_PATH)/../../google_breakpad/Android.mk
endif

View File

@ -1,32 +0,0 @@
# Copyright (c) 2012, 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.
APP_STL := stlport_static
APP_ABI := all
APP_CXXFLAGS := -std=c++11 -D__STDC_LIMIT_MACROS

View File

@ -1,57 +0,0 @@
// Copyright (c) 2012, 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.
#include <stdio.h>
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/minidump_descriptor.h"
namespace {
bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
void* context,
bool succeeded) {
printf("Dump path: %s\n", descriptor.path());
return succeeded;
}
void Crash() {
volatile int* a = reinterpret_cast<volatile int*>(NULL);
*a = 1;
}
} // namespace
int main(int argc, char* argv[]) {
google_breakpad::MinidumpDescriptor descriptor(".");
google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback,
NULL, true, -1);
Crash();
return 0;
}

View File

@ -1,131 +0,0 @@
#! /bin/sh
# test-driver - basic testsuite driver script.
# Slightly modified for Android, see ANDROID comment below.
scriptversion=2012-06-27.10; # UTC
# Copyright (C) 2011-2013 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
# Make unconditional expansion of undefined variables an error. This
# helps a lot in preventing typo-related bugs.
set -u
usage_error ()
{
echo "$0: $*" >&2
print_usage >&2
exit 2
}
print_usage ()
{
cat <<END
Usage:
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
[--expect-failure={yes|no}] [--color-tests={yes|no}]
[--enable-hard-errors={yes|no}] [--] TEST-SCRIPT
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
END
}
# TODO: better error handling in option parsing (in particular, ensure
# TODO: $log_file, $trs_file and $test_name are defined).
test_name= # Used for reporting.
log_file= # Where to save the output of the test script.
trs_file= # Where to save the metadata of the test run.
expect_failure=no
color_tests=no
enable_hard_errors=yes
while test $# -gt 0; do
case $1 in
--help) print_usage; exit $?;;
--version) echo "test-driver $scriptversion"; exit $?;;
--test-name) test_name=$2; shift;;
--log-file) log_file=$2; shift;;
--trs-file) trs_file=$2; shift;;
--color-tests) color_tests=$2; shift;;
--expect-failure) expect_failure=$2; shift;;
--enable-hard-errors) enable_hard_errors=$2; shift;;
--) shift; break;;
-*) usage_error "invalid option: '$1'";;
esac
shift
done
if test $color_tests = yes; then
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
red='' # Red.
grn='' # Green.
lgn='' # Light green.
blu='' # Blue.
mgn='' # Magenta.
std='' # No color.
else
red= grn= lgn= blu= mgn= std=
fi
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
trap "st=129; $do_exit" 1
trap "st=130; $do_exit" 2
trap "st=141; $do_exit" 13
trap "st=143; $do_exit" 15
# Test script is run here.
# ANDROID: old line was: "$@" > $log_file 2>&1
progdir=$(dirname "$0")
"$progdir/test-shell.sh" "$@" > $log_file 2>&1
estatus=$?
if test $enable_hard_errors = no && test $estatus -eq 99; then
estatus=1
fi
case $estatus:$expect_failure in
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
0:*) col=$grn res=PASS recheck=no gcopy=no;;
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
esac
# Report outcome to console.
echo "${col}${res}${std}: $test_name"
# Register the test result, and other relevant metadata.
echo ":test-result: $res" > $trs_file
echo ":global-test-result: $res" >> $trs_file
echo ":recheck: $recheck" >> $trs_file
echo ":copy-in-global-log: $gcopy" >> $trs_file
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -1,131 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2012 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.
# A special shell wrapper that can be used to run the Google Breakpad unit
# tests on a connected Android device.
#
# This is designed to be called from the Makefile during 'make check'
#
PROGDIR=$(dirname "$0")
PROGNAME=$(basename "$0")
. $PROGDIR/common-functions.sh
# Extract test program name first.
TEST_PROGRAM=$1
shift
if [ -z "$TEST_PROGRAM" ]; then
panic "No test program/script name on the command-line!"
fi
if [ ! -f "$TEST_PROGRAM" ]; then
panic "Can't find test program/script: $TEST_PROGRAM"
fi
# Create test directory on the device
TEST_DIR=/data/local/tmp/test-google-breakpad-$$
adb_shell mkdir "$TEST_DIR" ||
panic "Can't create test directory on device: $TEST_DIR"
# Ensure that it is always removed when the script exits.
clean_test_dir () {
# Don't care about success/failure, use '$ADB shell' directly.
adb_shell rm -r "$TEST_DIR"
}
atexit clean_test_dir
TEST_PROGRAM_NAME=$(basename "$TEST_PROGRAM")
TEST_PROGRAM_DIR=$(dirname "$TEST_PROGRAM")
# Handle special case(s) here.
DATA_FILES=
case $TEST_PROGRAM_NAME in
linux_client_unittest)
# linux_client_unittest will call another executable at runtime, ensure
# it is installed too.
adb_install "$TEST_PROGRAM_DIR/linux_dumper_unittest_helper" "$TEST_DIR"
# linux_client_unittest loads a shared library at runtime, ensure it is
# installed too.
adb_install "$TEST_PROGRAM_DIR/linux_client_unittest_shlib" "$TEST_DIR"
;;
basic_source_line_resolver_unittest)
DATA_FILES="module1.out \
module2.out \
module3_bad.out \
module4_bad.out"
;;
exploitability_unittest)
DATA_FILES="scii_read_av.dmp \
ascii_read_av_block_write.dmp \
ascii_read_av_clobber_write.dmp \
ascii_read_av_conditional.dmp \
ascii_read_av_non_null.dmp \
ascii_read_av_then_jmp.dmp \
ascii_read_av_xchg_write.dmp \
ascii_write_av.dmp \
ascii_write_av_arg_to_call.dmp \
exec_av_on_stack.dmp \
null_read_av.dmp \
null_write_av.dmp \
read_av.dmp \
null_read_av.dmp \
write_av_non_null.dmp"
;;
fast_source_line_resolver_unittest)
DATA_FILES="module0.out \
module1.out \
module2.out \
module3_bad.out \
module4_bad.out"
;;
minidump_processor_unittest|minidump_unittest)
DATA_FILES="src/processor/testdata/minidump2.dmp"
;;
esac
# Install the data files, their path is relative to the environment
# variable 'srcdir'
for FILE in $DATA_FILES; do
FILEDIR=src/processor/testdata/$(dirname "$FILE")
adb_shell mkdir -p "$TEST_DIR/$FILEDIR"
adb_install "${srcdir:-.}/$FILE" "$TEST_DIR"/"$FILE"
done
# Copy test program to device
adb_install "$TEST_PROGRAM" "$TEST_DIR"
# Run it
adb_shell "cd $TEST_DIR && LD_LIBRARY_PATH=. ./$TEST_PROGRAM_NAME $@"
# Note: exiting here will call cleanup_exit which will remove the temporary
# files from the device.

View File

@ -1,347 +0,0 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,791 +0,0 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -1,501 +0,0 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2013-12-25.23; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
# Set DOITPROG to "echo" to test this script.
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

File diff suppressed because it is too large Load Diff

View File

@ -1,215 +0,0 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU programs.
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try '$0 --help' for more information"
exit 1
fi
case $1 in
--is-lightweight)
# Used by our autoconf macros to check whether the available missing
# script is modern enough.
exit 0
;;
--run)
# Back-compat with the calling convention used by older automake.
shift
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
to PROGRAM being missing or too old.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal autoconf autoheader autom4te automake makeinfo
bison yacc flex lex help2man
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
'g' are ignored when checking the name.
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: unknown '$1' option"
echo 1>&2 "Try '$0 --help' for more information"
exit 1
;;
esac
# Run the given program, remember its exit status.
"$@"; st=$?
# If it succeeded, we are done.
test $st -eq 0 && exit 0
# Also exit now if we it failed (or wasn't found), and '--version' was
# passed; such an option is passed most likely to detect whether the
# program is present and works.
case $2 in --version|--help) exit $st;; esac
# Exit code 63 means version mismatch. This often happens when the user
# tries to use an ancient version of a tool on a file that requires a
# minimum version.
if test $st -eq 63; then
msg="probably too old"
elif test $st -eq 127; then
# Program was missing.
msg="missing on your system"
else
# Program was found and executed, but failed. Give up.
exit $st
fi
perl_URL=http://www.perl.org/
flex_URL=http://flex.sourceforge.net/
gnu_software_URL=http://www.gnu.org/software
program_details ()
{
case $1 in
aclocal|automake)
echo "The '$1' program is part of the GNU Automake package:"
echo "<$gnu_software_URL/automake>"
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/autoconf>"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
autoconf|autom4te|autoheader)
echo "The '$1' program is part of the GNU Autoconf package:"
echo "<$gnu_software_URL/autoconf/>"
echo "It also requires GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
esac
}
give_advice ()
{
# Normalize program name to check for.
normalized_program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
printf '%s\n' "'$1' is $msg."
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
case $normalized_program in
autoconf*)
echo "You should only need it if you modified 'configure.ac',"
echo "or m4 files included by it."
program_details 'autoconf'
;;
autoheader*)
echo "You should only need it if you modified 'acconfig.h' or"
echo "$configure_deps."
program_details 'autoheader'
;;
automake*)
echo "You should only need it if you modified 'Makefile.am' or"
echo "$configure_deps."
program_details 'automake'
;;
aclocal*)
echo "You should only need it if you modified 'acinclude.m4' or"
echo "$configure_deps."
program_details 'aclocal'
;;
autom4te*)
echo "You might have modified some maintainer files that require"
echo "the 'autom4te' program to be rebuilt."
program_details 'autom4te'
;;
bison*|yacc*)
echo "You should only need it if you modified a '.y' file."
echo "You may want to install the GNU Bison package:"
echo "<$gnu_software_URL/bison/>"
;;
lex*|flex*)
echo "You should only need it if you modified a '.l' file."
echo "You may want to install the Fast Lexical Analyzer package:"
echo "<$flex_URL>"
;;
help2man*)
echo "You should only need it if you modified a dependency" \
"of a man page."
echo "You may want to install the GNU Help2man package:"
echo "<$gnu_software_URL/help2man/>"
;;
makeinfo*)
echo "You should only need it if you modified a '.texi' file, or"
echo "any other file indirectly affecting the aspect of the manual."
echo "You might want to install the Texinfo package:"
echo "<$gnu_software_URL/texinfo/>"
echo "The spurious makeinfo call might also be the consequence of"
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
echo "want to install GNU make:"
echo "<$gnu_software_URL/make/>"
;;
*)
echo "You might have modified some files without having the proper"
echo "tools for further handling them. Check the 'README' file, it"
echo "often tells you about the needed prerequisites for installing"
echo "this package. You may also peek at any GNU archive site, in"
echo "case some other package contains this missing '$1' program."
;;
esac
}
give_advice "$1" | sed -e '1s/^/WARNING: /' \
-e '2,$s/^/ /' >&2
# Propagate the correct exit status (expected to be 127 for a program
# not found, 63 for a program that failed due to version mismatch).
exit $st
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -1,148 +0,0 @@
#! /bin/sh
# test-driver - basic testsuite driver script.
scriptversion=2013-07-13.22; # UTC
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
# Make unconditional expansion of undefined variables an error. This
# helps a lot in preventing typo-related bugs.
set -u
usage_error ()
{
echo "$0: $*" >&2
print_usage >&2
exit 2
}
print_usage ()
{
cat <<END
Usage:
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
[--expect-failure={yes|no}] [--color-tests={yes|no}]
[--enable-hard-errors={yes|no}] [--]
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
END
}
test_name= # Used for reporting.
log_file= # Where to save the output of the test script.
trs_file= # Where to save the metadata of the test run.
expect_failure=no
color_tests=no
enable_hard_errors=yes
while test $# -gt 0; do
case $1 in
--help) print_usage; exit $?;;
--version) echo "test-driver $scriptversion"; exit $?;;
--test-name) test_name=$2; shift;;
--log-file) log_file=$2; shift;;
--trs-file) trs_file=$2; shift;;
--color-tests) color_tests=$2; shift;;
--expect-failure) expect_failure=$2; shift;;
--enable-hard-errors) enable_hard_errors=$2; shift;;
--) shift; break;;
-*) usage_error "invalid option: '$1'";;
*) break;;
esac
shift
done
missing_opts=
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
if test x"$missing_opts" != x; then
usage_error "the following mandatory options are missing:$missing_opts"
fi
if test $# -eq 0; then
usage_error "missing argument"
fi
if test $color_tests = yes; then
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
red='' # Red.
grn='' # Green.
lgn='' # Light green.
blu='' # Blue.
mgn='' # Magenta.
std='' # No color.
else
red= grn= lgn= blu= mgn= std=
fi
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
trap "st=129; $do_exit" 1
trap "st=130; $do_exit" 2
trap "st=141; $do_exit" 13
trap "st=143; $do_exit" 15
# Test script is run here.
"$@" >$log_file 2>&1
estatus=$?
if test $enable_hard_errors = no && test $estatus -eq 99; then
tweaked_estatus=1
else
tweaked_estatus=$estatus
fi
case $tweaked_estatus:$expect_failure in
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
0:*) col=$grn res=PASS recheck=no gcopy=no;;
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
esac
# Report the test outcome and exit status in the logs, so that one can
# know whether the test passed or failed simply by looking at the '.log'
# file, without the need of also peaking into the corresponding '.trs'
# file (automake bug#11814).
echo "$res $test_name (exit status: $estatus)" >>$log_file
# Report outcome to console.
echo "${col}${res}${std}: $test_name"
# Register the test result, and other relevant metadata.
echo ":test-result: $res" > $trs_file
echo ":global-test-result: $res" >> $trs_file
echo ":recheck: $recheck" >> $trs_file
echo ":copy-in-global-log: $gcopy" >> $trs_file
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -1,10 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@/@PACKAGE_NAME@
Name: google-breakpad-client
Description: An open-source multi-platform crash reporting system
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lbreakpad_client @PTHREAD_LIBS@
Cflags: -I${includedir} @PTHREAD_CFLAGS@

View File

@ -1,10 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@/@PACKAGE_NAME@
Name: google-breakpad
Description: An open-source multi-platform crash reporting system
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lbreakpad @PTHREAD_LIBS@
Cflags: -I${includedir} @PTHREAD_CFLAGS@

View File

@ -1,4 +0,0 @@
GERRIT_HOST: True
GERRIT_SQUASH_UPLOADS: True
CODE_REVIEW_SERVER: chromium-review.googlesource.com
VIEW_VC: https://chromium.googlesource.com/breakpad/breakpad/+/

File diff suppressed because it is too large Load Diff

View File

@ -1,204 +0,0 @@
# Copyright (c) 2006, 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.
AC_PREREQ(2.57)
AC_INIT(breakpad, 0.1, google-breakpad-dev@googlegroups.com)
dnl Sanity check: the argument is just a file that should exist.
AC_CONFIG_SRCDIR(README.md)
AC_CONFIG_AUX_DIR(autotools)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.11.1)
AM_CONFIG_HEADER(src/config.h)
AM_MAINTAINER_MODE
AM_PROG_AR
AM_PROG_AS
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_CPP
AC_PROG_CXX
AC_PROG_RANLIB
AM_CONDITIONAL(GCC, test "$GCC" = yes) # let the Makefile know if we're gcc
dnl This must come before all the feature tests below.
AC_ARG_ENABLE(m32,
AS_HELP_STRING([--enable-m32],
[Compile/build with -m32]
[(default is no)]),
[case "${enableval}" in
yes)
CFLAGS="${CFLAGS} -m32"
CXXFLAGS="${CXXFLAGS} -m32"
usem32=true
;;
no)
usem32=false
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --enable-m32)
;;
esac],
[usem32=false])
AC_HEADER_STDC
AC_SYS_LARGEFILE
m4_include(m4/ax_pthread.m4)
AX_PTHREAD
AC_CHECK_HEADERS([a.out.h])
m4_include(m4/ax_cxx_compile_stdcxx.m4)
AX_CXX_COMPILE_STDCXX(11, noext, mandatory)
# Only build Linux client libs when compiling for Linux
case $host in
*-*-linux* | *-android* )
LINUX_HOST=true
;;
esac
AM_CONDITIONAL(LINUX_HOST, test x$LINUX_HOST = xtrue)
# Only use Android support headers when compiling for Android
case $host in
*-android*)
ANDROID_HOST=true
;;
esac
AM_CONDITIONAL(ANDROID_HOST, test x$ANDROID_HOST = xtrue)
# Some tools (like mac ones) only support x86 currently.
case $host_cpu in
i?86|x86_64)
X86_HOST=true
;;
esac
AM_CONDITIONAL(X86_HOST, test x$X86_HOST = xtrue)
AC_ARG_ENABLE(processor,
AS_HELP_STRING([--disable-processor],
[Don't build processor library]
[(default is no)]),
[case "${enableval}" in
yes)
disable_processor=false
;;
no)
disable_processor=true
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --disable-processor)
;;
esac],
[disable_processor=false])
AM_CONDITIONAL(DISABLE_PROCESSOR, test x$disable_processor = xtrue)
AC_ARG_ENABLE(tools,
AS_HELP_STRING([--disable-tools],
[Don't build tool binaries]
[(default is no)]),
[case "${enableval}" in
yes)
disable_tools=false
;;
no)
disable_tools=true
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --disable-tools)
;;
esac],
[disable_tools=false])
AM_CONDITIONAL(DISABLE_TOOLS, test x$disable_tools = xtrue)
if test x$LINUX_HOST = xfalse -a x$disable_processor = xtrue -a x$disable_tools = xtrue; then
AC_MSG_ERROR([--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!])
fi
AC_ARG_ENABLE(system-test-libs,
AS_HELP_STRING([--enable-system-test-libs],
[Use gtest/gmock/etc... from the system instead ]
[of the local copies (default is local)]),
[case "${enableval}" in
yes)
system_test_libs=true
;;
no)
system_test_libs=false
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --enable-system-test-libs)
;;
esac],
[system_test_libs=false])
AM_CONDITIONAL(SYSTEM_TEST_LIBS, test x$system_test_libs = xtrue)
AC_ARG_VAR([GMOCK_CONFIG], [Path to gmock-config script])
AC_ARG_VAR([GMOCK_CFLAGS], [Compiler flags for gmock])
AC_ARG_VAR([GMOCK_LIBS], [Linker flags for gmock])
AC_ARG_VAR([GTEST_CONFIG], [Path to gtest-config script])
AC_ARG_VAR([GTEST_CFLAGS], [Compiler flags for gtest])
AC_ARG_VAR([GTEST_LIBS], [Linker flags for gtest])
if test x$system_test_libs = xtrue; then
AC_CHECK_TOOL([GMOCK_CONFIG], [gmock-config])
AC_CHECK_TOOL([GTEST_CONFIG], [gtest-config])
GMOCK_CFLAGS=`$GMOCK_CONFIG --cppflags --cxxflags`
GMOCK_LIBS=`$GMOCK_CONFIG --ldflags --libs`
GTEST_CFLAGS=`$GTEST_CONFIG --cppflags --cxxflags`
GTEST_LIBS=`$GTEST_CONFIG --ldflags --libs`
fi
AC_ARG_ENABLE(selftest,
AS_HELP_STRING([--enable-selftest],
[Run extra tests with "make check" ]
[(may conflict with optimizations) ]
[(default is no)]),
[case "${enableval}" in
yes)
selftest=true
;;
no)
selftest=false
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --enable-selftest)
;;
esac],
[selftest=false])
AM_CONDITIONAL(SELFTEST, test x$selftest = xtrue)
AC_CONFIG_FILES(m4_flatten([
breakpad.pc
breakpad-client.pc
Makefile
]))
AC_OUTPUT

View File

@ -1,283 +0,0 @@
# ===========================================================================
# http://www.nongnu.org/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro figures out how to build C programs using POSIX threads. It
# sets the PTHREAD_LIBS output variable to the threads library and linker
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well. e.g. you should link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threads programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
# is not found. If ACTION-IF-FOUND is not specified, the default action
# will define HAVE_PTHREAD.
#
# Please let the authors know if this macro fails on any platform, or if
# you have any other suggestions or comments. This macro was based on work
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
# grateful for the helpful feedback of numerous users.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 6
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_SAVE
AC_LANG_C
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
AC_MSG_RESULT($ax_pthread_ok)
if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case "${host_cpu}-${host_os}" in
*solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
;;
*-darwin*)
acx_pthread_flags="-pthread $acx_pthread_flags"
;;
esac
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_TRY_LINK([#include <pthread.h>
static void routine(void* a) {a=0;}
static void* start_routine(void* a) {return a;}],
[pthread_t th; pthread_attr_t attr;
pthread_join(th, 0);
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_create(&th,0,start_routine,0);
pthread_cleanup_pop(0); ],
[ax_pthread_ok=yes])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($ax_pthread_ok)
if test "x$ax_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$ax_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
[attr_name=$attr; break])
done
AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case "${host_cpu}-${host_os}" in
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with xlc_r or cc_r
if test x"$GCC" != xyes; then
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
else
PTHREAD_CC=$CC
fi
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
ax_pthread_ok=no
$2
fi
AC_LANG_RESTORE
])dnl AX_PTHREAD

File diff suppressed because it is too large Load Diff

View File

@ -1,368 +0,0 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option `$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl `shared' nor `disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [0], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the `shared' and
# `disable-shared' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the `static' and
# `disable-static' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the `fast-install'
# and `disable-fast-install' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the `pic-only' and `no-pic'
# LT_INIT options.
# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[pic_mode="$withval"],
[pic_mode=default])
test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])

View File

@ -1,123 +0,0 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59 which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])

View File

@ -1,23 +0,0 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# Generated from ltversion.in.
# serial 3017 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.2.6b])
m4_define([LT_PACKAGE_REVISION], [1.3017])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.2.6b'
macro_revision='1.3017'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])

View File

@ -1,92 +0,0 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 4 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])

View File

@ -1,57 +0,0 @@
// Copyright (c) 2009, 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.
#ifndef BREAKPAD_GOOGLETEST_INCLUDES_H__
#define BREAKPAD_GOOGLETEST_INCLUDES_H__
#include "gtest/gtest.h"
#include "gmock/gmock.h"
// If AddressSanitizer is used, NULL pointer dereferences generate SIGILL
// (illegal instruction) instead of SIGSEGV (segmentation fault). Also,
// the number of memory regions differs, so there is no point in running
// this test if AddressSanitizer is used.
//
// Ideally we'd use this attribute to disable ASAN on a per-func basis,
// but this doesn't seem to actually work, and it's changed names over
// time. So just stick with disabling the actual tests.
// http://crbug.com/304575
//#define NO_ASAN __attribute__((no_sanitize_address))
#if defined(__clang__) && defined(__has_feature)
// Have to keep this check sep from above as newer gcc will barf on it.
# if __has_feature(address_sanitizer)
# define ADDRESS_SANITIZER
# endif
#elif defined(__GNUC__) && defined(__SANITIZE_ADDRESS__)
# define ADDRESS_SANITIZER
#else
# undef ADDRESS_SANITIZER
#endif
#endif // BREAKPAD_GOOGLETEST_INCLUDES_H__

View File

@ -1,41 +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.
{
'targets': [
{
'target_name': 'All',
'type': 'none',
'dependencies': [
'../common/common.gyp:*',
'../processor/processor.gyp:*',
'../tools/tools.gyp:*',
],
},
],
}

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +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.
{
'target_conditions': [
['OS!="win"', {
'sources/': [
['exclude', '(^|/)windows/'],
],
}],
['OS!="linux"', {
'sources/': [
['exclude', '(^|/)linux/'],
],
}],
['OS!="mac"', {
'sources/': [
['exclude', '(^|/)mac/'],
],
}],
['OS!="android"', {
'sources/': [
['exclude', '(^|/)android/'],
],
}],
['OS!="solaris"', {
'sources/': [
['exclude', '(^|/)solaris/'],
],
}],
],
}

View File

@ -1,67 +0,0 @@
#!/usr/bin/env python
# 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.
import os
import platform
import sys
script_dir = os.path.dirname(os.path.realpath(__file__))
breakpad_root = os.path.abspath(os.path.join(script_dir, os.pardir))
sys.path.insert(0, os.path.join(breakpad_root, 'tools', 'gyp', 'pylib'))
import gyp
def run_gyp(args):
rc = gyp.main(args)
if rc != 0:
print 'Error running GYP'
sys.exit(rc)
def main():
args = sys.argv[1:]
args.append(os.path.join(script_dir, 'all.gyp'))
args.append('-I')
args.append(os.path.join(breakpad_root, 'build', 'common.gypi'))
args.extend(['-D', 'gyp_output_dir=out'])
# Set the GYP DEPTH variable to the root of the project.
args.append('--depth=' + os.path.relpath(breakpad_root))
print 'Updating projects from gyp files...'
sys.stdout.flush()
run_gyp(args)
if __name__ == '__main__':
sys.exit(main())

View File

@ -1,90 +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.
{
'targets': [
{
'target_name': 'gtest',
'type': 'static_library',
'sources': [
'../testing/gtest/src/gtest-all.cc',
],
'include_dirs': [
'../testing/gtest',
'../testing/gtest/include',
],
'direct_dependent_settings': {
'include_dirs': [
'../testing/gtest/include',
],
},
},
{
'target_name': 'gtest_main',
'type': 'static_library',
'dependencies': [
'gtest',
],
'sources': [
'gtest/src/gtest_main.cc',
],
},
{
'target_name': 'gmock',
'type': 'static_library',
'dependencies': [
'gtest',
],
'sources': [
'../testing/src/gmock-all.cc',
],
'include_dirs': [
'../testing',
'../testing/include',
],
'direct_dependent_settings': {
'include_dirs': [
'../testing/include',
],
},
'export_dependent_settings': [
'gtest',
],
},
{
'target_name': 'gmock_main',
'type': 'static_library',
'dependencies': [
'gmock',
],
'sources': [
'../testing/src/gmock_main.cc',
],
},
],
}

View File

@ -1,73 +0,0 @@
// Copyright (c) 2011, 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.
// Keys for configuration file
#define kReporterMinidumpDirectoryKey "MinidumpDir"
#define kReporterMinidumpIDKey "MinidumpID"
// Filename for recording uploaded IDs
#define kReporterLogFilename "uploads.log"
// The default subdirectory of the Library to put crash dumps in
// The subdirectory is
// ~/Library/<kDefaultLibrarySubdirectory>/<GoogleBreakpadProduct>
#define kDefaultLibrarySubdirectory "Breakpad"
// Specify some special keys to be used in the configuration file that is
// generated by Breakpad and consumed by the crash_sender.
#define BREAKPAD_PRODUCT "BreakpadProduct"
#define BREAKPAD_PRODUCT_DISPLAY "BreakpadProductDisplay"
#define BREAKPAD_VERSION "BreakpadVersion"
#define BREAKPAD_VENDOR "BreakpadVendor"
#define BREAKPAD_URL "BreakpadURL"
#define BREAKPAD_REPORT_INTERVAL "BreakpadReportInterval"
#define BREAKPAD_SKIP_CONFIRM "BreakpadSkipConfirm"
#define BREAKPAD_CONFIRM_TIMEOUT "BreakpadConfirmTimeout"
#define BREAKPAD_SEND_AND_EXIT "BreakpadSendAndExit"
#define BREAKPAD_DUMP_DIRECTORY "BreakpadMinidumpLocation"
#define BREAKPAD_INSPECTOR_LOCATION "BreakpadInspectorLocation"
#define BREAKPAD_REPORTER_EXE_LOCATION \
"BreakpadReporterExeLocation"
#define BREAKPAD_LOGFILES "BreakpadLogFiles"
#define BREAKPAD_LOGFILE_UPLOAD_SIZE "BreakpadLogFileTailSize"
#define BREAKPAD_REQUEST_COMMENTS "BreakpadRequestComments"
#define BREAKPAD_COMMENTS "BreakpadComments"
#define BREAKPAD_REQUEST_EMAIL "BreakpadRequestEmail"
#define BREAKPAD_EMAIL "BreakpadEmail"
#define BREAKPAD_SERVER_TYPE "BreakpadServerType"
#define BREAKPAD_SERVER_PARAMETER_DICT "BreakpadServerParameters"
#define BREAKPAD_IN_PROCESS "BreakpadInProcess"
// The keys below are NOT user supplied, and are used internally.
#define BREAKPAD_PROCESS_START_TIME "BreakpadProcStartTime"
#define BREAKPAD_PROCESS_UP_TIME "BreakpadProcessUpTime"
#define BREAKPAD_PROCESS_CRASH_TIME "BreakpadProcessCrashTime"
#define BREAKPAD_LOGFILE_KEY_PREFIX "BreakpadAppLogFile"
#define BREAKPAD_SERVER_PARAMETER_PREFIX "BreakpadServerParameterPrefix_"
#define BREAKPAD_ON_DEMAND "BreakpadOnDemand"

View File

@ -1,246 +0,0 @@
// Copyright (c) 2011, 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.
// Framework to provide a simple C API to crash reporting for
// applications. By default, if any machine-level exception (e.g.,
// EXC_BAD_ACCESS) occurs, it will be handled by the BreakpadRef
// object as follows:
//
// 1. Create a minidump file (see Breakpad for details)
// 2. Create a config file.
//
// These files can then be uploaded to a server.
typedef void *BreakpadRef;
#ifdef __cplusplus
extern "C" {
#endif
#include <Foundation/Foundation.h>
#include <client/apple/Framework/BreakpadDefines.h>
// The keys in the dictionary returned by |BreakpadGenerateReport|.
#define BREAKPAD_OUTPUT_DUMP_FILE "BreakpadDumpFile"
#define BREAKPAD_OUTPUT_CONFIG_FILE "BreakpadConfigFile"
// Optional user-defined function to decide if we should handle this crash or
// forward it along.
// Return true if you want Breakpad to handle it.
// Return false if you want Breakpad to skip it
// The exception handler always returns false, as if SEND_AND_EXIT were false
// (which means the next exception handler will take the exception)
typedef bool (*BreakpadFilterCallback)(int exception_type,
int exception_code,
mach_port_t crashing_thread,
void *context);
// Create a new BreakpadRef object and install it as an exception
// handler. The |parameters| will typically be the contents of your
// bundle's Info.plist.
//
// You can also specify these additional keys for customizable behavior:
// Key: Value:
// BREAKPAD_PRODUCT Product name (e.g., "MyAwesomeProduct")
// This one is used as the key to identify
// the product when uploading. Falls back to
// CFBundleName if not specified.
// REQUIRED
//
// BREAKPAD_PRODUCT_DISPLAY This is the display name, e.g. a pretty
// name for the product when the crash_sender
// pops up UI for the user. Falls back first to
// CFBundleDisplayName and then to
// BREAKPAD_PRODUCT if not specified.
//
// BREAKPAD_VERSION Product version (e.g., 1.2.3), used
// as metadata for crash report. Falls back to
// CFBundleVersion if not specified.
// REQUIRED
//
// BREAKPAD_VENDOR Vendor name, used in UI (e.g. "A report has
// been created that you can send to <vendor>")
//
// BREAKPAD_URL URL destination for reporting
// REQUIRED
//
// BREAKPAD_DUMP_DIRECTORY The directory to store crash-dumps
// in. By default, we use
// ~/Library/Cache/Breakpad/<BREAKPAD_PRODUCT>
// The path you specify here is tilde-expanded.
//
// BREAKPAD_SERVER_TYPE A parameter that tells Breakpad how to
// rewrite the upload parameters for a specific
// server type. The currently valid values are
// 'socorro' or 'google'. If you want to add
// other types, see the function in
// crash_report_sender.m that maps parameters to
// URL parameters. Defaults to 'google'.
//
// BREAKPAD_SERVER_PARAMETER_DICT A plist dictionary of static
// parameters that are uploaded to the
// server. The parameters are sent as
// is to the crash server. Their
// content isn't added to the minidump
// but pass as URL parameters when
// uploading theminidump to the crash
// server.
//=============================================================================
// The BREAKPAD_PRODUCT, BREAKPAD_VERSION and BREAKPAD_URL are
// required to have non-NULL values. By default, the BREAKPAD_PRODUCT
// will be the CFBundleName and the BREAKPAD_VERSION will be the
// CFBundleVersion when these keys are present in the bundle's
// Info.plist, which is usually passed in to BreakpadCreate() as an
// NSDictionary (you could also pass in another dictionary that had
// the same keys configured). If the BREAKPAD_PRODUCT or
// BREAKPAD_VERSION are ultimately undefined, BreakpadCreate() will
// fail. You have been warned.
//
// If you are running in a debugger, Breakpad will not install, unless the
// BREAKPAD_IGNORE_DEBUGGER envionment variable is set and/or non-zero.
//
//=============================================================================
// The following are NOT user-supplied but are documented here for
// completeness. They are calculated by Breakpad during initialization &
// crash-dump generation, or entered in by the user.
//
// BREAKPAD_PROCESS_START_TIME The time, in seconds since the Epoch, the
// process started
//
// BREAKPAD_PROCESS_CRASH_TIME The time, in seconds since the Epoch, the
// process crashed.
//
// BREAKPAD_PROCESS_UP_TIME The total time in milliseconds the process
// has been running. This parameter is not
// set until the crash-dump-generation phase.
//
// BREAKPAD_SERVER_PARAMETER_PREFIX This prefix is used by Breakpad
// internally, because Breakpad uses
// the same dictionary internally to
// track both its internal
// configuration parameters and
// parameters meant to be uploaded
// to the server. This string is
// used internally by Breakpad to
// prefix user-supplied parameter
// names so those can be sent to the
// server without leaking Breakpad's
// internal values.
// Returns a new BreakpadRef object on success, NULL otherwise.
BreakpadRef BreakpadCreate(NSDictionary *parameters);
// Uninstall and release the data associated with |ref|.
void BreakpadRelease(BreakpadRef ref);
// User defined key and value string storage. Generally this is used
// to configure Breakpad's internal operation, such as whether the
// crash_sender should prompt the user, or the filesystem location for
// the minidump file. See Breakpad.h for some parameters that can be
// set. Anything longer than 255 bytes will be truncated. Note that
// the string is converted to UTF8 before truncation, so any multibyte
// character that straddles the 255(256 - 1 for terminator) byte limit
// will be mangled.
//
// A maximum number of 64 key/value pairs are supported. An assert()
// will fire if more than this number are set. Unfortunately, right
// now, the same dictionary is used for both Breakpad's parameters AND
// the Upload parameters.
//
// TODO (nealsid): Investigate how necessary this is if we don't
// automatically upload parameters to the server anymore.
// TODO (nealsid): separate server parameter dictionary from the
// dictionary used to configure Breakpad, and document limits for each
// independently.
void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value);
NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key);
void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key);
// You can use this method to specify parameters that will be uploaded
// to the crash server. They will be automatically encoded as
// necessary. Note that as mentioned above there are limits on both
// the number of keys and their length.
void BreakpadAddUploadParameter(BreakpadRef ref, NSString *key,
NSString *value);
// This method will remove a previously-added parameter from the
// upload parameter set.
void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString *key);
// Method to handle uploading data to the server
// Returns the number of crash reports waiting to send to the server.
int BreakpadGetCrashReportCount(BreakpadRef ref);
// Returns the next upload configuration. The report file is deleted.
NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref);
// Upload next report to the server.
void BreakpadUploadNextReport(BreakpadRef ref);
// Upload next report to the server.
// |server_parameters| is additional server parameters to send.
void BreakpadUploadNextReportWithParameters(BreakpadRef ref,
NSDictionary *server_parameters);
// Upload a report to the server.
// |server_parameters| is additional server parameters to send.
// |configuration| is the configuration of the breakpad report to send.
void BreakpadUploadReportWithParametersAndConfiguration(
BreakpadRef ref,
NSDictionary *server_parameters,
NSDictionary *configuration);
// Handles the network response of a breakpad upload. This function is needed if
// the actual upload is done by the Breakpad client.
// |configuration| is the configuration of the upload. It must contain the same
// fields as the configuration passed to
// BreakpadUploadReportWithParametersAndConfiguration.
// |data| and |error| contain the network response.
void BreakpadHandleNetworkResponse(BreakpadRef ref,
NSDictionary *configuration,
NSData *data,
NSError *error);
// Upload a file to the server. |data| is the content of the file to sent.
// |server_parameters| is additional server parameters to send.
void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name,
NSDictionary *server_parameters);
// Generate a breakpad minidump and configuration file in the dump directory.
// The report will be available for uploading. The paths of the created files
// are returned in the dictionary. |server_parameters| is additional server
// parameters to add in the config file.
NSDictionary *BreakpadGenerateReport(BreakpadRef ref,
NSDictionary *server_parameters);
#ifdef __cplusplus
}
#endif

View File

@ -1,916 +0,0 @@
// Copyright (c) 2011, 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.
#define IGNORE_DEBUGGER "BREAKPAD_IGNORE_DEBUGGER"
#import "client/ios/Breakpad.h"
#include <assert.h>
#import <Foundation/Foundation.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#import "client/ios/handler/ios_exception_minidump_generator.h"
#import "client/mac/crash_generation/ConfigFile.h"
#import "client/mac/handler/exception_handler.h"
#import "client/mac/handler/minidump_generator.h"
#import "client/mac/sender/uploader.h"
#import "client/mac/handler/protected_memory_allocator.h"
#import "common/simple_string_dictionary.h"
#if !defined(__EXCEPTIONS) || (__clang__ && !__has_feature(cxx_exceptions))
// This file uses C++ try/catch (but shouldn't). Duplicate the macros from
// <c++/4.2.1/exception_defines.h> allowing this file to work properly with
// exceptions disabled even when other C++ libraries are used. #undef the try
// and catch macros first in case libstdc++ is in use and has already provided
// its own definitions.
#undef try
#define try if (true)
#undef catch
#define catch(X) if (false)
#endif // __EXCEPTIONS
using google_breakpad::ConfigFile;
using google_breakpad::EnsureDirectoryPathExists;
using google_breakpad::SimpleStringDictionary;
//=============================================================================
// We want any memory allocations which are used by breakpad during the
// exception handling process (after a crash has happened) to be read-only
// to prevent them from being smashed before a crash occurs. Unfortunately
// we cannot protect against smashes to our exception handling thread's
// stack.
//
// NOTE: Any memory allocations which are not used during the exception
// handling process may be allocated in the normal ways.
//
// The ProtectedMemoryAllocator class provides an Allocate() method which
// we'll using in conjunction with placement operator new() to control
// allocation of C++ objects. Note that we don't use operator delete()
// but instead call the objects destructor directly: object->~ClassName();
//
ProtectedMemoryAllocator *gMasterAllocator = NULL;
ProtectedMemoryAllocator *gKeyValueAllocator = NULL;
ProtectedMemoryAllocator *gBreakpadAllocator = NULL;
// Mutex for thread-safe access to the key/value dictionary used by breakpad.
// It's a global instead of an instance variable of Breakpad
// since it can't live in a protected memory area.
pthread_mutex_t gDictionaryMutex;
//=============================================================================
// Stack-based object for thread-safe access to a memory-protected region.
// It's assumed that normally the memory block (allocated by the allocator)
// is protected (read-only). Creating a stack-based instance of
// ProtectedMemoryLocker will unprotect this block after taking the lock.
// Its destructor will first re-protect the memory then release the lock.
class ProtectedMemoryLocker {
public:
ProtectedMemoryLocker(pthread_mutex_t *mutex,
ProtectedMemoryAllocator *allocator)
: mutex_(mutex),
allocator_(allocator) {
// Lock the mutex
__attribute__((unused)) int rv = pthread_mutex_lock(mutex_);
assert(rv == 0);
// Unprotect the memory
allocator_->Unprotect();
}
~ProtectedMemoryLocker() {
// First protect the memory
allocator_->Protect();
// Then unlock the mutex
__attribute__((unused)) int rv = pthread_mutex_unlock(mutex_);
assert(rv == 0);
};
private:
ProtectedMemoryLocker();
ProtectedMemoryLocker(const ProtectedMemoryLocker&);
ProtectedMemoryLocker& operator=(const ProtectedMemoryLocker&);
pthread_mutex_t *mutex_;
ProtectedMemoryAllocator *allocator_;
};
//=============================================================================
class Breakpad {
public:
// factory method
static Breakpad *Create(NSDictionary *parameters) {
// Allocate from our special allocation pool
Breakpad *breakpad =
new (gBreakpadAllocator->Allocate(sizeof(Breakpad)))
Breakpad();
if (!breakpad)
return NULL;
if (!breakpad->Initialize(parameters)) {
// Don't use operator delete() here since we allocated from special pool
breakpad->~Breakpad();
return NULL;
}
return breakpad;
}
~Breakpad();
void SetKeyValue(NSString *key, NSString *value);
NSString *KeyValue(NSString *key);
void RemoveKeyValue(NSString *key);
NSArray *CrashReportsToUpload();
NSString *NextCrashReportToUpload();
NSDictionary *NextCrashReportConfiguration();
void UploadNextReport(NSDictionary *server_parameters);
void UploadReportWithConfiguration(NSDictionary *configuration,
NSDictionary *server_parameters);
void UploadData(NSData *data, NSString *name,
NSDictionary *server_parameters);
void HandleNetworkResponse(NSDictionary *configuration,
NSData *data,
NSError *error);
NSDictionary *GenerateReport(NSDictionary *server_parameters);
private:
Breakpad()
: handler_(NULL),
config_params_(NULL) {}
bool Initialize(NSDictionary *parameters);
bool ExtractParameters(NSDictionary *parameters);
// Dispatches to HandleMinidump()
static bool HandleMinidumpCallback(const char *dump_dir,
const char *minidump_id,
void *context, bool succeeded);
bool HandleMinidump(const char *dump_dir,
const char *minidump_id);
// NSException handler
static void UncaughtExceptionHandler(NSException *exception);
// Handle an uncaught NSException.
void HandleUncaughtException(NSException *exception);
// Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's
// MachineExceptions.h, we have to explicitly name the handler.
google_breakpad::ExceptionHandler *handler_; // The actual handler (STRONG)
SimpleStringDictionary *config_params_; // Create parameters (STRONG)
ConfigFile config_file_;
// A static reference to the current Breakpad instance. Used for handling
// NSException.
static Breakpad *current_breakpad_;
};
Breakpad *Breakpad::current_breakpad_ = NULL;
#pragma mark -
#pragma mark Helper functions
//=============================================================================
// Helper functions
//=============================================================================
static BOOL IsDebuggerActive() {
BOOL result = NO;
NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
// We check both defaults and the environment variable here
BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER];
if (!ignoreDebugger) {
char *ignoreDebuggerStr = getenv(IGNORE_DEBUGGER);
ignoreDebugger =
(ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0;
}
if (!ignoreDebugger) {
pid_t pid = getpid();
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
int mibSize = sizeof(mib) / sizeof(int);
size_t actualSize;
if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) {
struct kinfo_proc *info = (struct kinfo_proc *)malloc(actualSize);
if (info) {
// This comes from looking at the Darwin xnu Kernel
if (sysctl(mib, mibSize, info, &actualSize, NULL, 0) == 0)
result = (info->kp_proc.p_flag & P_TRACED) ? YES : NO;
free(info);
}
}
}
return result;
}
//=============================================================================
bool Breakpad::HandleMinidumpCallback(const char *dump_dir,
const char *minidump_id,
void *context, bool succeeded) {
Breakpad *breakpad = (Breakpad *)context;
// If our context is damaged or something, just return false to indicate that
// the handler should continue without us.
if (!breakpad || !succeeded)
return false;
return breakpad->HandleMinidump(dump_dir, minidump_id);
}
//=============================================================================
void Breakpad::UncaughtExceptionHandler(NSException *exception) {
NSSetUncaughtExceptionHandler(NULL);
if (current_breakpad_) {
current_breakpad_->HandleUncaughtException(exception);
BreakpadRelease(current_breakpad_);
}
}
//=============================================================================
#pragma mark -
//=============================================================================
bool Breakpad::Initialize(NSDictionary *parameters) {
// Initialize
current_breakpad_ = this;
config_params_ = NULL;
handler_ = NULL;
// Gather any user specified parameters
if (!ExtractParameters(parameters)) {
return false;
}
// Check for debugger
if (IsDebuggerActive()) {
return true;
}
// Create the handler (allocating it in our special protected pool)
handler_ =
new (gBreakpadAllocator->Allocate(
sizeof(google_breakpad::ExceptionHandler)))
google_breakpad::ExceptionHandler(
config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY),
0, &HandleMinidumpCallback, this, true, 0);
NSSetUncaughtExceptionHandler(&Breakpad::UncaughtExceptionHandler);
return true;
}
//=============================================================================
Breakpad::~Breakpad() {
NSSetUncaughtExceptionHandler(NULL);
current_breakpad_ = NULL;
// Note that we don't use operator delete() on these pointers,
// since they were allocated by ProtectedMemoryAllocator objects.
//
if (config_params_) {
config_params_->~SimpleStringDictionary();
}
if (handler_)
handler_->~ExceptionHandler();
}
//=============================================================================
bool Breakpad::ExtractParameters(NSDictionary *parameters) {
NSString *serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE];
NSString *display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY];
NSString *product = [parameters objectForKey:@BREAKPAD_PRODUCT];
NSString *version = [parameters objectForKey:@BREAKPAD_VERSION];
NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL];
NSString *vendor =
[parameters objectForKey:@BREAKPAD_VENDOR];
// We check both parameters and the environment variable here.
char *envVarDumpSubdirectory = getenv(BREAKPAD_DUMP_DIRECTORY);
NSString *dumpSubdirectory = envVarDumpSubdirectory ?
[NSString stringWithUTF8String:envVarDumpSubdirectory] :
[parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY];
NSDictionary *serverParameters =
[parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT];
if (!product)
product = [parameters objectForKey:@"CFBundleName"];
if (!display) {
display = [parameters objectForKey:@"CFBundleDisplayName"];
if (!display) {
display = product;
}
}
if (!version.length) // Default nil or empty string to CFBundleVersion
version = [parameters objectForKey:@"CFBundleVersion"];
if (!vendor) {
vendor = @"Vendor not specified";
}
if (!dumpSubdirectory) {
NSString *cachePath =
[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
NSUserDomainMask,
YES)
objectAtIndex:0];
dumpSubdirectory =
[cachePath stringByAppendingPathComponent:@kDefaultLibrarySubdirectory];
EnsureDirectoryPathExists(dumpSubdirectory);
}
// The product, version, and URL are required values.
if (![product length]) {
return false;
}
if (![version length]) {
return false;
}
if (![urlStr length]) {
return false;
}
config_params_ =
new (gKeyValueAllocator->Allocate(sizeof(SimpleStringDictionary)) )
SimpleStringDictionary();
SimpleStringDictionary &dictionary = *config_params_;
dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]);
dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]);
dictionary.SetKeyValue(BREAKPAD_PRODUCT, [product UTF8String]);
dictionary.SetKeyValue(BREAKPAD_VERSION, [version UTF8String]);
dictionary.SetKeyValue(BREAKPAD_URL, [urlStr UTF8String]);
dictionary.SetKeyValue(BREAKPAD_VENDOR, [vendor UTF8String]);
dictionary.SetKeyValue(BREAKPAD_DUMP_DIRECTORY,
[dumpSubdirectory UTF8String]);
struct timeval tv;
gettimeofday(&tv, NULL);
char timeStartedString[32];
sprintf(timeStartedString, "%zd", tv.tv_sec);
dictionary.SetKeyValue(BREAKPAD_PROCESS_START_TIME, timeStartedString);
if (serverParameters) {
// For each key-value pair, call BreakpadAddUploadParameter()
NSEnumerator *keyEnumerator = [serverParameters keyEnumerator];
NSString *aParameter;
while ((aParameter = [keyEnumerator nextObject])) {
BreakpadAddUploadParameter(this, aParameter,
[serverParameters objectForKey:aParameter]);
}
}
return true;
}
//=============================================================================
void Breakpad::SetKeyValue(NSString *key, NSString *value) {
// We allow nil values. This is the same as removing the keyvalue.
if (!config_params_ || !key)
return;
config_params_->SetKeyValue([key UTF8String], [value UTF8String]);
}
//=============================================================================
NSString *Breakpad::KeyValue(NSString *key) {
if (!config_params_ || !key)
return nil;
const char *value = config_params_->GetValueForKey([key UTF8String]);
return value ? [NSString stringWithUTF8String:value] : nil;
}
//=============================================================================
void Breakpad::RemoveKeyValue(NSString *key) {
if (!config_params_ || !key) return;
config_params_->RemoveKey([key UTF8String]);
}
//=============================================================================
NSArray *Breakpad::CrashReportsToUpload() {
NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!directory)
return nil;
NSArray *dirContents = [[NSFileManager defaultManager]
contentsOfDirectoryAtPath:directory error:nil];
NSArray *configs = [dirContents filteredArrayUsingPredicate:[NSPredicate
predicateWithFormat:@"self BEGINSWITH 'Config-'"]];
return configs;
}
//=============================================================================
NSString *Breakpad::NextCrashReportToUpload() {
NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!directory)
return nil;
NSString *config = [CrashReportsToUpload() lastObject];
if (!config)
return nil;
return [NSString stringWithFormat:@"%@/%@", directory, config];
}
//=============================================================================
NSDictionary *Breakpad::NextCrashReportConfiguration() {
return [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()];
}
//=============================================================================
void Breakpad::HandleNetworkResponse(NSDictionary *configuration,
NSData *data,
NSError *error) {
Uploader *uploader = [[[Uploader alloc]
initWithConfig:configuration] autorelease];
[uploader handleNetworkResponse:data withError:error];
}
//=============================================================================
void Breakpad::UploadReportWithConfiguration(NSDictionary *configuration,
NSDictionary *server_parameters) {
Uploader *uploader = [[[Uploader alloc]
initWithConfig:configuration] autorelease];
if (!uploader)
return;
for (NSString *key in server_parameters) {
[uploader addServerParameter:[server_parameters objectForKey:key]
forKey:key];
}
[uploader report];
}
//=============================================================================
void Breakpad::UploadNextReport(NSDictionary *server_parameters) {
NSDictionary *configuration = NextCrashReportConfiguration();
if (configuration) {
return UploadReportWithConfiguration(configuration, server_parameters);
}
}
//=============================================================================
void Breakpad::UploadData(NSData *data, NSString *name,
NSDictionary *server_parameters) {
NSMutableDictionary *config = [NSMutableDictionary dictionary];
SimpleStringDictionary::Iterator it(*config_params_);
while (const SimpleStringDictionary::Entry *next = it.Next()) {
[config setValue:[NSString stringWithUTF8String:next->value]
forKey:[NSString stringWithUTF8String:next->key]];
}
Uploader *uploader =
[[[Uploader alloc] initWithConfig:config] autorelease];
for (NSString *key in server_parameters) {
[uploader addServerParameter:[server_parameters objectForKey:key]
forKey:key];
}
[uploader uploadData:data name:name];
}
//=============================================================================
NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) {
NSString *dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!dumpDirAsNSString)
return nil;
const char *dumpDir = [dumpDirAsNSString UTF8String];
google_breakpad::MinidumpGenerator generator(mach_task_self(),
MACH_PORT_NULL);
std::string dumpId;
std::string dumpFilename = generator.UniqueNameInDirectory(dumpDir, &dumpId);
bool success = generator.Write(dumpFilename.c_str());
if (!success)
return nil;
SimpleStringDictionary params = *config_params_;
for (NSString *key in server_parameters) {
params.SetKeyValue([key UTF8String],
[[server_parameters objectForKey:key] UTF8String]);
}
ConfigFile config_file;
config_file.WriteFile(dumpDir, &params, dumpDir, dumpId.c_str());
// Handle results.
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSString *dumpFullPath = [NSString stringWithUTF8String:dumpFilename.c_str()];
[result setValue:dumpFullPath
forKey:@BREAKPAD_OUTPUT_DUMP_FILE];
[result setValue:[NSString stringWithUTF8String:config_file.GetFilePath()]
forKey:@BREAKPAD_OUTPUT_CONFIG_FILE];
return result;
}
//=============================================================================
bool Breakpad::HandleMinidump(const char *dump_dir,
const char *minidump_id) {
config_file_.WriteFile(dump_dir,
config_params_,
dump_dir,
minidump_id);
// Return true here to indicate that we've processed things as much as we
// want.
return true;
}
//=============================================================================
void Breakpad::HandleUncaughtException(NSException *exception) {
// Generate the minidump.
google_breakpad::IosExceptionMinidumpGenerator generator(exception);
const char *minidump_path =
config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
std::string minidump_id;
std::string minidump_filename = generator.UniqueNameInDirectory(minidump_path,
&minidump_id);
generator.Write(minidump_filename.c_str());
// Copy the config params and our custom parameter. This is necessary for 2
// reasons:
// 1- config_params_ is protected.
// 2- If the application crash while trying to handle this exception, a usual
// report will be generated. This report must not contain these special
// keys.
SimpleStringDictionary params = *config_params_;
params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "type", "exception");
params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionName",
[[exception name] UTF8String]);
params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionReason",
[[exception reason] UTF8String]);
// And finally write the config file.
ConfigFile config_file;
config_file.WriteFile(minidump_path,
&params,
minidump_path,
minidump_id.c_str());
}
//=============================================================================
#pragma mark -
#pragma mark Public API
//=============================================================================
BreakpadRef BreakpadCreate(NSDictionary *parameters) {
try {
// This is confusing. Our two main allocators for breakpad memory are:
// - gKeyValueAllocator for the key/value memory
// - gBreakpadAllocator for the Breakpad, ExceptionHandler, and other
// breakpad allocations which are accessed at exception handling time.
//
// But in order to avoid these two allocators themselves from being smashed,
// we'll protect them as well by allocating them with gMasterAllocator.
//
// gMasterAllocator itself will NOT be protected, but this doesn't matter,
// since once it does its allocations and locks the memory, smashes to
// itself don't affect anything we care about.
gMasterAllocator =
new ProtectedMemoryAllocator(sizeof(ProtectedMemoryAllocator) * 2);
gKeyValueAllocator =
new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
ProtectedMemoryAllocator(sizeof(SimpleStringDictionary));
// Create a mutex for use in accessing the SimpleStringDictionary
int mutexResult = pthread_mutex_init(&gDictionaryMutex, NULL);
if (mutexResult == 0) {
// With the current compiler, gBreakpadAllocator is allocating 1444 bytes.
// Let's round up to the nearest page size.
//
int breakpad_pool_size = 4096;
/*
sizeof(Breakpad)
+ sizeof(google_breakpad::ExceptionHandler)
+ sizeof( STUFF ALLOCATED INSIDE ExceptionHandler )
*/
gBreakpadAllocator =
new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
ProtectedMemoryAllocator(breakpad_pool_size);
// Stack-based autorelease pool for Breakpad::Create() obj-c code.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Breakpad *breakpad = Breakpad::Create(parameters);
if (breakpad) {
// Make read-only to protect against memory smashers
gMasterAllocator->Protect();
gKeyValueAllocator->Protect();
gBreakpadAllocator->Protect();
// Can uncomment this line to figure out how much space was actually
// allocated using this allocator
// printf("gBreakpadAllocator allocated size = %d\n",
// gBreakpadAllocator->GetAllocatedSize() );
[pool release];
return (BreakpadRef)breakpad;
}
[pool release];
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadCreate() : error\n");
}
if (gKeyValueAllocator) {
gKeyValueAllocator->~ProtectedMemoryAllocator();
gKeyValueAllocator = NULL;
}
if (gBreakpadAllocator) {
gBreakpadAllocator->~ProtectedMemoryAllocator();
gBreakpadAllocator = NULL;
}
delete gMasterAllocator;
gMasterAllocator = NULL;
return NULL;
}
//=============================================================================
void BreakpadRelease(BreakpadRef ref) {
try {
Breakpad *breakpad = (Breakpad *)ref;
if (gMasterAllocator) {
gMasterAllocator->Unprotect();
gKeyValueAllocator->Unprotect();
gBreakpadAllocator->Unprotect();
breakpad->~Breakpad();
// Unfortunately, it's not possible to deallocate this stuff
// because the exception handling thread is still finishing up
// asynchronously at this point... OK, it could be done with
// locks, etc. But since BreakpadRelease() should usually only
// be called right before the process exits, it's not worth
// deallocating this stuff.
#if 0
gKeyValueAllocator->~ProtectedMemoryAllocator();
gBreakpadAllocator->~ProtectedMemoryAllocator();
delete gMasterAllocator;
gMasterAllocator = NULL;
gKeyValueAllocator = NULL;
gBreakpadAllocator = NULL;
#endif
pthread_mutex_destroy(&gDictionaryMutex);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadRelease() : error\n");
}
}
//=============================================================================
void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
breakpad->SetKeyValue(key, value);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadSetKeyValue() : error\n");
}
}
void BreakpadAddUploadParameter(BreakpadRef ref,
NSString *key,
NSString *value) {
// The only difference, internally, between an upload parameter and
// a key value one that is set with BreakpadSetKeyValue is that we
// prepend the keyname with a special prefix. This informs the
// crash sender that the parameter should be sent along with the
// POST of the crash dump upload.
try {
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
NSString *prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX
stringByAppendingString:key];
breakpad->SetKeyValue(prefixedKey, value);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadSetKeyValue() : error\n");
}
}
void BreakpadRemoveUploadParameter(BreakpadRef ref,
NSString *key) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
NSString *prefixedKey = [NSString stringWithFormat:@"%@%@",
@BREAKPAD_SERVER_PARAMETER_PREFIX, key];
breakpad->RemoveKeyValue(prefixedKey);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadRemoveKeyValue() : error\n");
}
}
//=============================================================================
NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) {
NSString *value = nil;
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (!breakpad || !key || !gKeyValueAllocator)
return nil;
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
value = breakpad->KeyValue(key);
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadKeyValue() : error\n");
}
return value;
}
//=============================================================================
void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
breakpad->RemoveKeyValue(key);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadRemoveKeyValue() : error\n");
}
}
//=============================================================================
int BreakpadGetCrashReportCount(BreakpadRef ref) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad) {
return static_cast<int>([breakpad->CrashReportsToUpload() count]);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadGetCrashReportCount() : error\n");
}
return false;
}
//=============================================================================
void BreakpadUploadNextReport(BreakpadRef ref) {
BreakpadUploadNextReportWithParameters(ref, nil);
}
//=============================================================================
NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref) {
try {
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad)
return breakpad->NextCrashReportConfiguration();
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadGetNextReportConfiguration() : error\n");
}
return nil;
}
//=============================================================================
void BreakpadUploadReportWithParametersAndConfiguration(
BreakpadRef ref,
NSDictionary *server_parameters,
NSDictionary *configuration) {
try {
Breakpad *breakpad = (Breakpad *)ref;
if (!breakpad || !configuration)
return;
breakpad->UploadReportWithConfiguration(configuration, server_parameters);
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr,
"BreakpadUploadReportWithParametersAndConfiguration() : error\n");
}
}
//=============================================================================
void BreakpadUploadNextReportWithParameters(BreakpadRef ref,
NSDictionary *server_parameters) {
try {
Breakpad *breakpad = (Breakpad *)ref;
if (!breakpad)
return;
NSDictionary *configuration = breakpad->NextCrashReportConfiguration();
if (!configuration)
return;
return BreakpadUploadReportWithParametersAndConfiguration(ref,
server_parameters,
configuration);
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadUploadNextReportWithParameters() : error\n");
}
}
void BreakpadHandleNetworkResponse(BreakpadRef ref,
NSDictionary *configuration,
NSData *data,
NSError *error) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && configuration)
breakpad->HandleNetworkResponse(configuration,data, error);
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadHandleNetworkResponse() : error\n");
}
}
//=============================================================================
void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name,
NSDictionary *server_parameters) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad) {
breakpad->UploadData(data, name, server_parameters);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadUploadData() : error\n");
}
}
//=============================================================================
NSDictionary *BreakpadGenerateReport(BreakpadRef ref,
NSDictionary *server_parameters) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad) {
return breakpad->GenerateReport(server_parameters);
} else {
return nil;
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadGenerateReport() : error\n");
return nil;
}
}

View File

@ -1,578 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
14569321182CE29F0029C465 /* ucontext_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569320182CE29F0029C465 /* ucontext_compat.h */; };
14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569322182CE2C10029C465 /* mach_vm_compat.h */; };
16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */; };
16BFA67214E1965A009704F8 /* ios_exception_minidump_generator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */; };
16C7CCCB147D4A4300776EAD /* BreakpadDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7C968147D4A4200776EAD /* BreakpadDefines.h */; };
16C7CCCC147D4A4300776EAD /* Breakpad.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7C96A147D4A4200776EAD /* Breakpad.h */; };
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C7C96B147D4A4200776EAD /* Breakpad.mm */; };
16C7CDE8147D4A4300776EAD /* ConfigFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CB9E147D4A4300776EAD /* ConfigFile.h */; };
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CB9F147D4A4300776EAD /* ConfigFile.mm */; };
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBAD147D4A4300776EAD /* breakpad_nlist_64.cc */; };
16C7CDF6147D4A4300776EAD /* breakpad_nlist_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBAE147D4A4300776EAD /* breakpad_nlist_64.h */; };
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBAF147D4A4300776EAD /* dynamic_images.cc */; };
16C7CDF8147D4A4300776EAD /* dynamic_images.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBB0147D4A4300776EAD /* dynamic_images.h */; };
16C7CDF9147D4A4300776EAD /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBB1147D4A4300776EAD /* exception_handler.cc */; };
16C7CDFA147D4A4300776EAD /* exception_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBB2147D4A4300776EAD /* exception_handler.h */; };
16C7CDFC147D4A4300776EAD /* minidump_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBB4147D4A4300776EAD /* minidump_generator.cc */; };
16C7CDFD147D4A4300776EAD /* minidump_generator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBB5147D4A4300776EAD /* minidump_generator.h */; };
16C7CDFE147D4A4300776EAD /* protected_memory_allocator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */; };
16C7CDFF147D4A4300776EAD /* protected_memory_allocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */; };
16C7CE08147D4A4300776EAD /* uploader.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBEA147D4A4300776EAD /* uploader.h */; };
16C7CE09147D4A4300776EAD /* uploader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBEB147D4A4300776EAD /* uploader.mm */; };
16C7CE18147D4A4300776EAD /* minidump_file_writer-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC04147D4A4300776EAD /* minidump_file_writer-inl.h */; };
16C7CE19147D4A4300776EAD /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC05147D4A4300776EAD /* minidump_file_writer.cc */; };
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC06147D4A4300776EAD /* minidump_file_writer.h */; };
16C7CE40147D4A4300776EAD /* convert_UTF.c in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC4A147D4A4300776EAD /* convert_UTF.c */; };
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC4B147D4A4300776EAD /* convert_UTF.h */; };
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC88147D4A4300776EAD /* GTMLogger.h */; };
16C7CE79147D4A4300776EAD /* GTMLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC89147D4A4300776EAD /* GTMLogger.m */; };
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */; };
16C7CE7B147D4A4300776EAD /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */; };
16C7CE83147D4A4300776EAD /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC93147D4A4300776EAD /* file_id.cc */; };
16C7CE84147D4A4300776EAD /* file_id.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC94147D4A4300776EAD /* file_id.h */; };
16C7CE85147D4A4300776EAD /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC95147D4A4300776EAD /* macho_id.cc */; };
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC96147D4A4300776EAD /* macho_id.h */; };
16C7CE8A147D4A4300776EAD /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC9A147D4A4300776EAD /* macho_utilities.cc */; };
16C7CE8B147D4A4300776EAD /* macho_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC9B147D4A4300776EAD /* macho_utilities.h */; };
16C7CE8C147D4A4300776EAD /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC9C147D4A4300776EAD /* macho_walker.cc */; };
16C7CE8D147D4A4300776EAD /* macho_walker.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC9D147D4A4300776EAD /* macho_walker.h */; };
16C7CE8F147D4A4300776EAD /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC9F147D4A4300776EAD /* string_utilities.cc */; };
16C7CE90147D4A4300776EAD /* string_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CCA0147D4A4300776EAD /* string_utilities.h */; };
16C7CE93147D4A4300776EAD /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CCA4147D4A4300776EAD /* md5.cc */; };
16C7CE94147D4A4300776EAD /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CCA5147D4A4300776EAD /* md5.h */; };
16C7CEA7147D4A4300776EAD /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CCB9147D4A4300776EAD /* string_conversion.cc */; };
16C7CEA8147D4A4300776EAD /* string_conversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CCBA147D4A4300776EAD /* string_conversion.h */; };
16C92FAD150DF8330053D7BA /* BreakpadController.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C92FAB150DF8330053D7BA /* BreakpadController.h */; };
16C92FAE150DF8330053D7BA /* BreakpadController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C92FAC150DF8330053D7BA /* BreakpadController.mm */; };
1EEEB60F1720821900F7E689 /* simple_string_dictionary.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1EEEB60C1720821900F7E689 /* simple_string_dictionary.cc */; };
1EEEB6101720821900F7E689 /* simple_string_dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EEEB60D1720821900F7E689 /* simple_string_dictionary.h */; };
AA747D9F0F9514B9006C5449 /* Breakpad_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* Breakpad_Prefix.pch */; };
AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
14569320182CE29F0029C465 /* ucontext_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucontext_compat.h; sourceTree = "<group>"; };
14569322182CE2C10029C465 /* mach_vm_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_vm_compat.h; sourceTree = "<group>"; };
16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_exception_minidump_generator.h; sourceTree = "<group>"; };
16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ios_exception_minidump_generator.mm; sourceTree = "<group>"; };
16C7C968147D4A4200776EAD /* BreakpadDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BreakpadDefines.h; sourceTree = "<group>"; };
16C7C96A147D4A4200776EAD /* Breakpad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpad.h; sourceTree = "<group>"; };
16C7C96B147D4A4200776EAD /* Breakpad.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Breakpad.mm; sourceTree = "<group>"; };
16C7CB9E147D4A4300776EAD /* ConfigFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConfigFile.h; sourceTree = "<group>"; };
16C7CB9F147D4A4300776EAD /* ConfigFile.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ConfigFile.mm; sourceTree = "<group>"; };
16C7CBAD147D4A4300776EAD /* breakpad_nlist_64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_64.cc; sourceTree = "<group>"; };
16C7CBAE147D4A4300776EAD /* breakpad_nlist_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_64.h; sourceTree = "<group>"; };
16C7CBAF147D4A4300776EAD /* dynamic_images.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dynamic_images.cc; sourceTree = "<group>"; };
16C7CBB0147D4A4300776EAD /* dynamic_images.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dynamic_images.h; sourceTree = "<group>"; };
16C7CBB1147D4A4300776EAD /* exception_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exception_handler.cc; sourceTree = "<group>"; };
16C7CBB2147D4A4300776EAD /* exception_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exception_handler.h; sourceTree = "<group>"; };
16C7CBB4147D4A4300776EAD /* minidump_generator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_generator.cc; sourceTree = "<group>"; };
16C7CBB5147D4A4300776EAD /* minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minidump_generator.h; sourceTree = "<group>"; };
16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = protected_memory_allocator.cc; sourceTree = "<group>"; };
16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = protected_memory_allocator.h; sourceTree = "<group>"; };
16C7CBEA147D4A4300776EAD /* uploader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uploader.h; sourceTree = "<group>"; };
16C7CBEB147D4A4300776EAD /* uploader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = uploader.mm; sourceTree = "<group>"; };
16C7CC04147D4A4300776EAD /* minidump_file_writer-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "minidump_file_writer-inl.h"; sourceTree = "<group>"; };
16C7CC05147D4A4300776EAD /* minidump_file_writer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_file_writer.cc; sourceTree = "<group>"; };
16C7CC06147D4A4300776EAD /* minidump_file_writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minidump_file_writer.h; sourceTree = "<group>"; };
16C7CC07147D4A4300776EAD /* minidump_file_writer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_file_writer_unittest.cc; sourceTree = "<group>"; };
16C7CC4A147D4A4300776EAD /* convert_UTF.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = convert_UTF.c; sourceTree = "<group>"; };
16C7CC4B147D4A4300776EAD /* convert_UTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = convert_UTF.h; sourceTree = "<group>"; };
16C7CC88147D4A4300776EAD /* GTMLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMLogger.h; sourceTree = "<group>"; };
16C7CC89147D4A4300776EAD /* GTMLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMLogger.m; sourceTree = "<group>"; };
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPMultipartUpload.h; sourceTree = "<group>"; };
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPMultipartUpload.m; sourceTree = "<group>"; };
16C7CC93147D4A4300776EAD /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_id.cc; sourceTree = "<group>"; };
16C7CC94147D4A4300776EAD /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_id.h; sourceTree = "<group>"; };
16C7CC95147D4A4300776EAD /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_id.cc; sourceTree = "<group>"; };
16C7CC96147D4A4300776EAD /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_id.h; sourceTree = "<group>"; };
16C7CC9A147D4A4300776EAD /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_utilities.cc; sourceTree = "<group>"; };
16C7CC9B147D4A4300776EAD /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_utilities.h; sourceTree = "<group>"; };
16C7CC9C147D4A4300776EAD /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_walker.cc; sourceTree = "<group>"; };
16C7CC9D147D4A4300776EAD /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_walker.h; sourceTree = "<group>"; };
16C7CC9F147D4A4300776EAD /* string_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_utilities.cc; sourceTree = "<group>"; };
16C7CCA0147D4A4300776EAD /* string_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_utilities.h; sourceTree = "<group>"; };
16C7CCA4147D4A4300776EAD /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = md5.cc; sourceTree = "<group>"; };
16C7CCA5147D4A4300776EAD /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = "<group>"; };
16C7CCB9147D4A4300776EAD /* string_conversion.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_conversion.cc; sourceTree = "<group>"; };
16C7CCBA147D4A4300776EAD /* string_conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_conversion.h; sourceTree = "<group>"; };
16C92FAB150DF8330053D7BA /* BreakpadController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BreakpadController.h; sourceTree = "<group>"; };
16C92FAC150DF8330053D7BA /* BreakpadController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BreakpadController.mm; sourceTree = "<group>"; };
1EEEB60C1720821900F7E689 /* simple_string_dictionary.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_string_dictionary.cc; sourceTree = "<group>"; };
1EEEB60D1720821900F7E689 /* simple_string_dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_string_dictionary.h; sourceTree = "<group>"; };
AA747D9E0F9514B9006C5449 /* Breakpad_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpad_Prefix.pch; sourceTree = SOURCE_ROOT; };
AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D2AAC07E0554694100DB518D /* libBreakpad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBreakpad.a; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D2AAC07C0554694100DB518D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
034768DFFF38A50411DB9C8B /* Products */ = {
isa = PBXGroup;
children = (
D2AAC07E0554694100DB518D /* libBreakpad.a */,
);
name = Products;
sourceTree = "<group>";
};
0867D691FE84028FC02AAC07 /* Breakpad */ = {
isa = PBXGroup;
children = (
08FB77AEFE84172EC02AAC07 /* Classes */,
32C88DFF0371C24200C91783 /* Other Sources */,
0867D69AFE84028FC02AAC07 /* Frameworks */,
034768DFFF38A50411DB9C8B /* Products */,
);
name = Breakpad;
sourceTree = "<group>";
};
0867D69AFE84028FC02AAC07 /* Frameworks */ = {
isa = PBXGroup;
children = (
AACBBE490F95108600F1A2B1 /* Foundation.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
08FB77AEFE84172EC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
16C7C965147D4A4200776EAD /* client */,
16C7CC47147D4A4300776EAD /* common */,
);
name = Classes;
sourceTree = "<group>";
};
16BFA66A14E195E9009704F8 /* handler */ = {
isa = PBXGroup;
children = (
16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */,
16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */,
);
path = handler;
sourceTree = "<group>";
};
16C7C965147D4A4200776EAD /* client */ = {
isa = PBXGroup;
children = (
16C7C966147D4A4200776EAD /* apple */,
16C7C969147D4A4200776EAD /* ios */,
16C7C99E147D4A4200776EAD /* mac */,
16C7CC04147D4A4300776EAD /* minidump_file_writer-inl.h */,
16C7CC05147D4A4300776EAD /* minidump_file_writer.cc */,
16C7CC06147D4A4300776EAD /* minidump_file_writer.h */,
16C7CC07147D4A4300776EAD /* minidump_file_writer_unittest.cc */,
);
name = client;
path = ..;
sourceTree = SOURCE_ROOT;
};
16C7C966147D4A4200776EAD /* apple */ = {
isa = PBXGroup;
children = (
16C7C967147D4A4200776EAD /* Framework */,
);
path = apple;
sourceTree = "<group>";
};
16C7C967147D4A4200776EAD /* Framework */ = {
isa = PBXGroup;
children = (
16C7C968147D4A4200776EAD /* BreakpadDefines.h */,
);
path = Framework;
sourceTree = "<group>";
};
16C7C969147D4A4200776EAD /* ios */ = {
isa = PBXGroup;
children = (
16C92FAB150DF8330053D7BA /* BreakpadController.h */,
16C92FAC150DF8330053D7BA /* BreakpadController.mm */,
16BFA66A14E195E9009704F8 /* handler */,
16C7C96A147D4A4200776EAD /* Breakpad.h */,
16C7C96B147D4A4200776EAD /* Breakpad.mm */,
);
path = ios;
sourceTree = "<group>";
};
16C7C99E147D4A4200776EAD /* mac */ = {
isa = PBXGroup;
children = (
16C7CB9D147D4A4300776EAD /* crash_generation */,
16C7CBAA147D4A4300776EAD /* handler */,
16C7CBC8147D4A4300776EAD /* sender */,
);
path = mac;
sourceTree = "<group>";
};
16C7CB9D147D4A4300776EAD /* crash_generation */ = {
isa = PBXGroup;
children = (
16C7CB9E147D4A4300776EAD /* ConfigFile.h */,
16C7CB9F147D4A4300776EAD /* ConfigFile.mm */,
);
path = crash_generation;
sourceTree = "<group>";
};
16C7CBAA147D4A4300776EAD /* handler */ = {
isa = PBXGroup;
children = (
16C7CBAD147D4A4300776EAD /* breakpad_nlist_64.cc */,
16C7CBAE147D4A4300776EAD /* breakpad_nlist_64.h */,
16C7CBAF147D4A4300776EAD /* dynamic_images.cc */,
16C7CBB0147D4A4300776EAD /* dynamic_images.h */,
16C7CBB1147D4A4300776EAD /* exception_handler.cc */,
16C7CBB2147D4A4300776EAD /* exception_handler.h */,
14569322182CE2C10029C465 /* mach_vm_compat.h */,
16C7CBB4147D4A4300776EAD /* minidump_generator.cc */,
16C7CBB5147D4A4300776EAD /* minidump_generator.h */,
16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */,
16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */,
14569320182CE29F0029C465 /* ucontext_compat.h */,
);
path = handler;
sourceTree = "<group>";
};
16C7CBC8147D4A4300776EAD /* sender */ = {
isa = PBXGroup;
children = (
16C7CBEA147D4A4300776EAD /* uploader.h */,
16C7CBEB147D4A4300776EAD /* uploader.mm */,
);
path = sender;
sourceTree = "<group>";
};
16C7CC47147D4A4300776EAD /* common */ = {
isa = PBXGroup;
children = (
1EEEB60C1720821900F7E689 /* simple_string_dictionary.cc */,
1EEEB60D1720821900F7E689 /* simple_string_dictionary.h */,
16C7CC4A147D4A4300776EAD /* convert_UTF.c */,
16C7CC4B147D4A4300776EAD /* convert_UTF.h */,
16C7CC82147D4A4300776EAD /* mac */,
16C7CCA4147D4A4300776EAD /* md5.cc */,
16C7CCA5147D4A4300776EAD /* md5.h */,
16C7CCB9147D4A4300776EAD /* string_conversion.cc */,
16C7CCBA147D4A4300776EAD /* string_conversion.h */,
);
name = common;
path = ../../common;
sourceTree = SOURCE_ROOT;
};
16C7CC82147D4A4300776EAD /* mac */ = {
isa = PBXGroup;
children = (
16C7CC88147D4A4300776EAD /* GTMLogger.h */,
16C7CC89147D4A4300776EAD /* GTMLogger.m */,
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */,
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */,
16C7CC93147D4A4300776EAD /* file_id.cc */,
16C7CC94147D4A4300776EAD /* file_id.h */,
16C7CC95147D4A4300776EAD /* macho_id.cc */,
16C7CC96147D4A4300776EAD /* macho_id.h */,
16C7CC9A147D4A4300776EAD /* macho_utilities.cc */,
16C7CC9B147D4A4300776EAD /* macho_utilities.h */,
16C7CC9C147D4A4300776EAD /* macho_walker.cc */,
16C7CC9D147D4A4300776EAD /* macho_walker.h */,
16C7CC9F147D4A4300776EAD /* string_utilities.cc */,
16C7CCA0147D4A4300776EAD /* string_utilities.h */,
);
path = mac;
sourceTree = "<group>";
};
32C88DFF0371C24200C91783 /* Other Sources */ = {
isa = PBXGroup;
children = (
AA747D9E0F9514B9006C5449 /* Breakpad_Prefix.pch */,
);
name = "Other Sources";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
D2AAC07A0554694100DB518D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
AA747D9F0F9514B9006C5449 /* Breakpad_Prefix.pch in Headers */,
16C7CCCB147D4A4300776EAD /* BreakpadDefines.h in Headers */,
16C7CCCC147D4A4300776EAD /* Breakpad.h in Headers */,
16C7CDE8147D4A4300776EAD /* ConfigFile.h in Headers */,
14569321182CE29F0029C465 /* ucontext_compat.h in Headers */,
16C7CDF6147D4A4300776EAD /* breakpad_nlist_64.h in Headers */,
16C7CDF8147D4A4300776EAD /* dynamic_images.h in Headers */,
16C7CDFA147D4A4300776EAD /* exception_handler.h in Headers */,
16C7CDFD147D4A4300776EAD /* minidump_generator.h in Headers */,
16C7CDFF147D4A4300776EAD /* protected_memory_allocator.h in Headers */,
16C7CE08147D4A4300776EAD /* uploader.h in Headers */,
16C7CE18147D4A4300776EAD /* minidump_file_writer-inl.h in Headers */,
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */,
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */,
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */,
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */,
16C7CE84147D4A4300776EAD /* file_id.h in Headers */,
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */,
16C7CE8B147D4A4300776EAD /* macho_utilities.h in Headers */,
16C7CE8D147D4A4300776EAD /* macho_walker.h in Headers */,
16C7CE90147D4A4300776EAD /* string_utilities.h in Headers */,
16C7CE94147D4A4300776EAD /* md5.h in Headers */,
16C7CEA8147D4A4300776EAD /* string_conversion.h in Headers */,
16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */,
16C92FAD150DF8330053D7BA /* BreakpadController.h in Headers */,
1EEEB6101720821900F7E689 /* simple_string_dictionary.h in Headers */,
14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
D2AAC07D0554694100DB518D /* Breakpad */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */;
buildPhases = (
D2AAC07A0554694100DB518D /* Headers */,
D2AAC07B0554694100DB518D /* Sources */,
D2AAC07C0554694100DB518D /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Breakpad;
productName = Breakpad;
productReference = D2AAC07E0554694100DB518D /* libBreakpad.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0510;
};
buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Breakpad" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German,
da,
de,
es,
fr,
it,
ja,
nl,
no,
sl,
sv,
tr,
);
mainGroup = 0867D691FE84028FC02AAC07 /* Breakpad */;
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D2AAC07D0554694100DB518D /* Breakpad */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
D2AAC07B0554694100DB518D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */,
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */,
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */,
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */,
16C7CDF9147D4A4300776EAD /* exception_handler.cc in Sources */,
16C7CDFC147D4A4300776EAD /* minidump_generator.cc in Sources */,
16C7CDFE147D4A4300776EAD /* protected_memory_allocator.cc in Sources */,
16C7CE09147D4A4300776EAD /* uploader.mm in Sources */,
16C7CE19147D4A4300776EAD /* minidump_file_writer.cc in Sources */,
16C7CE40147D4A4300776EAD /* convert_UTF.c in Sources */,
16C7CE79147D4A4300776EAD /* GTMLogger.m in Sources */,
16C7CE7B147D4A4300776EAD /* HTTPMultipartUpload.m in Sources */,
16C7CE83147D4A4300776EAD /* file_id.cc in Sources */,
16C7CE85147D4A4300776EAD /* macho_id.cc in Sources */,
16C7CE8A147D4A4300776EAD /* macho_utilities.cc in Sources */,
16C7CE8C147D4A4300776EAD /* macho_walker.cc in Sources */,
16C7CE8F147D4A4300776EAD /* string_utilities.cc in Sources */,
16C7CE93147D4A4300776EAD /* md5.cc in Sources */,
16C7CEA7147D4A4300776EAD /* string_conversion.cc in Sources */,
16BFA67214E1965A009704F8 /* ios_exception_minidump_generator.mm in Sources */,
16C92FAE150DF8330053D7BA /* BreakpadController.mm in Sources */,
1EEEB60F1720821900F7E689 /* simple_string_dictionary.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
1DEB921F08733DC00010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
DSTROOT = /tmp/Breakpad.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../mac/build/Debug\"",
);
GCC_DYNAMIC_NO_PIC = NO;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Breakpad_Prefix.pch;
INSTALL_PATH = /usr/local/lib;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Debug\"",
"\"$(SRCROOT)/../mac/gcov\"",
);
PRODUCT_NAME = Breakpad;
};
name = Debug;
};
1DEB922008733DC00010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
DSTROOT = /tmp/Breakpad.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../mac/build/Debug\"",
);
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Breakpad_Prefix.pch;
INSTALL_PATH = /usr/local/lib;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Debug\"",
"\"$(SRCROOT)/../mac/gcov\"",
);
PRODUCT_NAME = Breakpad;
};
name = Release;
};
1DEB922308733DC00010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
../../,
../../client/apple/Framework,
../../common/mac,
);
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC";
SDKROOT = iphoneos;
WARNING_CFLAGS = "-Wundef";
};
name = Debug;
};
1DEB922408733DC00010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
../../,
../../client/apple/Framework,
../../common/mac,
);
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
OTHER_LDFLAGS = "-ObjC";
SDKROOT = iphoneos;
WARNING_CFLAGS = "-Wundef";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB921F08733DC00010E9CD /* Debug */,
1DEB922008733DC00010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Breakpad" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB922308733DC00010E9CD /* Debug */,
1DEB922408733DC00010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
}

View File

@ -1,141 +0,0 @@
// Copyright (c) 2012, 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.
#ifndef CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_
#define CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_
#import <Foundation/Foundation.h>
#import "client/ios/Breakpad.h"
// This class is used to offer a higher level API around BreakpadRef. It
// configures it, ensures thread-safety, and sends crash reports back to the
// collecting server. By default, no crash reports are sent, the user must call
// |setUploadingEnabled:YES| to start the uploading.
@interface BreakpadController : NSObject {
@private
// The dispatch queue that will own the breakpad reference.
dispatch_queue_t queue_;
// Instance of Breakpad crash reporter. This is owned by the queue, but can
// be created on the main thread at startup.
BreakpadRef breakpadRef_;
// The dictionary that contains configuration for breakpad. Modifying it
// should only happen when the controller is not started. The initial value
// is the infoDictionary of the bundle of the application.
NSMutableDictionary* configuration_;
// Whether or not crash reports should be uploaded.
BOOL enableUploads_;
// Whether the controller has been started on the main thread. This is only
// used to assert the initialization order is correct.
BOOL started_;
// The interval to wait between two uploads. Value is 0 if no upload must be
// done.
int uploadIntervalInSeconds_;
// The dictionary that contains additional server parameters to send when
// uploading crash reports.
NSDictionary* uploadTimeParameters_;
}
// Singleton.
+ (BreakpadController*)sharedInstance;
// Update the controller configuration. Merges its old configuration with the
// new one. Merge is done by replacing the old values by the new values.
- (void)updateConfiguration:(NSDictionary*)configuration;
// Reset the controller configuration to its initial value, which is the
// infoDictionary of the bundle of the application.
- (void)resetConfiguration;
// Configure the URL to upload the report to. This must be called at least once
// if the URL is not in the bundle information.
- (void)setUploadingURL:(NSString*)url;
// Set the minimal interval between two uploads in seconds. This must be called
// at least once if the interval is not in the bundle information. A value of 0
// will prevent uploads.
- (void)setUploadInterval:(int)intervalInSeconds;
// Set additional server parameters to send when uploading crash reports.
- (void)setParametersToAddAtUploadTime:(NSDictionary*)uploadTimeParameters;
// Specify an upload parameter that will be added to the crash report when a
// crash report is generated. See |BreakpadAddUploadParameter|.
- (void)addUploadParameter:(NSString*)value forKey:(NSString*)key;
// Remove a previously-added parameter from the upload parameter set. See
// |BreakpadRemoveUploadParameter|.
- (void)removeUploadParameterForKey:(NSString*)key;
// Access the underlying BreakpadRef. This method is asynchronous, and will be
// executed on the thread owning the BreakpadRef variable. Moreover, if the
// controller is not started, the block will be called with a NULL parameter.
- (void)withBreakpadRef:(void(^)(BreakpadRef))callback;
// Starts the BreakpadController by registering crash handlers. If
// |onCurrentThread| is YES, all setup is done on the current thread, otherwise
// it is done on a private queue.
- (void)start:(BOOL)onCurrentThread;
// Unregisters the crash handlers.
- (void)stop;
// Enables or disables uploading of crash reports, but does not stop the
// BreakpadController.
- (void)setUploadingEnabled:(BOOL)enabled;
// Check if there is currently a crash report to upload.
- (void)hasReportToUpload:(void(^)(BOOL))callback;
// Get the number of crash reports waiting to upload.
- (void)getCrashReportCount:(void(^)(int))callback;
// Get the next report to upload.
// - If upload is disabled, callback will be called with (nil, -1).
// - If a delay is to be waited before sending, callback will be called with
// (nil, n), with n (> 0) being the number of seconds to wait.
// - if no delay is needed, callback will be called with (0, configuration),
// configuration being next report to upload, or nil if none is pending.
- (void)getNextReportConfigurationOrSendDelay:
(void(^)(NSDictionary*, int))callback;
// Sends synchronously the report specified by |configuration|. This method is
// NOT thread safe and must be called from the breakpad thread.
- (void)threadUnsafeSendReportWithConfiguration:(NSDictionary*)configuration
withBreakpadRef:(BreakpadRef)ref;
@end
#endif // CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_

View File

@ -1,354 +0,0 @@
// Copyright (c) 2012, 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.
#import "BreakpadController.h"
#import <UIKit/UIKit.h>
#include <asl.h>
#include <execinfo.h>
#include <signal.h>
#include <unistd.h>
#include <sys/sysctl.h>
#include <common/scoped_ptr.h>
#pragma mark -
#pragma mark Private Methods
@interface BreakpadController ()
// Init the singleton instance.
- (id)initSingleton;
// Load a crash report and send it to the server.
- (void)sendStoredCrashReports;
// Returns when a report can be sent. |-1| means never, |0| means that a report
// can be sent immediately, a positive number is the number of seconds to wait
// before being allowed to upload a report.
- (int)sendDelay;
// Notifies that a report will be sent, and update the last sending time
// accordingly.
- (void)reportWillBeSent;
@end
#pragma mark -
#pragma mark Anonymous namespace
namespace {
// The name of the user defaults key for the last submission to the crash
// server.
NSString* const kLastSubmission = @"com.google.Breakpad.LastSubmission";
// Returns a NSString describing the current platform.
NSString* GetPlatform() {
// Name of the system call for getting the platform.
static const char kHwMachineSysctlName[] = "hw.machine";
NSString* result = nil;
size_t size = 0;
if (sysctlbyname(kHwMachineSysctlName, NULL, &size, NULL, 0) || size == 0)
return nil;
google_breakpad::scoped_array<char> machine(new char[size]);
if (sysctlbyname(kHwMachineSysctlName, machine.get(), &size, NULL, 0) == 0)
result = [NSString stringWithUTF8String:machine.get()];
return result;
}
} // namespace
#pragma mark -
#pragma mark BreakpadController Implementation
@implementation BreakpadController
+ (BreakpadController*)sharedInstance {
@synchronized(self) {
static BreakpadController* sharedInstance_ =
[[BreakpadController alloc] initSingleton];
return sharedInstance_;
}
}
- (id)init {
return nil;
}
- (id)initSingleton {
self = [super init];
if (self) {
queue_ = dispatch_queue_create("com.google.BreakpadQueue", NULL);
enableUploads_ = NO;
started_ = NO;
[self resetConfiguration];
}
return self;
}
// Since this class is a singleton, this method is not expected to be called.
- (void)dealloc {
assert(!breakpadRef_);
dispatch_release(queue_);
[configuration_ release];
[uploadTimeParameters_ release];
[super dealloc];
}
#pragma mark -
- (void)start:(BOOL)onCurrentThread {
if (started_)
return;
started_ = YES;
void(^startBlock)() = ^{
assert(!breakpadRef_);
breakpadRef_ = BreakpadCreate(configuration_);
if (breakpadRef_) {
BreakpadAddUploadParameter(breakpadRef_, @"platform", GetPlatform());
}
};
if (onCurrentThread)
startBlock();
else
dispatch_async(queue_, startBlock);
}
- (void)stop {
if (!started_)
return;
started_ = NO;
dispatch_sync(queue_, ^{
if (breakpadRef_) {
BreakpadRelease(breakpadRef_);
breakpadRef_ = NULL;
}
});
}
// This method must be called from the breakpad queue.
- (void)threadUnsafeSendReportWithConfiguration:(NSDictionary*)configuration
withBreakpadRef:(BreakpadRef)ref {
NSAssert(started_, @"The controller must be started before "
"threadUnsafeSendReportWithConfiguration is called");
if (breakpadRef_) {
BreakpadUploadReportWithParametersAndConfiguration(breakpadRef_,
uploadTimeParameters_,
configuration);
}
}
- (void)setUploadingEnabled:(BOOL)enabled {
NSAssert(started_,
@"The controller must be started before setUploadingEnabled is called");
dispatch_async(queue_, ^{
if (enabled == enableUploads_)
return;
if (enabled) {
// Set this before calling doSendStoredCrashReport, because that
// calls sendDelay, which in turn checks this flag.
enableUploads_ = YES;
[self sendStoredCrashReports];
} else {
enableUploads_ = NO;
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(sendStoredCrashReports)
object:nil];
}
});
}
- (void)updateConfiguration:(NSDictionary*)configuration {
NSAssert(!started_,
@"The controller must not be started when updateConfiguration is called");
[configuration_ addEntriesFromDictionary:configuration];
NSString* uploadInterval =
[configuration_ valueForKey:@BREAKPAD_REPORT_INTERVAL];
if (uploadInterval)
[self setUploadInterval:[uploadInterval intValue]];
}
- (void)resetConfiguration {
NSAssert(!started_,
@"The controller must not be started when resetConfiguration is called");
[configuration_ autorelease];
configuration_ = [[[NSBundle mainBundle] infoDictionary] mutableCopy];
NSString* uploadInterval =
[configuration_ valueForKey:@BREAKPAD_REPORT_INTERVAL];
[self setUploadInterval:[uploadInterval intValue]];
[self setParametersToAddAtUploadTime:nil];
}
- (void)setUploadingURL:(NSString*)url {
NSAssert(!started_,
@"The controller must not be started when setUploadingURL is called");
[configuration_ setValue:url forKey:@BREAKPAD_URL];
}
- (void)setUploadInterval:(int)intervalInSeconds {
NSAssert(!started_,
@"The controller must not be started when setUploadInterval is called");
[configuration_ removeObjectForKey:@BREAKPAD_REPORT_INTERVAL];
uploadIntervalInSeconds_ = intervalInSeconds;
if (uploadIntervalInSeconds_ < 0)
uploadIntervalInSeconds_ = 0;
}
- (void)setParametersToAddAtUploadTime:(NSDictionary*)uploadTimeParameters {
NSAssert(!started_, @"The controller must not be started when "
"setParametersToAddAtUploadTime is called");
[uploadTimeParameters_ autorelease];
uploadTimeParameters_ = [uploadTimeParameters copy];
}
- (void)addUploadParameter:(NSString*)value forKey:(NSString*)key {
NSAssert(started_,
@"The controller must be started before addUploadParameter is called");
dispatch_async(queue_, ^{
if (breakpadRef_)
BreakpadAddUploadParameter(breakpadRef_, key, value);
});
}
- (void)removeUploadParameterForKey:(NSString*)key {
NSAssert(started_, @"The controller must be started before "
"removeUploadParameterForKey is called");
dispatch_async(queue_, ^{
if (breakpadRef_)
BreakpadRemoveUploadParameter(breakpadRef_, key);
});
}
- (void)withBreakpadRef:(void(^)(BreakpadRef))callback {
NSAssert(started_,
@"The controller must be started before withBreakpadRef is called");
dispatch_async(queue_, ^{
callback(breakpadRef_);
});
}
- (void)hasReportToUpload:(void(^)(BOOL))callback {
NSAssert(started_, @"The controller must be started before "
"hasReportToUpload is called");
dispatch_async(queue_, ^{
callback(breakpadRef_ && (BreakpadGetCrashReportCount(breakpadRef_) > 0));
});
}
- (void)getCrashReportCount:(void(^)(int))callback {
NSAssert(started_, @"The controller must be started before "
"getCrashReportCount is called");
dispatch_async(queue_, ^{
callback(breakpadRef_ ? BreakpadGetCrashReportCount(breakpadRef_) : 0);
});
}
- (void)getNextReportConfigurationOrSendDelay:
(void(^)(NSDictionary*, int))callback {
NSAssert(started_, @"The controller must be started before "
"getNextReportConfigurationOrSendDelay is called");
dispatch_async(queue_, ^{
if (!breakpadRef_) {
callback(nil, -1);
return;
}
int delay = [self sendDelay];
if (delay != 0) {
callback(nil, delay);
return;
}
[self reportWillBeSent];
callback(BreakpadGetNextReportConfiguration(breakpadRef_), 0);
});
}
#pragma mark -
- (int)sendDelay {
if (!breakpadRef_ || uploadIntervalInSeconds_ <= 0 || !enableUploads_)
return -1;
// To prevent overloading the crash server, crashes are not sent than one
// report every |uploadIntervalInSeconds_|. A value in the user defaults is
// used to keep the time of the last upload.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSNumber *lastTimeNum = [userDefaults objectForKey:kLastSubmission];
NSTimeInterval lastTime = lastTimeNum ? [lastTimeNum floatValue] : 0;
NSTimeInterval spanSeconds = CFAbsoluteTimeGetCurrent() - lastTime;
if (spanSeconds >= uploadIntervalInSeconds_)
return 0;
return uploadIntervalInSeconds_ - static_cast<int>(spanSeconds);
}
- (void)reportWillBeSent {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[NSNumber numberWithDouble:CFAbsoluteTimeGetCurrent()]
forKey:kLastSubmission];
[userDefaults synchronize];
}
- (void)sendStoredCrashReports {
dispatch_async(queue_, ^{
if (BreakpadGetCrashReportCount(breakpadRef_) == 0)
return;
int timeToWait = [self sendDelay];
// Unable to ever send report.
if (timeToWait == -1)
return;
// A report can be sent now.
if (timeToWait == 0) {
[self reportWillBeSent];
BreakpadUploadNextReportWithParameters(breakpadRef_,
uploadTimeParameters_);
// If more reports must be sent, make sure this method is called again.
if (BreakpadGetCrashReportCount(breakpadRef_) > 0)
timeToWait = uploadIntervalInSeconds_;
}
// A report must be sent later.
if (timeToWait > 0) {
// performSelector: doesn't work on queue_
dispatch_async(dispatch_get_main_queue(), ^{
[self performSelector:@selector(sendStoredCrashReports)
withObject:nil
afterDelay:timeToWait];
});
}
});
}
@end

View File

@ -1,7 +0,0 @@
//
// Prefix header for all source files of the 'CocoaTouchStaticLibrary' target in the 'CocoaTouchStaticLibrary' project.
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif

View File

@ -1,74 +0,0 @@
// Copyright (c) 2012, 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.
// ios_exception_minidump_generator.h: Create a fake minidump from a
// NSException.
#ifndef CLIENT_IOS_HANDLER_IOS_EXCEPTION_MINIDUMP_GENERATOR_H_
#define CLIENT_IOS_HANDLER_IOS_EXCEPTION_MINIDUMP_GENERATOR_H_
#include <Foundation/Foundation.h>
#include "client/mac/handler/minidump_generator.h"
namespace google_breakpad {
class IosExceptionMinidumpGenerator : public MinidumpGenerator {
public:
explicit IosExceptionMinidumpGenerator(NSException *exception);
virtual ~IosExceptionMinidumpGenerator();
protected:
virtual bool WriteExceptionStream(MDRawDirectory *exception_stream);
virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread);
private:
// Get the crashing program counter from the exception.
uintptr_t GetPCFromException();
// Get the crashing link register from the exception.
uintptr_t GetLRFromException();
// Write a virtual thread context for the crashing site.
bool WriteCrashingContext(MDLocationDescriptor *register_location);
// Per-CPU implementations of the above method.
#ifdef HAS_ARM_SUPPORT
bool WriteCrashingContextARM(MDLocationDescriptor *register_location);
#endif
#ifdef HAS_ARM64_SUPPORT
bool WriteCrashingContextARM64(MDLocationDescriptor *register_location);
#endif
NSArray *return_addresses_;
};
} // namespace google_breakpad
#endif // CLIENT_IOS_HANDLER_IOS_EXCEPTION_MINIDUMP_GENERATOR_H_

View File

@ -1,210 +0,0 @@
// Copyright (c) 2012, 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.
#include "client/ios/handler/ios_exception_minidump_generator.h"
#include <pthread.h>
#include "google_breakpad/common/minidump_cpu_arm.h"
#include "google_breakpad/common/minidump_cpu_arm64.h"
#include "google_breakpad/common/minidump_exception_mac.h"
#include "client/minidump_file_writer-inl.h"
#include "common/scoped_ptr.h"
#if defined(HAS_ARM_SUPPORT) && defined(HAS_ARM64_SUPPORT)
#error "This file should be compiled for only one architecture at a time"
#endif
namespace {
const int kExceptionType = EXC_SOFTWARE;
const int kExceptionCode = MD_EXCEPTION_CODE_MAC_NS_EXCEPTION;
#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT)
const uintptr_t kExpectedFinalFp = sizeof(uintptr_t);
const uintptr_t kExpectedFinalSp = 0;
// Append the given value to the sp position of the stack represented
// by memory.
void AppendToMemory(uint8_t *memory, uintptr_t sp, uintptr_t data) {
memcpy(memory + sp, &data, sizeof(data));
}
#endif
} // namespace
namespace google_breakpad {
IosExceptionMinidumpGenerator::IosExceptionMinidumpGenerator(
NSException *exception)
: MinidumpGenerator(mach_task_self(), 0) {
return_addresses_ = [[exception callStackReturnAddresses] retain];
SetExceptionInformation(kExceptionType,
kExceptionCode,
0,
pthread_mach_thread_np(pthread_self()));
}
IosExceptionMinidumpGenerator::~IosExceptionMinidumpGenerator() {
[return_addresses_ release];
}
bool IosExceptionMinidumpGenerator::WriteCrashingContext(
MDLocationDescriptor *register_location) {
#ifdef HAS_ARM_SUPPORT
return WriteCrashingContextARM(register_location);
#elif defined(HAS_ARM64_SUPPORT)
return WriteCrashingContextARM64(register_location);
#else
assert(false);
return false;
#endif
}
#ifdef HAS_ARM_SUPPORT
bool IosExceptionMinidumpGenerator::WriteCrashingContextARM(
MDLocationDescriptor *register_location) {
TypedMDRVA<MDRawContextARM> context(&writer_);
if (!context.Allocate())
return false;
*register_location = context.location();
MDRawContextARM *context_ptr = context.get();
memset(context_ptr, 0, sizeof(MDRawContextARM));
context_ptr->context_flags = MD_CONTEXT_ARM_FULL;
context_ptr->iregs[MD_CONTEXT_ARM_REG_IOS_FP] = kExpectedFinalFp; // FP
context_ptr->iregs[MD_CONTEXT_ARM_REG_SP] = kExpectedFinalSp; // SP
context_ptr->iregs[MD_CONTEXT_ARM_REG_LR] = GetLRFromException(); // LR
context_ptr->iregs[MD_CONTEXT_ARM_REG_PC] = GetPCFromException(); // PC
return true;
}
#endif
#ifdef HAS_ARM64_SUPPORT
bool IosExceptionMinidumpGenerator::WriteCrashingContextARM64(
MDLocationDescriptor *register_location) {
TypedMDRVA<MDRawContextARM64> context(&writer_);
if (!context.Allocate())
return false;
*register_location = context.location();
MDRawContextARM64 *context_ptr = context.get();
memset(context_ptr, 0, sizeof(*context_ptr));
context_ptr->context_flags = MD_CONTEXT_ARM64_FULL;
context_ptr->iregs[MD_CONTEXT_ARM64_REG_FP] = kExpectedFinalFp; // FP
context_ptr->iregs[MD_CONTEXT_ARM64_REG_SP] = kExpectedFinalSp; // SP
context_ptr->iregs[MD_CONTEXT_ARM64_REG_LR] = GetLRFromException(); // LR
context_ptr->iregs[MD_CONTEXT_ARM64_REG_PC] = GetPCFromException(); // PC
return true;
}
#endif
uintptr_t IosExceptionMinidumpGenerator::GetPCFromException() {
return [[return_addresses_ objectAtIndex:0] unsignedIntegerValue];
}
uintptr_t IosExceptionMinidumpGenerator::GetLRFromException() {
return [[return_addresses_ objectAtIndex:1] unsignedIntegerValue];
}
bool IosExceptionMinidumpGenerator::WriteExceptionStream(
MDRawDirectory *exception_stream) {
#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT)
TypedMDRVA<MDRawExceptionStream> exception(&writer_);
if (!exception.Allocate())
return false;
exception_stream->stream_type = MD_EXCEPTION_STREAM;
exception_stream->location = exception.location();
MDRawExceptionStream *exception_ptr = exception.get();
exception_ptr->thread_id = pthread_mach_thread_np(pthread_self());
// This naming is confusing, but it is the proper translation from
// mach naming to minidump naming.
exception_ptr->exception_record.exception_code = kExceptionType;
exception_ptr->exception_record.exception_flags = kExceptionCode;
if (!WriteCrashingContext(&exception_ptr->thread_context))
return false;
exception_ptr->exception_record.exception_address = GetPCFromException();
return true;
#else
return MinidumpGenerator::WriteExceptionStream(exception_stream);
#endif
}
bool IosExceptionMinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
MDRawThread *thread) {
#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT)
if (pthread_mach_thread_np(pthread_self()) != thread_id)
return MinidumpGenerator::WriteThreadStream(thread_id, thread);
size_t frame_count = [return_addresses_ count];
if (frame_count == 0)
return false;
UntypedMDRVA memory(&writer_);
size_t pointer_size = sizeof(uintptr_t);
size_t frame_record_size = 2 * pointer_size;
size_t stack_size = frame_record_size * (frame_count - 1) + pointer_size;
if (!memory.Allocate(stack_size))
return false;
scoped_array<uint8_t> stack_memory(new uint8_t[stack_size]);
uintptr_t sp = stack_size - pointer_size;
uintptr_t fp = 0;
uintptr_t lr = 0;
for (size_t current_frame = frame_count - 1;
current_frame > 0;
--current_frame) {
AppendToMemory(stack_memory.get(), sp, lr);
sp -= pointer_size;
AppendToMemory(stack_memory.get(), sp, fp);
fp = sp;
sp -= pointer_size;
lr = [[return_addresses_ objectAtIndex:current_frame] unsignedIntegerValue];
}
if (!memory.Copy(stack_memory.get(), stack_size))
return false;
assert(sp == kExpectedFinalSp);
assert(fp == kExpectedFinalFp);
assert(lr == GetLRFromException());
thread->stack.start_of_memory_range = sp;
thread->stack.memory = memory.location();
memory_blocks_.push_back(thread->stack);
if (!WriteCrashingContext(&thread->thread_context))
return false;
thread->thread_id = thread_id;
return true;
#else
return MinidumpGenerator::WriteThreadStream(thread_id, thread);
#endif
}
} // namespace google_breakpad

View File

@ -1,53 +0,0 @@
// Copyright (c) 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.
#ifndef CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
#define CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
namespace google_breakpad {
class CrashGenerationServer;
class ClientInfo {
public:
ClientInfo(pid_t pid, CrashGenerationServer* crash_server)
: crash_server_(crash_server),
pid_(pid) {}
CrashGenerationServer* crash_server() const { return crash_server_; }
pid_t pid() const { return pid_; }
private:
CrashGenerationServer* crash_server_;
pid_t pid_;
};
}
#endif // CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_

Some files were not shown because too many files have changed in this diff Show More