Remove crashreporter toolkit files.
This commit is contained in:
parent
b2628357b3
commit
e26c5e1e50
|
@ -70,7 +70,6 @@ IPDL_SOURCES = [
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
'/dom/ipc',
|
'/dom/ipc',
|
||||||
'/toolkit/crashreporter',
|
|
||||||
'/xpcom/threads',
|
'/xpcom/threads',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,6 @@ IPDL_SOURCES = [
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
'/dom/ipc',
|
'/dom/ipc',
|
||||||
'/toolkit/crashreporter',
|
|
||||||
'/toolkit/xre',
|
'/toolkit/xre',
|
||||||
'/xpcom/threads',
|
'/xpcom/threads',
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = [
|
|
||||||
"CrashReports"
|
|
||||||
];
|
|
||||||
|
|
||||||
this.CrashReports = {
|
|
||||||
pendingDir: null,
|
|
||||||
reportsDir: null,
|
|
||||||
submittedDir: null,
|
|
||||||
getReports: function CrashReports_getReports()
|
|
||||||
{
|
|
||||||
let reports = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Ignore any non http/https urls
|
|
||||||
if (!/^https?:/i.test(Services.prefs.getCharPref("breakpad.reportURL")))
|
|
||||||
return reports;
|
|
||||||
}
|
|
||||||
catch (e) { }
|
|
||||||
|
|
||||||
if (this.submittedDir.exists() && this.submittedDir.isDirectory()) {
|
|
||||||
let entries = this.submittedDir.directoryEntries;
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
let file = entries.getNext().QueryInterface(Components.interfaces.nsIFile);
|
|
||||||
let leaf = file.leafName;
|
|
||||||
if (leaf.startsWith("bp-") &&
|
|
||||||
leaf.endsWith(".txt")) {
|
|
||||||
let entry = {
|
|
||||||
id: leaf.slice(0, -4),
|
|
||||||
date: file.lastModifiedTime,
|
|
||||||
pending: false
|
|
||||||
};
|
|
||||||
reports.push(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.pendingDir.exists() && this.pendingDir.isDirectory()) {
|
|
||||||
let uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
||||||
let entries = this.pendingDir.directoryEntries;
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
let file = entries.getNext().QueryInterface(Components.interfaces.nsIFile);
|
|
||||||
let leaf = file.leafName;
|
|
||||||
let id = leaf.slice(0, -4);
|
|
||||||
if (leaf.endsWith(".dmp") && uuidRegex.test(id)) {
|
|
||||||
let entry = {
|
|
||||||
id: id,
|
|
||||||
date: file.lastModifiedTime,
|
|
||||||
pending: true
|
|
||||||
};
|
|
||||||
reports.push(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort reports descending by date
|
|
||||||
return reports.sort( (a, b) => b.date - a.date);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function CrashReports_pendingDir()
|
|
||||||
{
|
|
||||||
let pendingDir = Services.dirsvc.get("UAppData", Components.interfaces.nsIFile);
|
|
||||||
pendingDir.append("Crash Reports");
|
|
||||||
pendingDir.append("pending");
|
|
||||||
return pendingDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
function CrashReports_reportsDir()
|
|
||||||
{
|
|
||||||
let reportsDir = Services.dirsvc.get("UAppData", Components.interfaces.nsIFile);
|
|
||||||
reportsDir.append("Crash Reports");
|
|
||||||
return reportsDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
function CrashReports_submittedDir()
|
|
||||||
{
|
|
||||||
let submittedDir = Services.dirsvc.get("UAppData", Components.interfaces.nsIFile);
|
|
||||||
submittedDir.append("Crash Reports");
|
|
||||||
submittedDir.append("submitted");
|
|
||||||
return submittedDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.CrashReports.pendingDir = CrashReports_pendingDir();
|
|
||||||
this.CrashReports.reportsDir = CrashReports_reportsDir();
|
|
||||||
this.CrashReports.submittedDir = CrashReports_submittedDir();
|
|
|
@ -1,570 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
|
||||||
Cu.import("resource://gre/modules/KeyValueParser.jsm");
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
Cu.importGlobalProperties(['File']);
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
|
|
||||||
"resource://gre/modules/PromiseUtils.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
|
||||||
"resource://gre/modules/osfile.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
|
||||||
"resource://gre/modules/Task.jsm");
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = [
|
|
||||||
"CrashSubmit"
|
|
||||||
];
|
|
||||||
|
|
||||||
const STATE_START = Ci.nsIWebProgressListener.STATE_START;
|
|
||||||
const STATE_STOP = Ci.nsIWebProgressListener.STATE_STOP;
|
|
||||||
|
|
||||||
const SUCCESS = "success";
|
|
||||||
const FAILED = "failed";
|
|
||||||
const SUBMITTING = "submitting";
|
|
||||||
|
|
||||||
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
||||||
|
|
||||||
function parseINIStrings(file) {
|
|
||||||
var factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
|
|
||||||
getService(Ci.nsIINIParserFactory);
|
|
||||||
var parser = factory.createINIParser(file);
|
|
||||||
var obj = {};
|
|
||||||
var en = parser.getKeys("Strings");
|
|
||||||
while (en.hasMore()) {
|
|
||||||
var key = en.getNext();
|
|
||||||
obj[key] = parser.getString("Strings", key);
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we're basically re-implementing part of the crashreporter
|
|
||||||
// client here, we'll just steal the strings we need from crashreporter.ini
|
|
||||||
function getL10nStrings() {
|
|
||||||
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
|
||||||
getService(Ci.nsIProperties);
|
|
||||||
let path = dirSvc.get("GreD", Ci.nsIFile);
|
|
||||||
path.append("crashreporter.ini");
|
|
||||||
if (!path.exists()) {
|
|
||||||
// see if we're on a mac
|
|
||||||
path = path.parent;
|
|
||||||
path = path.parent;
|
|
||||||
path.append("MacOS");
|
|
||||||
path.append("crashreporter.app");
|
|
||||||
path.append("Contents");
|
|
||||||
path.append("Resources");
|
|
||||||
path.append("crashreporter.ini");
|
|
||||||
if (!path.exists()) {
|
|
||||||
// very bad, but I don't know how to recover
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let crstrings = parseINIStrings(path);
|
|
||||||
let strings = {
|
|
||||||
'crashid': crstrings.CrashID,
|
|
||||||
'reporturl': crstrings.CrashDetailsURL
|
|
||||||
};
|
|
||||||
|
|
||||||
path = dirSvc.get("XCurProcD", Ci.nsIFile);
|
|
||||||
path.append("crashreporter-override.ini");
|
|
||||||
if (path.exists()) {
|
|
||||||
crstrings = parseINIStrings(path);
|
|
||||||
if ('CrashID' in crstrings)
|
|
||||||
strings['crashid'] = crstrings.CrashID;
|
|
||||||
if ('CrashDetailsURL' in crstrings)
|
|
||||||
strings['reporturl'] = crstrings.CrashDetailsURL;
|
|
||||||
}
|
|
||||||
return strings;
|
|
||||||
}
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "strings", getL10nStrings);
|
|
||||||
|
|
||||||
function getDir(name) {
|
|
||||||
let directoryService = Cc["@mozilla.org/file/directory_service;1"].
|
|
||||||
getService(Ci.nsIProperties);
|
|
||||||
let dir = directoryService.get("UAppData", Ci.nsIFile);
|
|
||||||
dir.append("Crash Reports");
|
|
||||||
dir.append(name);
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeFile(dirName, fileName, data) {
|
|
||||||
let path = getDir(dirName);
|
|
||||||
if (!path.exists())
|
|
||||||
path.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0700', 8));
|
|
||||||
path.append(fileName);
|
|
||||||
var fs = Cc["@mozilla.org/network/file-output-stream;1"].
|
|
||||||
createInstance(Ci.nsIFileOutputStream);
|
|
||||||
// open, write, truncate
|
|
||||||
fs.init(path, -1, -1, 0);
|
|
||||||
var os = Cc["@mozilla.org/intl/converter-output-stream;1"].
|
|
||||||
createInstance(Ci.nsIConverterOutputStream);
|
|
||||||
os.init(fs, "UTF-8", 0, 0x0000);
|
|
||||||
os.writeString(data);
|
|
||||||
os.close();
|
|
||||||
fs.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPendingMinidump(id) {
|
|
||||||
let pendingDir = getDir("pending");
|
|
||||||
let dump = pendingDir.clone();
|
|
||||||
let extra = pendingDir.clone();
|
|
||||||
let memory = pendingDir.clone();
|
|
||||||
dump.append(id + ".dmp");
|
|
||||||
extra.append(id + ".extra");
|
|
||||||
memory.append(id + ".memory.json.gz");
|
|
||||||
return [dump, extra, memory];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAllPendingMinidumpsIDs() {
|
|
||||||
let minidumps = [];
|
|
||||||
let pendingDir = getDir("pending");
|
|
||||||
|
|
||||||
if (!(pendingDir.exists() && pendingDir.isDirectory()))
|
|
||||||
return [];
|
|
||||||
let entries = pendingDir.directoryEntries;
|
|
||||||
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
|
||||||
if (entry.isFile()) {
|
|
||||||
let matches = entry.leafName.match(/(.+)\.extra$/);
|
|
||||||
if (matches)
|
|
||||||
minidumps.push(matches[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return minidumps;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pruneSavedDumps() {
|
|
||||||
const KEEP = 10;
|
|
||||||
|
|
||||||
let pendingDir = getDir("pending");
|
|
||||||
if (!(pendingDir.exists() && pendingDir.isDirectory()))
|
|
||||||
return;
|
|
||||||
let entries = pendingDir.directoryEntries;
|
|
||||||
let entriesArray = [];
|
|
||||||
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
|
||||||
if (entry.isFile()) {
|
|
||||||
let matches = entry.leafName.match(/(.+)\.extra$/);
|
|
||||||
if (matches)
|
|
||||||
entriesArray.push(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entriesArray.sort(function(a, b) {
|
|
||||||
let dateA = a.lastModifiedTime;
|
|
||||||
let dateB = b.lastModifiedTime;
|
|
||||||
if (dateA < dateB)
|
|
||||||
return -1;
|
|
||||||
if (dateB < dateA)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (entriesArray.length > KEEP) {
|
|
||||||
for (let i = 0; i < entriesArray.length - KEEP; ++i) {
|
|
||||||
let extra = entriesArray[i];
|
|
||||||
let matches = extra.leafName.match(/(.+)\.extra$/);
|
|
||||||
if (matches) {
|
|
||||||
let dump = extra.clone();
|
|
||||||
dump.leafName = matches[1] + '.dmp';
|
|
||||||
dump.remove(false);
|
|
||||||
|
|
||||||
let memory = extra.clone();
|
|
||||||
memory.leafName = matches[1] + '.memory.json.gz';
|
|
||||||
if (memory.exists()) {
|
|
||||||
memory.remove(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
extra.remove(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addFormEntry(doc, form, name, value) {
|
|
||||||
var input = doc.createElement("input");
|
|
||||||
input.type = "hidden";
|
|
||||||
input.name = name;
|
|
||||||
input.value = value;
|
|
||||||
form.appendChild(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeSubmittedReport(crashID, viewURL) {
|
|
||||||
var data = strings.crashid.replace("%s", crashID);
|
|
||||||
if (viewURL)
|
|
||||||
data += "\n" + strings.reporturl.replace("%s", viewURL);
|
|
||||||
|
|
||||||
writeFile("submitted", crashID + ".txt", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the Submitter class represents an individual submission.
|
|
||||||
function Submitter(id, recordSubmission, noThrottle, extraExtraKeyVals) {
|
|
||||||
this.id = id;
|
|
||||||
this.recordSubmission = recordSubmission;
|
|
||||||
this.noThrottle = noThrottle;
|
|
||||||
this.additionalDumps = [];
|
|
||||||
this.extraKeyVals = extraExtraKeyVals || {};
|
|
||||||
this.deferredSubmit = PromiseUtils.defer();
|
|
||||||
}
|
|
||||||
|
|
||||||
Submitter.prototype = {
|
|
||||||
submitSuccess: function Submitter_submitSuccess(ret)
|
|
||||||
{
|
|
||||||
// Write out the details file to submitted/
|
|
||||||
writeSubmittedReport(ret.CrashID, ret.ViewURL);
|
|
||||||
|
|
||||||
// Delete from pending dir
|
|
||||||
try {
|
|
||||||
this.dump.remove(false);
|
|
||||||
this.extra.remove(false);
|
|
||||||
|
|
||||||
if (this.memory) {
|
|
||||||
this.memory.remove(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i of this.additionalDumps) {
|
|
||||||
i.dump.remove(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ex) {
|
|
||||||
// report an error? not much the user can do here.
|
|
||||||
}
|
|
||||||
|
|
||||||
this.notifyStatus(SUCCESS, ret);
|
|
||||||
this.cleanup();
|
|
||||||
},
|
|
||||||
|
|
||||||
cleanup: function Submitter_cleanup() {
|
|
||||||
// drop some references just to be nice
|
|
||||||
this.iframe = null;
|
|
||||||
this.dump = null;
|
|
||||||
this.extra = null;
|
|
||||||
this.memory = null;
|
|
||||||
this.additionalDumps = null;
|
|
||||||
// remove this object from the list of active submissions
|
|
||||||
let idx = CrashSubmit._activeSubmissions.indexOf(this);
|
|
||||||
if (idx != -1)
|
|
||||||
CrashSubmit._activeSubmissions.splice(idx, 1);
|
|
||||||
},
|
|
||||||
|
|
||||||
submitForm: function Submitter_submitForm()
|
|
||||||
{
|
|
||||||
if (!('ServerURL' in this.extraKeyVals)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let serverURL = this.extraKeyVals.ServerURL;
|
|
||||||
|
|
||||||
// Override the submission URL from the environment
|
|
||||||
|
|
||||||
var envOverride = Cc['@mozilla.org/process/environment;1'].
|
|
||||||
getService(Ci.nsIEnvironment).get("MOZ_CRASHREPORTER_URL");
|
|
||||||
if (envOverride != '') {
|
|
||||||
serverURL = envOverride;
|
|
||||||
}
|
|
||||||
|
|
||||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
|
||||||
.createInstance(Ci.nsIXMLHttpRequest);
|
|
||||||
xhr.open("POST", serverURL, true);
|
|
||||||
|
|
||||||
let formData = Cc["@mozilla.org/files/formdata;1"]
|
|
||||||
.createInstance(Ci.nsIDOMFormData);
|
|
||||||
// add the data
|
|
||||||
for (let [name, value] of Object.entries(this.extraKeyVals)) {
|
|
||||||
if (name != "ServerURL") {
|
|
||||||
formData.append(name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.noThrottle) {
|
|
||||||
// tell the server not to throttle this, since it was manually submitted
|
|
||||||
formData.append("Throttleable", "0");
|
|
||||||
}
|
|
||||||
// add the minidumps
|
|
||||||
formData.append("upload_file_minidump", File.createFromFileName(this.dump.path));
|
|
||||||
if (this.memory) {
|
|
||||||
formData.append("memory_report", File.createFromFileName(this.memory.path));
|
|
||||||
}
|
|
||||||
if (this.additionalDumps.length > 0) {
|
|
||||||
let names = [];
|
|
||||||
for (let i of this.additionalDumps) {
|
|
||||||
names.push(i.name);
|
|
||||||
formData.append("upload_file_minidump_"+i.name,
|
|
||||||
File.createFromFileName(i.dump.path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let manager = Services.crashmanager;
|
|
||||||
let submissionID = manager.generateSubmissionID();
|
|
||||||
|
|
||||||
xhr.addEventListener("readystatechange", (evt) => {
|
|
||||||
if (xhr.readyState == 4) {
|
|
||||||
let ret =
|
|
||||||
xhr.status == 200 ? parseKeyValuePairs(xhr.responseText) : {};
|
|
||||||
let submitted = !!ret.CrashID;
|
|
||||||
|
|
||||||
if (this.recordSubmission) {
|
|
||||||
let result = submitted ? manager.SUBMISSION_RESULT_OK :
|
|
||||||
manager.SUBMISSION_RESULT_FAILED;
|
|
||||||
manager.addSubmissionResult(this.id, submissionID, new Date(),
|
|
||||||
result);
|
|
||||||
if (submitted) {
|
|
||||||
manager.setRemoteCrashID(this.id, ret.CrashID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (submitted) {
|
|
||||||
this.submitSuccess(ret);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.notifyStatus(FAILED);
|
|
||||||
this.cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
if (this.recordSubmission) {
|
|
||||||
manager.addSubmissionAttempt(this.id, submissionID, new Date());
|
|
||||||
}
|
|
||||||
xhr.send(formData);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
notifyStatus: function Submitter_notify(status, ret)
|
|
||||||
{
|
|
||||||
let propBag = Cc["@mozilla.org/hash-property-bag;1"].
|
|
||||||
createInstance(Ci.nsIWritablePropertyBag2);
|
|
||||||
propBag.setPropertyAsAString("minidumpID", this.id);
|
|
||||||
if (status == SUCCESS) {
|
|
||||||
propBag.setPropertyAsAString("serverCrashID", ret.CrashID);
|
|
||||||
}
|
|
||||||
|
|
||||||
let extraKeyValsBag = Cc["@mozilla.org/hash-property-bag;1"].
|
|
||||||
createInstance(Ci.nsIWritablePropertyBag2);
|
|
||||||
for (let key in this.extraKeyVals) {
|
|
||||||
extraKeyValsBag.setPropertyAsAString(key, this.extraKeyVals[key]);
|
|
||||||
}
|
|
||||||
propBag.setPropertyAsInterface("extra", extraKeyValsBag);
|
|
||||||
|
|
||||||
Services.obs.notifyObservers(propBag, "crash-report-status", status);
|
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case SUCCESS:
|
|
||||||
this.deferredSubmit.resolve(ret.CrashID);
|
|
||||||
break;
|
|
||||||
case FAILED:
|
|
||||||
this.deferredSubmit.reject();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// no callbacks invoked.
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
submit: function Submitter_submit()
|
|
||||||
{
|
|
||||||
let [dump, extra, memory] = getPendingMinidump(this.id);
|
|
||||||
|
|
||||||
if (!dump.exists() || !extra.exists()) {
|
|
||||||
this.notifyStatus(FAILED);
|
|
||||||
this.cleanup();
|
|
||||||
return this.deferredSubmit.promise;
|
|
||||||
}
|
|
||||||
this.dump = dump;
|
|
||||||
this.extra = extra;
|
|
||||||
|
|
||||||
// The memory file may or may not exist
|
|
||||||
if (memory.exists()) {
|
|
||||||
this.memory = memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
let extraKeyVals = parseKeyValuePairsFromFile(extra);
|
|
||||||
for (let key in extraKeyVals) {
|
|
||||||
if (!(key in this.extraKeyVals)) {
|
|
||||||
this.extraKeyVals[key] = extraKeyVals[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let additionalDumps = [];
|
|
||||||
if ("additional_minidumps" in this.extraKeyVals) {
|
|
||||||
let names = this.extraKeyVals.additional_minidumps.split(',');
|
|
||||||
for (let name of names) {
|
|
||||||
let [dump, extra, memory] = getPendingMinidump(this.id + "-" + name);
|
|
||||||
if (!dump.exists()) {
|
|
||||||
this.notifyStatus(FAILED);
|
|
||||||
this.cleanup();
|
|
||||||
return this.deferredSubmit.promise;
|
|
||||||
}
|
|
||||||
additionalDumps.push({'name': name, 'dump': dump});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.notifyStatus(SUBMITTING);
|
|
||||||
|
|
||||||
this.additionalDumps = additionalDumps;
|
|
||||||
|
|
||||||
if (!this.submitForm()) {
|
|
||||||
this.notifyStatus(FAILED);
|
|
||||||
this.cleanup();
|
|
||||||
}
|
|
||||||
return this.deferredSubmit.promise;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ===================================
|
|
||||||
// External API goes here
|
|
||||||
this.CrashSubmit = {
|
|
||||||
/**
|
|
||||||
* Submit the crash report named id.dmp from the "pending" directory.
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
* Filename (minus .dmp extension) of the minidump to submit.
|
|
||||||
* @param params
|
|
||||||
* An object containing any of the following optional parameters:
|
|
||||||
* - recordSubmission
|
|
||||||
* If true, a submission event is recorded in CrashManager.
|
|
||||||
* - noThrottle
|
|
||||||
* If true, this crash report should be submitted with
|
|
||||||
* an extra parameter of "Throttleable=0" indicating that
|
|
||||||
* it should be processed right away. This should be set
|
|
||||||
* when the report is being submitted and the user expects
|
|
||||||
* to see the results immediately. Defaults to false.
|
|
||||||
* - extraExtraKeyVals
|
|
||||||
* An object whose key-value pairs will be merged with the data from
|
|
||||||
* the ".extra" file submitted with the report. The properties of
|
|
||||||
* this object will override properties of the same name in the
|
|
||||||
* .extra file.
|
|
||||||
*
|
|
||||||
* @return a Promise that is fulfilled with the server crash ID when the
|
|
||||||
* submission succeeds and rejected otherwise.
|
|
||||||
*/
|
|
||||||
submit: function CrashSubmit_submit(id, params)
|
|
||||||
{
|
|
||||||
params = params || {};
|
|
||||||
let recordSubmission = false;
|
|
||||||
let submitSuccess = null;
|
|
||||||
let submitError = null;
|
|
||||||
let noThrottle = false;
|
|
||||||
let extraExtraKeyVals = null;
|
|
||||||
|
|
||||||
if ('recordSubmission' in params)
|
|
||||||
recordSubmission = params.recordSubmission;
|
|
||||||
if ('noThrottle' in params)
|
|
||||||
noThrottle = params.noThrottle;
|
|
||||||
if ('extraExtraKeyVals' in params)
|
|
||||||
extraExtraKeyVals = params.extraExtraKeyVals;
|
|
||||||
|
|
||||||
let submitter = new Submitter(id, recordSubmission,
|
|
||||||
noThrottle, extraExtraKeyVals);
|
|
||||||
CrashSubmit._activeSubmissions.push(submitter);
|
|
||||||
return submitter.submit();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the minidup from the "pending" directory.
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
* Filename (minus .dmp extension) of the minidump to delete.
|
|
||||||
*/
|
|
||||||
delete: function CrashSubmit_delete(id) {
|
|
||||||
let [dump, extra, memory] = getPendingMinidump(id);
|
|
||||||
dump.remove(false);
|
|
||||||
extra.remove(false);
|
|
||||||
if (memory.exists()) {
|
|
||||||
memory.remove(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a .dmg.ignore file along side the .dmp file to indicate that the user
|
|
||||||
* shouldn't be prompted to submit this crash report again.
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
* Filename (minus .dmp extension) of the report to ignore
|
|
||||||
*/
|
|
||||||
|
|
||||||
ignore: function CrashSubmit_ignore(id) {
|
|
||||||
let [dump, extra, mem] = getPendingMinidump(id);
|
|
||||||
return OS.File.open(dump.path + ".ignore", {create: true},
|
|
||||||
{unixFlags: OS.Constants.libc.O_CREAT})
|
|
||||||
.then((file) => { file.close(); });
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of pending crash IDs.
|
|
||||||
*
|
|
||||||
* @return an array of string, each being an ID as
|
|
||||||
* expected to be passed to submit()
|
|
||||||
*/
|
|
||||||
pendingIDs: function CrashSubmit_pendingIDs() {
|
|
||||||
return getAllPendingMinidumpsIDs();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of pending crash IDs, excluding those marked to be ignored
|
|
||||||
* @param maxFileDate
|
|
||||||
* A Date object. Any files last modified before that date will be ignored
|
|
||||||
*
|
|
||||||
* @return a Promise that is fulfilled with an array of string, each
|
|
||||||
* being an ID as expected to be passed to submit() or ignore()
|
|
||||||
*/
|
|
||||||
pendingIDsAsync: Task.async(function* CrashSubmit_pendingIDsAsync(maxFileDate) {
|
|
||||||
let ids = [];
|
|
||||||
let info = null;
|
|
||||||
try {
|
|
||||||
info = yield OS.File.stat(getDir("pending").path)
|
|
||||||
} catch (ex) {
|
|
||||||
/* pending dir doesn't exist, ignore */
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.isDir) {
|
|
||||||
let iterator = new OS.File.DirectoryIterator(getDir("pending").path);
|
|
||||||
try {
|
|
||||||
yield iterator.forEach(
|
|
||||||
function onEntry(file) {
|
|
||||||
if (file.name.endsWith(".dmp")) {
|
|
||||||
return OS.File.exists(file.path + ".ignore")
|
|
||||||
.then(ignoreExists => {
|
|
||||||
if (!ignoreExists) {
|
|
||||||
let id = file.name.slice(0, -4);
|
|
||||||
if (UUID_REGEX.test(id)) {
|
|
||||||
return OS.File.stat(file.path)
|
|
||||||
.then(info => {
|
|
||||||
if (info.lastAccessDate.valueOf() >
|
|
||||||
maxFileDate.valueOf()) {
|
|
||||||
ids.push(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (ex) {
|
|
||||||
Cu.reportError(ex);
|
|
||||||
} finally {
|
|
||||||
iterator.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ids;
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prune the saved dumps.
|
|
||||||
*/
|
|
||||||
pruneSavedDumps: function CrashSubmit_pruneSavedDumps() {
|
|
||||||
pruneSavedDumps();
|
|
||||||
},
|
|
||||||
|
|
||||||
// List of currently active submit objects
|
|
||||||
_activeSubmissions: []
|
|
||||||
};
|
|
|
@ -1,84 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "InjectCrashReporter.h"
|
|
||||||
#include "nsDirectoryServiceUtils.h"
|
|
||||||
#include "nsDirectoryServiceDefs.h"
|
|
||||||
#include "client/windows/crash_generation/crash_generation_client.h"
|
|
||||||
#include "nsExceptionHandler.h"
|
|
||||||
#include "LoadLibraryRemote.h"
|
|
||||||
#include "nsWindowsHelpers.h"
|
|
||||||
|
|
||||||
using google_breakpad::CrashGenerationClient;
|
|
||||||
using CrashReporter::GetChildNotificationPipe;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
InjectCrashRunnable::InjectCrashRunnable(DWORD pid)
|
|
||||||
: mPID(pid)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIFile> dll;
|
|
||||||
nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(dll));
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
dll->Append(NS_LITERAL_STRING("breakpadinjector.dll"));
|
|
||||||
dll->GetPath(mInjectorPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
InjectCrashRunnable::Run()
|
|
||||||
{
|
|
||||||
if (mInjectorPath.IsEmpty())
|
|
||||||
return NS_OK;
|
|
||||||
|
|
||||||
nsAutoHandle hProcess(
|
|
||||||
OpenProcess(PROCESS_CREATE_THREAD |
|
|
||||||
PROCESS_QUERY_INFORMATION |
|
|
||||||
PROCESS_DUP_HANDLE |
|
|
||||||
PROCESS_VM_OPERATION |
|
|
||||||
PROCESS_VM_WRITE |
|
|
||||||
PROCESS_VM_READ, FALSE, mPID));
|
|
||||||
if (!hProcess) {
|
|
||||||
NS_WARNING("Unable to open remote process handle for crashreporter injection.");
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* proc = LoadRemoteLibraryAndGetAddress(hProcess, mInjectorPath.get(),
|
|
||||||
"Start");
|
|
||||||
if (!proc) {
|
|
||||||
NS_WARNING("Unable to inject crashreporter DLL.");
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLE hRemotePipe =
|
|
||||||
CrashGenerationClient::DuplicatePipeToClientProcess(
|
|
||||||
NS_ConvertASCIItoUTF16(GetChildNotificationPipe()).get(),
|
|
||||||
hProcess);
|
|
||||||
if (INVALID_HANDLE_VALUE == hRemotePipe) {
|
|
||||||
NS_WARNING("Unable to duplicate crash reporter pipe to process.");
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoHandle hThread(CreateRemoteThread(hProcess, nullptr, 0,
|
|
||||||
(LPTHREAD_START_ROUTINE) proc,
|
|
||||||
(void*) hRemotePipe, 0, nullptr));
|
|
||||||
if (!hThread) {
|
|
||||||
NS_WARNING("Unable to CreateRemoteThread");
|
|
||||||
|
|
||||||
// We have to close the remote pipe or else our crash generation client
|
|
||||||
// will be stuck unable to accept other remote requests.
|
|
||||||
HANDLE toClose = INVALID_HANDLE_VALUE;
|
|
||||||
if (DuplicateHandle(hProcess, hRemotePipe, ::GetCurrentProcess(),
|
|
||||||
&toClose, 0, FALSE,
|
|
||||||
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
|
|
||||||
CloseHandle(toClose);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mozilla
|
|
|
@ -1,28 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef InjectCrashReporter_h
|
|
||||||
#define InjectCrashReporter_h
|
|
||||||
|
|
||||||
#include "nsThreadUtils.h"
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
class InjectCrashRunnable : public Runnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
InjectCrashRunnable(DWORD pid);
|
|
||||||
|
|
||||||
NS_IMETHOD Run();
|
|
||||||
|
|
||||||
private:
|
|
||||||
DWORD mPID;
|
|
||||||
nsString mInjectorPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // Namespace mozilla
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,54 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = [
|
|
||||||
"parseKeyValuePairsFromLines",
|
|
||||||
"parseKeyValuePairs",
|
|
||||||
"parseKeyValuePairsFromFile"
|
|
||||||
];
|
|
||||||
|
|
||||||
const Cc = Components.classes;
|
|
||||||
const Ci = Components.interfaces;
|
|
||||||
|
|
||||||
this.parseKeyValuePairsFromLines = function(lines) {
|
|
||||||
let data = {};
|
|
||||||
for (let line of lines) {
|
|
||||||
if (line == '')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// can't just .split() because the value might contain = characters
|
|
||||||
let eq = line.indexOf('=');
|
|
||||||
if (eq != -1) {
|
|
||||||
let [key, value] = [line.substring(0, eq),
|
|
||||||
line.substring(eq + 1)];
|
|
||||||
if (key && value)
|
|
||||||
data[key] = value.replace(/\\n/g, "\n").replace(/\\\\/g, "\\");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.parseKeyValuePairs = function parseKeyValuePairs(text) {
|
|
||||||
let lines = text.split('\n');
|
|
||||||
return parseKeyValuePairsFromLines(lines);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.parseKeyValuePairsFromFile = function parseKeyValuePairsFromFile(file) {
|
|
||||||
let fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
|
||||||
createInstance(Ci.nsIFileInputStream);
|
|
||||||
fstream.init(file, -1, 0, 0);
|
|
||||||
let is = Cc["@mozilla.org/intl/converter-input-stream;1"].
|
|
||||||
createInstance(Ci.nsIConverterInputStream);
|
|
||||||
is.init(fstream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
|
||||||
let str = {};
|
|
||||||
let contents = '';
|
|
||||||
while (is.readString(4096, str) != 0) {
|
|
||||||
contents += str.value;
|
|
||||||
}
|
|
||||||
is.close();
|
|
||||||
fstream.close();
|
|
||||||
return parseKeyValuePairs(contents);
|
|
||||||
}
|
|
|
@ -1,454 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef __GNUC__
|
|
||||||
// disable warnings about pointer <-> DWORD conversions
|
|
||||||
#pragma warning( disable : 4311 4312 )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
|
||||||
#define POINTER_TYPE ULONGLONG
|
|
||||||
#else
|
|
||||||
#define POINTER_TYPE DWORD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <winnt.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifdef DEBUG_OUTPUT
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "nsWindowsHelpers.h"
|
|
||||||
|
|
||||||
typedef const unsigned char* FileView;
|
|
||||||
|
|
||||||
template<>
|
|
||||||
class nsAutoRefTraits<FileView>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef FileView RawRef;
|
|
||||||
static FileView Void()
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Release(RawRef aView)
|
|
||||||
{
|
|
||||||
if (nullptr != aView)
|
|
||||||
UnmapViewOfFile(aView);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef IMAGE_SIZEOF_BASE_RELOCATION
|
|
||||||
// Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!?
|
|
||||||
#define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "LoadLibraryRemote.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PIMAGE_NT_HEADERS headers;
|
|
||||||
unsigned char *localCodeBase;
|
|
||||||
unsigned char *remoteCodeBase;
|
|
||||||
HMODULE *modules;
|
|
||||||
int numModules;
|
|
||||||
} MEMORYMODULE, *PMEMORYMODULE;
|
|
||||||
|
|
||||||
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
|
|
||||||
|
|
||||||
#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
|
|
||||||
|
|
||||||
#ifdef DEBUG_OUTPUT
|
|
||||||
static void
|
|
||||||
OutputLastError(const char *msg)
|
|
||||||
{
|
|
||||||
char* tmp;
|
|
||||||
char *tmpmsg;
|
|
||||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
||||||
nullptr, GetLastError(),
|
|
||||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
||||||
(LPSTR) &tmp, 0, nullptr);
|
|
||||||
tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3);
|
|
||||||
sprintf(tmpmsg, "%s: %s", msg, tmp);
|
|
||||||
OutputDebugStringA(tmpmsg);
|
|
||||||
LocalFree(tmpmsg);
|
|
||||||
LocalFree(tmp);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
|
||||||
CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char *codeBase = module->localCodeBase;
|
|
||||||
unsigned char *dest;
|
|
||||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
|
|
||||||
for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
|
|
||||||
dest = codeBase + section->VirtualAddress;
|
|
||||||
memset(dest, 0, section->Misc.VirtualSize);
|
|
||||||
if (section->SizeOfRawData) {
|
|
||||||
memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData);
|
|
||||||
}
|
|
||||||
// section->Misc.PhysicalAddress = (POINTER_TYPE) module->remoteCodeBase + section->VirtualAddress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
CopyRegion(HANDLE hRemoteProcess, void* remoteAddress, void* localAddress, DWORD size, DWORD protect)
|
|
||||||
{
|
|
||||||
if (size > 0) {
|
|
||||||
// Copy the data from local->remote and set the memory protection
|
|
||||||
if (!VirtualAllocEx(hRemoteProcess, remoteAddress, size, MEM_COMMIT, PAGE_READWRITE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!WriteProcessMemory(hRemoteProcess,
|
|
||||||
remoteAddress,
|
|
||||||
localAddress,
|
|
||||||
size,
|
|
||||||
nullptr)) {
|
|
||||||
#ifdef DEBUG_OUTPUT
|
|
||||||
OutputLastError("Error writing remote memory.\n");
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD oldProtect;
|
|
||||||
if (VirtualProtectEx(hRemoteProcess, remoteAddress, size, protect, &oldProtect) == 0) {
|
|
||||||
#ifdef DEBUG_OUTPUT
|
|
||||||
OutputLastError("Error protecting memory page");
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Protection flags for memory pages (Executable, Readable, Writeable)
|
|
||||||
static int ProtectionFlags[2][2][2] = {
|
|
||||||
{
|
|
||||||
// not executable
|
|
||||||
{PAGE_NOACCESS, PAGE_WRITECOPY},
|
|
||||||
{PAGE_READONLY, PAGE_READWRITE},
|
|
||||||
}, {
|
|
||||||
// executable
|
|
||||||
{PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY},
|
|
||||||
{PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool
|
|
||||||
FinalizeSections(PMEMORYMODULE module, HANDLE hRemoteProcess)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_OUTPUT
|
|
||||||
fprintf(stderr, "Finalizing sections: local base %p, remote base %p\n",
|
|
||||||
module->localCodeBase, module->remoteCodeBase);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int i;
|
|
||||||
int numSections = module->headers->FileHeader.NumberOfSections;
|
|
||||||
|
|
||||||
if (numSections < 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
|
|
||||||
|
|
||||||
// Copy any data before the first section (i.e. the image header)
|
|
||||||
if (!CopyRegion(hRemoteProcess, module->remoteCodeBase, module->localCodeBase, section->VirtualAddress, PAGE_READONLY))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// loop through all sections and change access flags
|
|
||||||
for (i=0; i<numSections; i++, section++) {
|
|
||||||
DWORD protect, size;
|
|
||||||
int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
|
|
||||||
int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0;
|
|
||||||
int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
|
|
||||||
|
|
||||||
// determine protection flags based on characteristics
|
|
||||||
protect = ProtectionFlags[executable][readable][writeable];
|
|
||||||
if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) {
|
|
||||||
protect |= PAGE_NOCACHE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* remoteAddress = module->remoteCodeBase + section->VirtualAddress;
|
|
||||||
void* localAddress = module->localCodeBase + section->VirtualAddress;
|
|
||||||
|
|
||||||
// determine size of region
|
|
||||||
size = section->Misc.VirtualSize;
|
|
||||||
#ifdef DEBUG_OUTPUT
|
|
||||||
fprintf(stderr, "Copying section %s to %p, size %x, executable %i readable %i writeable %i\n",
|
|
||||||
section->Name, remoteAddress, size, executable, readable, writeable);
|
|
||||||
#endif
|
|
||||||
if (!CopyRegion(hRemoteProcess, remoteAddress, localAddress, size, protect))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta)
|
|
||||||
{
|
|
||||||
DWORD i;
|
|
||||||
unsigned char *codeBase = module->localCodeBase;
|
|
||||||
|
|
||||||
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
|
||||||
if (directory->Size > 0) {
|
|
||||||
PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress);
|
|
||||||
for (; relocation->VirtualAddress > 0; ) {
|
|
||||||
unsigned char *dest = codeBase + relocation->VirtualAddress;
|
|
||||||
unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION);
|
|
||||||
for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) {
|
|
||||||
DWORD *patchAddrHL;
|
|
||||||
#ifdef _WIN64
|
|
||||||
ULONGLONG *patchAddr64;
|
|
||||||
#endif
|
|
||||||
int type, offset;
|
|
||||||
|
|
||||||
// the upper 4 bits define the type of relocation
|
|
||||||
type = *relInfo >> 12;
|
|
||||||
// the lower 12 bits define the offset
|
|
||||||
offset = *relInfo & 0xfff;
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case IMAGE_REL_BASED_ABSOLUTE:
|
|
||||||
// skip relocation
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IMAGE_REL_BASED_HIGHLOW:
|
|
||||||
// change complete 32 bit address
|
|
||||||
patchAddrHL = (DWORD *) (dest + offset);
|
|
||||||
*patchAddrHL += delta;
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
|
||||||
case IMAGE_REL_BASED_DIR64:
|
|
||||||
patchAddr64 = (ULONGLONG *) (dest + offset);
|
|
||||||
*patchAddr64 += delta;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
|
||||||
//printf("Unknown relocation: %d\n", type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// advance to next relocation block
|
|
||||||
relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
BuildImportTable(PMEMORYMODULE module)
|
|
||||||
{
|
|
||||||
int result=1;
|
|
||||||
unsigned char *codeBase = module->localCodeBase;
|
|
||||||
|
|
||||||
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
|
||||||
if (directory->Size > 0) {
|
|
||||||
PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress);
|
|
||||||
PIMAGE_IMPORT_DESCRIPTOR importEnd = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress + directory->Size);
|
|
||||||
|
|
||||||
for (; importDesc < importEnd && importDesc->Name; importDesc++) {
|
|
||||||
POINTER_TYPE *thunkRef;
|
|
||||||
FARPROC *funcRef;
|
|
||||||
HMODULE handle = GetModuleHandleA((LPCSTR) (codeBase + importDesc->Name));
|
|
||||||
if (handle == nullptr) {
|
|
||||||
#if DEBUG_OUTPUT
|
|
||||||
OutputLastError("Can't load library");
|
|
||||||
#endif
|
|
||||||
result = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
module->modules = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE)));
|
|
||||||
if (module->modules == nullptr) {
|
|
||||||
result = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
module->modules[module->numModules++] = handle;
|
|
||||||
if (importDesc->OriginalFirstThunk) {
|
|
||||||
thunkRef = (POINTER_TYPE *) (codeBase + importDesc->OriginalFirstThunk);
|
|
||||||
funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
|
|
||||||
} else {
|
|
||||||
// no hint table
|
|
||||||
thunkRef = (POINTER_TYPE *) (codeBase + importDesc->FirstThunk);
|
|
||||||
funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
|
|
||||||
}
|
|
||||||
for (; *thunkRef; thunkRef++, funcRef++) {
|
|
||||||
if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) {
|
|
||||||
*funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef));
|
|
||||||
} else {
|
|
||||||
PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef));
|
|
||||||
*funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)&thunkData->Name);
|
|
||||||
}
|
|
||||||
if (*funcRef == 0) {
|
|
||||||
result = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void* MemoryGetProcAddress(PMEMORYMODULE module, const char *name);
|
|
||||||
|
|
||||||
void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess,
|
|
||||||
const WCHAR* library,
|
|
||||||
const char* symbol)
|
|
||||||
{
|
|
||||||
// Map the DLL into memory
|
|
||||||
nsAutoHandle hLibrary(
|
|
||||||
CreateFile(library, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
|
||||||
FILE_ATTRIBUTE_NORMAL, nullptr));
|
|
||||||
if (INVALID_HANDLE_VALUE == hLibrary) {
|
|
||||||
#if DEBUG_OUTPUT
|
|
||||||
OutputLastError("Couldn't CreateFile the library.\n");
|
|
||||||
#endif
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoHandle hMapping(
|
|
||||||
CreateFileMapping(hLibrary, nullptr, PAGE_READONLY, 0, 0, nullptr));
|
|
||||||
if (!hMapping) {
|
|
||||||
#if DEBUG_OUTPUT
|
|
||||||
OutputLastError("Couldn't CreateFileMapping.\n");
|
|
||||||
#endif
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoRef<FileView> data(
|
|
||||||
(const unsigned char*) MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
|
||||||
if (!data) {
|
|
||||||
#if DEBUG_OUTPUT
|
|
||||||
OutputLastError("Couldn't MapViewOfFile.\n");
|
|
||||||
#endif
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SIZE_T locationDelta;
|
|
||||||
|
|
||||||
PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)data.get();
|
|
||||||
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
||||||
#if DEBUG_OUTPUT
|
|
||||||
OutputDebugStringA("Not a valid executable file.\n");
|
|
||||||
#endif
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIMAGE_NT_HEADERS old_header = (PIMAGE_NT_HEADERS)(data + dos_header->e_lfanew);
|
|
||||||
if (old_header->Signature != IMAGE_NT_SIGNATURE) {
|
|
||||||
#if DEBUG_OUTPUT
|
|
||||||
OutputDebugStringA("No PE header found.\n");
|
|
||||||
#endif
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reserve memory for image of library in this process and the target process
|
|
||||||
unsigned char* localCode = (unsigned char*) VirtualAlloc(nullptr,
|
|
||||||
old_header->OptionalHeader.SizeOfImage,
|
|
||||||
MEM_RESERVE | MEM_COMMIT,
|
|
||||||
PAGE_READWRITE);
|
|
||||||
if (!localCode) {
|
|
||||||
#if DEBUG_OUTPUT
|
|
||||||
OutputLastError("Can't reserve local memory.");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char* remoteCode = (unsigned char*) VirtualAllocEx(hRemoteProcess, nullptr,
|
|
||||||
old_header->OptionalHeader.SizeOfImage,
|
|
||||||
MEM_RESERVE,
|
|
||||||
PAGE_EXECUTE_READ);
|
|
||||||
if (!remoteCode) {
|
|
||||||
#if DEBUG_OUTPUT
|
|
||||||
OutputLastError("Can't reserve remote memory.");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
MEMORYMODULE result;
|
|
||||||
result.localCodeBase = localCode;
|
|
||||||
result.remoteCodeBase = remoteCode;
|
|
||||||
result.numModules = 0;
|
|
||||||
result.modules = nullptr;
|
|
||||||
|
|
||||||
// copy PE header to code
|
|
||||||
memcpy(localCode, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders);
|
|
||||||
result.headers = reinterpret_cast<PIMAGE_NT_HEADERS>(localCode + dos_header->e_lfanew);
|
|
||||||
|
|
||||||
// update position
|
|
||||||
result.headers->OptionalHeader.ImageBase = (POINTER_TYPE)remoteCode;
|
|
||||||
|
|
||||||
// copy sections from DLL file block to new memory location
|
|
||||||
CopySections(data, old_header, &result);
|
|
||||||
|
|
||||||
// adjust base address of imported data
|
|
||||||
locationDelta = (SIZE_T)(remoteCode - old_header->OptionalHeader.ImageBase);
|
|
||||||
if (locationDelta != 0) {
|
|
||||||
PerformBaseRelocation(&result, locationDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load required dlls and adjust function table of imports
|
|
||||||
if (!BuildImportTable(&result)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark memory pages depending on section headers and release
|
|
||||||
// sections that are marked as "discardable"
|
|
||||||
if (!FinalizeSections(&result, hRemoteProcess)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MemoryGetProcAddress(&result, symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void* MemoryGetProcAddress(PMEMORYMODULE module, const char *name)
|
|
||||||
{
|
|
||||||
unsigned char *localCodeBase = module->localCodeBase;
|
|
||||||
int idx=-1;
|
|
||||||
DWORD i, *nameRef;
|
|
||||||
WORD *ordinal;
|
|
||||||
PIMAGE_EXPORT_DIRECTORY exports;
|
|
||||||
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT);
|
|
||||||
if (directory->Size == 0) {
|
|
||||||
// no export table found
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
exports = (PIMAGE_EXPORT_DIRECTORY) (localCodeBase + directory->VirtualAddress);
|
|
||||||
if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) {
|
|
||||||
// DLL doesn't export anything
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// search function name in list of exported names
|
|
||||||
nameRef = (DWORD *) (localCodeBase + exports->AddressOfNames);
|
|
||||||
ordinal = (WORD *) (localCodeBase + exports->AddressOfNameOrdinals);
|
|
||||||
for (i=0; i<exports->NumberOfNames; i++, nameRef++, ordinal++) {
|
|
||||||
if (stricmp(name, (const char *) (localCodeBase + (*nameRef))) == 0) {
|
|
||||||
idx = *ordinal;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx == -1) {
|
|
||||||
// exported symbol not found
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((DWORD)idx > exports->NumberOfFunctions) {
|
|
||||||
// name <-> ordinal number don't match
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddressOfFunctions contains the RVAs to the "real" functions
|
|
||||||
return module->remoteCodeBase + (*(DWORD *) (localCodeBase + exports->AddressOfFunctions + (idx*4)));
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef LoadLibraryRemote_h
|
|
||||||
#define LoadLibraryRemote_h
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inject a library into a remote process. This injection has the following
|
|
||||||
* restrictions:
|
|
||||||
*
|
|
||||||
* - The DLL being injected must only depend on kernel32 and user32.
|
|
||||||
* - The entry point of the DLL is not run. If the DLL uses the CRT, it is
|
|
||||||
* the responsibility of the caller to make sure that _CRT_INIT is called.
|
|
||||||
* - There is no support for unloading a library once it has been loaded.
|
|
||||||
* - The symbol must be a named symbol and not an ordinal.
|
|
||||||
*/
|
|
||||||
void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess,
|
|
||||||
const WCHAR* library,
|
|
||||||
const char* symbol);
|
|
||||||
|
|
||||||
#endif // LoadLibraryRemote_h
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +0,0 @@
|
||||||
Do not land local patches to Breakpad without the approval of
|
|
||||||
Ted Mielczarek <ted@mielczarek.org>
|
|
||||||
|
|
||||||
All local patches must be in the process of being upstreamed.
|
|
|
@ -1,32 +0,0 @@
|
||||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
|
||||||
# vim: set filetype=python:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
SOURCES += [
|
|
||||||
'../google-breakpad/src/common/windows/http_upload.cc',
|
|
||||||
]
|
|
||||||
|
|
||||||
Library('google_breakpad_libxul_s')
|
|
||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
|
||||||
|
|
||||||
for var in ('UNICODE', 'UNICODE_', 'BREAKPAD_NO_TERMINATE_THREAD'):
|
|
||||||
DEFINES[var] = True
|
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
|
||||||
'/toolkit/crashreporter/google-breakpad/src',
|
|
||||||
]
|
|
||||||
|
|
||||||
include('/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild')
|
|
||||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild')
|
|
||||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/sender/objs.mozbuild')
|
|
||||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/objs.mozbuild')
|
|
||||||
|
|
||||||
SOURCES += objs_common
|
|
||||||
SOURCES += objs_crash_generation
|
|
||||||
SOURCES += objs_handler
|
|
||||||
SOURCES += objs_sender
|
|
||||||
|
|
||||||
DISABLE_STL_WRAPPING = True
|
|
|
@ -1,26 +0,0 @@
|
||||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
|
||||||
# vim: set filetype=python:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
FINAL_LIBRARY = 'breakpadinjector'
|
|
||||||
|
|
||||||
for var in ('UNICODE', 'UNICODE_', 'BREAKPAD_NO_TERMINATE_THREAD'):
|
|
||||||
DEFINES[var] = True
|
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
|
||||||
'/toolkit/crashreporter/google-breakpad/src',
|
|
||||||
]
|
|
||||||
|
|
||||||
include('/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild')
|
|
||||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild')
|
|
||||||
include('/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/objs.mozbuild')
|
|
||||||
|
|
||||||
SOURCES += objs_common
|
|
||||||
SOURCES += objs_crash_generation
|
|
||||||
SOURCES += objs_handler
|
|
||||||
|
|
||||||
USE_STATIC_LIBS = True
|
|
||||||
|
|
||||||
DISABLE_STL_WRAPPING = True
|
|
|
@ -1,20 +0,0 @@
|
||||||
# vim:set ts=8 sw=8 sts=8 noet:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
ifeq ($(OS_ARCH),WINNT)
|
|
||||||
MOZ_WINCONSOLE = 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
|
||||||
|
|
||||||
ifeq ($(OS_ARCH),Darwin)
|
|
||||||
libs::
|
|
||||||
$(NSINSTALL) -D $(DIST)/bin/crashreporter.app
|
|
||||||
rsync -a -C --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/bin/crashreporter.app
|
|
||||||
sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \
|
|
||||||
iconv -f UTF-8 -t UTF-16 > $(DIST)/bin/crashreporter.app/Contents/Resources/English.lproj/InfoPlist.strings
|
|
||||||
$(NSINSTALL) -D $(DIST)/bin/crashreporter.app/Contents/MacOS
|
|
||||||
$(NSINSTALL) $(DIST)/bin/crashreporter $(DIST)/bin/crashreporter.app/Contents/MacOS
|
|
||||||
endif
|
|
Binary file not shown.
|
@ -1,759 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "crashreporter.h"
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// Disable exception handler warnings.
|
|
||||||
# pragma warning( disable : 4530 )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <memory>
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::istream;
|
|
||||||
using std::ifstream;
|
|
||||||
using std::istringstream;
|
|
||||||
using std::ostringstream;
|
|
||||||
using std::ostream;
|
|
||||||
using std::ofstream;
|
|
||||||
using std::vector;
|
|
||||||
using std::auto_ptr;
|
|
||||||
|
|
||||||
namespace CrashReporter {
|
|
||||||
|
|
||||||
StringTable gStrings;
|
|
||||||
string gSettingsPath;
|
|
||||||
string gEventsPath;
|
|
||||||
int gArgc;
|
|
||||||
char** gArgv;
|
|
||||||
|
|
||||||
enum SubmissionResult {Succeeded, Failed};
|
|
||||||
|
|
||||||
static auto_ptr<ofstream> gLogStream(nullptr);
|
|
||||||
static string gReporterDumpFile;
|
|
||||||
static string gExtraFile;
|
|
||||||
static string gMemoryFile;
|
|
||||||
|
|
||||||
static const char kExtraDataExtension[] = ".extra";
|
|
||||||
static const char kMemoryReportExtension[] = ".memory.json.gz";
|
|
||||||
|
|
||||||
void UIError(const string& message)
|
|
||||||
{
|
|
||||||
string errorMessage;
|
|
||||||
if (!gStrings[ST_CRASHREPORTERERROR].empty()) {
|
|
||||||
char buf[2048];
|
|
||||||
UI_SNPRINTF(buf, 2048,
|
|
||||||
gStrings[ST_CRASHREPORTERERROR].c_str(),
|
|
||||||
message.c_str());
|
|
||||||
errorMessage = buf;
|
|
||||||
} else {
|
|
||||||
errorMessage = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
UIError_impl(errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
static string Unescape(const string& str)
|
|
||||||
{
|
|
||||||
string ret;
|
|
||||||
for (string::const_iterator iter = str.begin();
|
|
||||||
iter != str.end();
|
|
||||||
iter++) {
|
|
||||||
if (*iter == '\\') {
|
|
||||||
iter++;
|
|
||||||
if (*iter == '\\'){
|
|
||||||
ret.push_back('\\');
|
|
||||||
} else if (*iter == 'n') {
|
|
||||||
ret.push_back('\n');
|
|
||||||
} else if (*iter == 't') {
|
|
||||||
ret.push_back('\t');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret.push_back(*iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string Escape(const string& str)
|
|
||||||
{
|
|
||||||
string ret;
|
|
||||||
for (string::const_iterator iter = str.begin();
|
|
||||||
iter != str.end();
|
|
||||||
iter++) {
|
|
||||||
if (*iter == '\\') {
|
|
||||||
ret += "\\\\";
|
|
||||||
} else if (*iter == '\n') {
|
|
||||||
ret += "\\n";
|
|
||||||
} else if (*iter == '\t') {
|
|
||||||
ret += "\\t";
|
|
||||||
} else {
|
|
||||||
ret.push_back(*iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReadStrings(istream& in, StringTable& strings, bool unescape)
|
|
||||||
{
|
|
||||||
string currentSection;
|
|
||||||
while (!in.eof()) {
|
|
||||||
string line;
|
|
||||||
std::getline(in, line);
|
|
||||||
int sep = line.find('=');
|
|
||||||
if (sep >= 0) {
|
|
||||||
string key, value;
|
|
||||||
key = line.substr(0, sep);
|
|
||||||
value = line.substr(sep + 1);
|
|
||||||
if (unescape)
|
|
||||||
value = Unescape(value);
|
|
||||||
strings[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReadStringsFromFile(const string& path,
|
|
||||||
StringTable& strings,
|
|
||||||
bool unescape)
|
|
||||||
{
|
|
||||||
ifstream* f = UIOpenRead(path);
|
|
||||||
bool success = false;
|
|
||||||
if (f->is_open()) {
|
|
||||||
success = ReadStrings(*f, strings, unescape);
|
|
||||||
f->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete f;
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WriteStrings(ostream& out,
|
|
||||||
const string& header,
|
|
||||||
StringTable& strings,
|
|
||||||
bool escape)
|
|
||||||
{
|
|
||||||
out << "[" << header << "]" << std::endl;
|
|
||||||
for (StringTable::iterator iter = strings.begin();
|
|
||||||
iter != strings.end();
|
|
||||||
iter++) {
|
|
||||||
out << iter->first << "=";
|
|
||||||
if (escape)
|
|
||||||
out << Escape(iter->second);
|
|
||||||
else
|
|
||||||
out << iter->second;
|
|
||||||
|
|
||||||
out << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WriteStringsToFile(const string& path,
|
|
||||||
const string& header,
|
|
||||||
StringTable& strings,
|
|
||||||
bool escape)
|
|
||||||
{
|
|
||||||
ofstream* f = UIOpenWrite(path.c_str());
|
|
||||||
bool success = false;
|
|
||||||
if (f->is_open()) {
|
|
||||||
success = WriteStrings(*f, header, strings, escape);
|
|
||||||
f->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete f;
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string Basename(const string& file)
|
|
||||||
{
|
|
||||||
string::size_type slashIndex = file.rfind(UI_DIR_SEPARATOR);
|
|
||||||
if (slashIndex != string::npos)
|
|
||||||
return file.substr(slashIndex + 1);
|
|
||||||
else
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string GetDumpLocalID()
|
|
||||||
{
|
|
||||||
string localId = Basename(gReporterDumpFile);
|
|
||||||
string::size_type dot = localId.rfind('.');
|
|
||||||
|
|
||||||
if (dot == string::npos)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
return localId.substr(0, dot);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This appends the StackTraces entry generated by the minidump analyzer to the
|
|
||||||
// main crash event so that it can be picked up by Firefox once it restarts
|
|
||||||
static void AppendStackTracesToEventFile(const string& aStackTraces)
|
|
||||||
{
|
|
||||||
if (gEventsPath.empty()) {
|
|
||||||
// If there is no path for finding the crash event, skip this step.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string localId = GetDumpLocalID();
|
|
||||||
string path = gEventsPath + UI_DIR_SEPARATOR + localId;
|
|
||||||
ofstream* f = UIOpenWrite(path.c_str(), true);
|
|
||||||
|
|
||||||
if (f->is_open()) {
|
|
||||||
*f << "StackTraces=" << aStackTraces;
|
|
||||||
f->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void WriteSubmissionEvent(SubmissionResult result,
|
|
||||||
const string& remoteId)
|
|
||||||
{
|
|
||||||
if (gEventsPath.empty()) {
|
|
||||||
// If there is no path for writing the submission event, skip it.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string localId = GetDumpLocalID();
|
|
||||||
string fpath = gEventsPath + UI_DIR_SEPARATOR + localId + "-submission";
|
|
||||||
ofstream* f = UIOpenWrite(fpath.c_str(), false, true);
|
|
||||||
time_t tm;
|
|
||||||
time(&tm);
|
|
||||||
|
|
||||||
if (f->is_open()) {
|
|
||||||
*f << "crash.submission.1\n";
|
|
||||||
*f << tm << "\n";
|
|
||||||
*f << localId << "\n";
|
|
||||||
*f << (result == Succeeded ? "true" : "false") << "\n";
|
|
||||||
*f << remoteId;
|
|
||||||
|
|
||||||
f->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogMessage(const std::string& message)
|
|
||||||
{
|
|
||||||
if (gLogStream.get()) {
|
|
||||||
char date[64];
|
|
||||||
time_t tm;
|
|
||||||
time(&tm);
|
|
||||||
if (strftime(date, sizeof(date) - 1, "%c", localtime(&tm)) == 0)
|
|
||||||
date[0] = '\0';
|
|
||||||
(*gLogStream) << "[" << date << "] " << message << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OpenLogFile()
|
|
||||||
{
|
|
||||||
string logPath = gSettingsPath + UI_DIR_SEPARATOR + "submit.log";
|
|
||||||
gLogStream.reset(UIOpenWrite(logPath.c_str(), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ReadConfig()
|
|
||||||
{
|
|
||||||
string iniPath;
|
|
||||||
if (!UIGetIniPath(iniPath))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!ReadStringsFromFile(iniPath, gStrings, true))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// See if we have a string override file, if so process it
|
|
||||||
char* overrideEnv = getenv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE");
|
|
||||||
if (overrideEnv && *overrideEnv && UIFileExists(overrideEnv))
|
|
||||||
ReadStringsFromFile(overrideEnv, gStrings, true);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string
|
|
||||||
GetAdditionalFilename(const string& dumpfile, const char* extension)
|
|
||||||
{
|
|
||||||
string filename(dumpfile);
|
|
||||||
int dot = filename.rfind('.');
|
|
||||||
if (dot < 0)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
filename.replace(dot, filename.length() - dot, extension);
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool MoveCrashData(const string& toDir,
|
|
||||||
string& dumpfile,
|
|
||||||
string& extrafile,
|
|
||||||
string& memoryfile)
|
|
||||||
{
|
|
||||||
if (!UIEnsurePathExists(toDir)) {
|
|
||||||
UIError(gStrings[ST_ERROR_CREATEDUMPDIR]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile);
|
|
||||||
string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile);
|
|
||||||
string newMemory = toDir + UI_DIR_SEPARATOR + Basename(memoryfile);
|
|
||||||
|
|
||||||
if (!UIMoveFile(dumpfile, newDump)) {
|
|
||||||
UIError(gStrings[ST_ERROR_DUMPFILEMOVE]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UIMoveFile(extrafile, newExtra)) {
|
|
||||||
UIError(gStrings[ST_ERROR_EXTRAFILEMOVE]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memoryfile.empty()) {
|
|
||||||
// Ignore errors from moving the memory file
|
|
||||||
if (!UIMoveFile(memoryfile, newMemory)) {
|
|
||||||
UIDeleteFile(memoryfile);
|
|
||||||
newMemory.erase();
|
|
||||||
}
|
|
||||||
memoryfile = newMemory;
|
|
||||||
}
|
|
||||||
|
|
||||||
dumpfile = newDump;
|
|
||||||
extrafile = newExtra;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool AddSubmittedReport(const string& serverResponse)
|
|
||||||
{
|
|
||||||
StringTable responseItems;
|
|
||||||
istringstream in(serverResponse);
|
|
||||||
ReadStrings(in, responseItems, false);
|
|
||||||
|
|
||||||
if (responseItems.find("StopSendingReportsFor") != responseItems.end()) {
|
|
||||||
// server wants to tell us to stop sending reports for a certain version
|
|
||||||
string reportPath =
|
|
||||||
gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" +
|
|
||||||
responseItems["StopSendingReportsFor"];
|
|
||||||
|
|
||||||
ofstream* reportFile = UIOpenWrite(reportPath);
|
|
||||||
if (reportFile->is_open()) {
|
|
||||||
// don't really care about the contents
|
|
||||||
*reportFile << 1 << "\n";
|
|
||||||
reportFile->close();
|
|
||||||
}
|
|
||||||
delete reportFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (responseItems.find("Discarded") != responseItems.end()) {
|
|
||||||
// server discarded this report... save it so the user can resubmit it
|
|
||||||
// manually
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (responseItems.find("CrashID") == responseItems.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
string submittedDir =
|
|
||||||
gSettingsPath + UI_DIR_SEPARATOR + "submitted";
|
|
||||||
if (!UIEnsurePathExists(submittedDir)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string path = submittedDir + UI_DIR_SEPARATOR +
|
|
||||||
responseItems["CrashID"] + ".txt";
|
|
||||||
|
|
||||||
ofstream* file = UIOpenWrite(path);
|
|
||||||
if (!file->is_open()) {
|
|
||||||
delete file;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buf[1024];
|
|
||||||
UI_SNPRINTF(buf, 1024,
|
|
||||||
gStrings["CrashID"].c_str(),
|
|
||||||
responseItems["CrashID"].c_str());
|
|
||||||
*file << buf << "\n";
|
|
||||||
|
|
||||||
if (responseItems.find("ViewURL") != responseItems.end()) {
|
|
||||||
UI_SNPRINTF(buf, 1024,
|
|
||||||
gStrings["CrashDetailsURL"].c_str(),
|
|
||||||
responseItems["ViewURL"].c_str());
|
|
||||||
*file << buf << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
file->close();
|
|
||||||
delete file;
|
|
||||||
|
|
||||||
WriteSubmissionEvent(Succeeded, responseItems["CrashID"]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeleteDump()
|
|
||||||
{
|
|
||||||
const char* noDelete = getenv("MOZ_CRASHREPORTER_NO_DELETE_DUMP");
|
|
||||||
if (!noDelete || *noDelete == '\0') {
|
|
||||||
if (!gReporterDumpFile.empty())
|
|
||||||
UIDeleteFile(gReporterDumpFile);
|
|
||||||
if (!gExtraFile.empty())
|
|
||||||
UIDeleteFile(gExtraFile);
|
|
||||||
if (!gMemoryFile.empty())
|
|
||||||
UIDeleteFile(gMemoryFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendCompleted(bool success, const string& serverResponse)
|
|
||||||
{
|
|
||||||
if (success) {
|
|
||||||
if (AddSubmittedReport(serverResponse)) {
|
|
||||||
DeleteDump();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
string directory = gReporterDumpFile;
|
|
||||||
int slashpos = directory.find_last_of("/\\");
|
|
||||||
if (slashpos < 2)
|
|
||||||
return;
|
|
||||||
directory.resize(slashpos);
|
|
||||||
UIPruneSavedDumps(directory);
|
|
||||||
WriteSubmissionEvent(Failed, "");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
WriteSubmissionEvent(Failed, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShouldEnableSending()
|
|
||||||
{
|
|
||||||
srand(time(0));
|
|
||||||
return ((rand() % 100) < MOZ_CRASHREPORTER_ENABLE_PERCENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace CrashReporter
|
|
||||||
|
|
||||||
using namespace CrashReporter;
|
|
||||||
|
|
||||||
void RewriteStrings(StringTable& queryParameters)
|
|
||||||
{
|
|
||||||
// rewrite some UI strings with the values from the query parameters
|
|
||||||
string product = queryParameters["ProductName"];
|
|
||||||
string vendor = queryParameters["Vendor"];
|
|
||||||
if (vendor.empty()) {
|
|
||||||
// Assume Mozilla if no vendor is specified
|
|
||||||
vendor = "Mozilla";
|
|
||||||
}
|
|
||||||
|
|
||||||
char buf[4096];
|
|
||||||
UI_SNPRINTF(buf, sizeof(buf),
|
|
||||||
gStrings[ST_CRASHREPORTERVENDORTITLE].c_str(),
|
|
||||||
vendor.c_str());
|
|
||||||
gStrings[ST_CRASHREPORTERTITLE] = buf;
|
|
||||||
|
|
||||||
|
|
||||||
string str = gStrings[ST_CRASHREPORTERPRODUCTERROR];
|
|
||||||
// Only do the replacement here if the string has two
|
|
||||||
// format specifiers to start. Otherwise
|
|
||||||
// we assume it has the product name hardcoded.
|
|
||||||
string::size_type pos = str.find("%s");
|
|
||||||
if (pos != string::npos)
|
|
||||||
pos = str.find("%s", pos+2);
|
|
||||||
if (pos != string::npos) {
|
|
||||||
// Leave a format specifier for UIError to fill in
|
|
||||||
UI_SNPRINTF(buf, sizeof(buf),
|
|
||||||
gStrings[ST_CRASHREPORTERPRODUCTERROR].c_str(),
|
|
||||||
product.c_str(),
|
|
||||||
"%s");
|
|
||||||
gStrings[ST_CRASHREPORTERERROR] = buf;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// product name is hardcoded
|
|
||||||
gStrings[ST_CRASHREPORTERERROR] = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
UI_SNPRINTF(buf, sizeof(buf),
|
|
||||||
gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(),
|
|
||||||
product.c_str());
|
|
||||||
gStrings[ST_CRASHREPORTERDESCRIPTION] = buf;
|
|
||||||
|
|
||||||
UI_SNPRINTF(buf, sizeof(buf),
|
|
||||||
gStrings[ST_CHECKSUBMIT].c_str(),
|
|
||||||
vendor.c_str());
|
|
||||||
gStrings[ST_CHECKSUBMIT] = buf;
|
|
||||||
|
|
||||||
UI_SNPRINTF(buf, sizeof(buf),
|
|
||||||
gStrings[ST_CHECKEMAIL].c_str(),
|
|
||||||
vendor.c_str());
|
|
||||||
gStrings[ST_CHECKEMAIL] = buf;
|
|
||||||
|
|
||||||
UI_SNPRINTF(buf, sizeof(buf),
|
|
||||||
gStrings[ST_RESTART].c_str(),
|
|
||||||
product.c_str());
|
|
||||||
gStrings[ST_RESTART] = buf;
|
|
||||||
|
|
||||||
UI_SNPRINTF(buf, sizeof(buf),
|
|
||||||
gStrings[ST_QUIT].c_str(),
|
|
||||||
product.c_str());
|
|
||||||
gStrings[ST_QUIT] = buf;
|
|
||||||
|
|
||||||
UI_SNPRINTF(buf, sizeof(buf),
|
|
||||||
gStrings[ST_ERROR_ENDOFLIFE].c_str(),
|
|
||||||
product.c_str());
|
|
||||||
gStrings[ST_ERROR_ENDOFLIFE] = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CheckEndOfLifed(string version)
|
|
||||||
{
|
|
||||||
string reportPath =
|
|
||||||
gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + version;
|
|
||||||
return UIFileExists(reportPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef RELEASE_OR_BETA
|
|
||||||
|
|
||||||
static string
|
|
||||||
GetMinidumpAnalyzerPath()
|
|
||||||
{
|
|
||||||
string path = gArgv[0];
|
|
||||||
size_t pos = path.rfind(UI_CRASH_REPORTER_FILENAME BIN_SUFFIX);
|
|
||||||
path.erase(pos);
|
|
||||||
path.append(UI_MINIDUMP_ANALYZER_FILENAME BIN_SUFFIX);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
gArgc = argc;
|
|
||||||
gArgv = argv;
|
|
||||||
|
|
||||||
if (!ReadConfig()) {
|
|
||||||
UIError("Couldn't read configuration.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UIInit())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
gReporterDumpFile = argv[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gReporterDumpFile.empty()) {
|
|
||||||
// no dump file specified, run the default UI
|
|
||||||
UIShowDefaultUI();
|
|
||||||
} else {
|
|
||||||
#ifndef RELEASE_OR_BETA
|
|
||||||
// start by running minidump analyzer, this is currently enabled only in
|
|
||||||
// nightly and aurora
|
|
||||||
UIRunMinidumpAnalyzer(GetMinidumpAnalyzerPath(), gReporterDumpFile);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// go ahead with the crash reporter
|
|
||||||
gExtraFile = GetAdditionalFilename(gReporterDumpFile, kExtraDataExtension);
|
|
||||||
if (gExtraFile.empty()) {
|
|
||||||
UIError(gStrings[ST_ERROR_BADARGUMENTS]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UIFileExists(gExtraFile)) {
|
|
||||||
UIError(gStrings[ST_ERROR_EXTRAFILEEXISTS]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
gMemoryFile = GetAdditionalFilename(gReporterDumpFile,
|
|
||||||
kMemoryReportExtension);
|
|
||||||
if (!UIFileExists(gMemoryFile)) {
|
|
||||||
gMemoryFile.erase();
|
|
||||||
}
|
|
||||||
|
|
||||||
StringTable queryParameters;
|
|
||||||
if (!ReadStringsFromFile(gExtraFile, queryParameters, true)) {
|
|
||||||
UIError(gStrings[ST_ERROR_EXTRAFILEREAD]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryParameters.find("ProductName") == queryParameters.end()) {
|
|
||||||
UIError(gStrings[ST_ERROR_NOPRODUCTNAME]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is enough information in the extra file to rewrite strings
|
|
||||||
// to be product specific
|
|
||||||
RewriteStrings(queryParameters);
|
|
||||||
|
|
||||||
if (queryParameters.find("ServerURL") == queryParameters.end()) {
|
|
||||||
UIError(gStrings[ST_ERROR_NOSERVERURL]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hopefully the settings path exists in the environment. Try that before
|
|
||||||
// asking the platform-specific code to guess.
|
|
||||||
#ifdef XP_WIN32
|
|
||||||
static const wchar_t kDataDirKey[] = L"MOZ_CRASHREPORTER_DATA_DIRECTORY";
|
|
||||||
const wchar_t *settingsPath = _wgetenv(kDataDirKey);
|
|
||||||
if (settingsPath && *settingsPath) {
|
|
||||||
gSettingsPath = WideToUTF8(settingsPath);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static const char kDataDirKey[] = "MOZ_CRASHREPORTER_DATA_DIRECTORY";
|
|
||||||
const char *settingsPath = getenv(kDataDirKey);
|
|
||||||
if (settingsPath && *settingsPath) {
|
|
||||||
gSettingsPath = settingsPath;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else {
|
|
||||||
string product = queryParameters["ProductName"];
|
|
||||||
string vendor = queryParameters["Vendor"];
|
|
||||||
if (!UIGetSettingsPath(vendor, product, gSettingsPath)) {
|
|
||||||
gSettingsPath.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gSettingsPath.empty() || !UIEnsurePathExists(gSettingsPath)) {
|
|
||||||
UIError(gStrings[ST_ERROR_NOSETTINGSPATH]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenLogFile();
|
|
||||||
|
|
||||||
#ifdef XP_WIN32
|
|
||||||
static const wchar_t kEventsDirKey[] = L"MOZ_CRASHREPORTER_EVENTS_DIRECTORY";
|
|
||||||
const wchar_t *eventsPath = _wgetenv(kEventsDirKey);
|
|
||||||
if (eventsPath && *eventsPath) {
|
|
||||||
gEventsPath = WideToUTF8(eventsPath);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static const char kEventsDirKey[] = "MOZ_CRASHREPORTER_EVENTS_DIRECTORY";
|
|
||||||
const char *eventsPath = getenv(kEventsDirKey);
|
|
||||||
if (eventsPath && *eventsPath) {
|
|
||||||
gEventsPath = eventsPath;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else {
|
|
||||||
gEventsPath.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the crash event with stacks if they are present
|
|
||||||
auto stackTracesItr = queryParameters.find("StackTraces");
|
|
||||||
if (stackTracesItr != queryParameters.end()) {
|
|
||||||
AppendStackTracesToEventFile(stackTracesItr->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UIFileExists(gReporterDumpFile)) {
|
|
||||||
UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending";
|
|
||||||
if (!MoveCrashData(pendingDir, gReporterDumpFile, gExtraFile,
|
|
||||||
gMemoryFile)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string sendURL = queryParameters["ServerURL"];
|
|
||||||
// we don't need to actually send this
|
|
||||||
queryParameters.erase("ServerURL");
|
|
||||||
|
|
||||||
queryParameters["Throttleable"] = "1";
|
|
||||||
|
|
||||||
// re-set XUL_APP_FILE for xulrunner wrapped apps
|
|
||||||
const char *appfile = getenv("MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE");
|
|
||||||
if (appfile && *appfile) {
|
|
||||||
const char prefix[] = "XUL_APP_FILE=";
|
|
||||||
char *env = (char*) malloc(strlen(appfile) + strlen(prefix) + 1);
|
|
||||||
if (!env) {
|
|
||||||
UIError("Out of memory");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
strcpy(env, prefix);
|
|
||||||
strcat(env, appfile);
|
|
||||||
putenv(env);
|
|
||||||
free(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<string> restartArgs;
|
|
||||||
|
|
||||||
ostringstream paramName;
|
|
||||||
int i = 0;
|
|
||||||
paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
|
|
||||||
const char *param = getenv(paramName.str().c_str());
|
|
||||||
while (param && *param) {
|
|
||||||
restartArgs.push_back(param);
|
|
||||||
|
|
||||||
paramName.str("");
|
|
||||||
paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
|
|
||||||
param = getenv(paramName.str().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// allow override of the server url via environment variable
|
|
||||||
//XXX: remove this in the far future when our robot
|
|
||||||
// masters force everyone to use XULRunner
|
|
||||||
char* urlEnv = getenv("MOZ_CRASHREPORTER_URL");
|
|
||||||
if (urlEnv && *urlEnv) {
|
|
||||||
sendURL = urlEnv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// see if this version has been end-of-lifed
|
|
||||||
if (queryParameters.find("Version") != queryParameters.end() &&
|
|
||||||
CheckEndOfLifed(queryParameters["Version"])) {
|
|
||||||
UIError(gStrings[ST_ERROR_ENDOFLIFE]);
|
|
||||||
DeleteDump();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringTable files;
|
|
||||||
files["upload_file_minidump"] = gReporterDumpFile;
|
|
||||||
if (!gMemoryFile.empty()) {
|
|
||||||
files["memory_report"] = gMemoryFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UIShowCrashUI(files, queryParameters, sendURL, restartArgs))
|
|
||||||
DeleteDump();
|
|
||||||
}
|
|
||||||
|
|
||||||
UIShutdown();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(XP_WIN) && !defined(__GNUC__)
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// We need WinMain in order to not be a console app. This function is unused
|
|
||||||
// if we are a console application.
|
|
||||||
int WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR args, int )
|
|
||||||
{
|
|
||||||
// Remove everything except close window from the context menu
|
|
||||||
{
|
|
||||||
HKEY hkApp;
|
|
||||||
RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications", 0,
|
|
||||||
nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr,
|
|
||||||
&hkApp, nullptr);
|
|
||||||
RegCloseKey(hkApp);
|
|
||||||
if (RegCreateKeyExW(HKEY_CURRENT_USER,
|
|
||||||
L"Software\\Classes\\Applications\\crashreporter.exe",
|
|
||||||
0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE,
|
|
||||||
nullptr, &hkApp, nullptr) == ERROR_SUCCESS) {
|
|
||||||
RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0);
|
|
||||||
RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0);
|
|
||||||
RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0);
|
|
||||||
RegCloseKey(hkApp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char** argv = static_cast<char**>(malloc(__argc * sizeof(char*)));
|
|
||||||
for (int i = 0; i < __argc; i++) {
|
|
||||||
argv[i] = strdup(WideToUTF8(__wargv[i]).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the real work.
|
|
||||||
return main(__argc, argv);
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,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>
|
|
|
@ -1,158 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef CRASHREPORTER_H__
|
|
||||||
#define CRASHREPORTER_H__
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# pragma warning( push )
|
|
||||||
// Disable exception handler warnings.
|
|
||||||
# pragma warning( disable : 4530 )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#define MAX_COMMENT_LENGTH 500
|
|
||||||
|
|
||||||
#if defined(XP_WIN32)
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#define UI_SNPRINTF _snprintf
|
|
||||||
#define UI_DIR_SEPARATOR "\\"
|
|
||||||
|
|
||||||
std::string WideToUTF8(const std::wstring& wide, bool* success = 0);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define UI_SNPRINTF snprintf
|
|
||||||
#define UI_DIR_SEPARATOR "/"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define UI_CRASH_REPORTER_FILENAME "crashreporter"
|
|
||||||
#define UI_MINIDUMP_ANALYZER_FILENAME "minidump-analyzer"
|
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> StringTable;
|
|
||||||
|
|
||||||
#define ST_CRASHREPORTERTITLE "CrashReporterTitle"
|
|
||||||
#define ST_CRASHREPORTERVENDORTITLE "CrashReporterVendorTitle"
|
|
||||||
#define ST_CRASHREPORTERERROR "CrashReporterErrorText"
|
|
||||||
#define ST_CRASHREPORTERPRODUCTERROR "CrashReporterProductErrorText2"
|
|
||||||
#define ST_CRASHREPORTERHEADER "CrashReporterSorry"
|
|
||||||
#define ST_CRASHREPORTERDESCRIPTION "CrashReporterDescriptionText2"
|
|
||||||
#define ST_CRASHREPORTERDEFAULT "CrashReporterDefault"
|
|
||||||
#define ST_VIEWREPORT "Details"
|
|
||||||
#define ST_VIEWREPORTTITLE "ViewReportTitle"
|
|
||||||
#define ST_COMMENTGRAYTEXT "CommentGrayText"
|
|
||||||
#define ST_EXTRAREPORTINFO "ExtraReportInfo"
|
|
||||||
#define ST_CHECKSUBMIT "CheckSendReport"
|
|
||||||
#define ST_CHECKURL "CheckIncludeURL"
|
|
||||||
#define ST_CHECKEMAIL "CheckAllowEmail"
|
|
||||||
#define ST_EMAILGRAYTEXT "EmailGrayText"
|
|
||||||
#define ST_REPORTPRESUBMIT "ReportPreSubmit2"
|
|
||||||
#define ST_REPORTDURINGSUBMIT "ReportDuringSubmit2"
|
|
||||||
#define ST_REPORTSUBMITSUCCESS "ReportSubmitSuccess"
|
|
||||||
#define ST_SUBMITFAILED "ReportSubmitFailed"
|
|
||||||
#define ST_QUIT "Quit2"
|
|
||||||
#define ST_RESTART "Restart"
|
|
||||||
#define ST_OK "Ok"
|
|
||||||
#define ST_CLOSE "Close"
|
|
||||||
|
|
||||||
#define ST_ERROR_BADARGUMENTS "ErrorBadArguments"
|
|
||||||
#define ST_ERROR_EXTRAFILEEXISTS "ErrorExtraFileExists"
|
|
||||||
#define ST_ERROR_EXTRAFILEREAD "ErrorExtraFileRead"
|
|
||||||
#define ST_ERROR_EXTRAFILEMOVE "ErrorExtraFileMove"
|
|
||||||
#define ST_ERROR_DUMPFILEEXISTS "ErrorDumpFileExists"
|
|
||||||
#define ST_ERROR_DUMPFILEMOVE "ErrorDumpFileMove"
|
|
||||||
#define ST_ERROR_NOPRODUCTNAME "ErrorNoProductName"
|
|
||||||
#define ST_ERROR_NOSERVERURL "ErrorNoServerURL"
|
|
||||||
#define ST_ERROR_NOSETTINGSPATH "ErrorNoSettingsPath"
|
|
||||||
#define ST_ERROR_CREATEDUMPDIR "ErrorCreateDumpDir"
|
|
||||||
#define ST_ERROR_ENDOFLIFE "ErrorEndOfLife"
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// implemented in crashreporter.cpp
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
namespace CrashReporter {
|
|
||||||
extern StringTable gStrings;
|
|
||||||
extern std::string gSettingsPath;
|
|
||||||
extern std::string gEventsPath;
|
|
||||||
extern int gArgc;
|
|
||||||
extern char** gArgv;
|
|
||||||
|
|
||||||
void UIError(const std::string& message);
|
|
||||||
|
|
||||||
// The UI finished sending the report
|
|
||||||
void SendCompleted(bool success, const std::string& serverResponse);
|
|
||||||
|
|
||||||
bool ReadStrings(std::istream& in,
|
|
||||||
StringTable& strings,
|
|
||||||
bool unescape);
|
|
||||||
bool ReadStringsFromFile(const std::string& path,
|
|
||||||
StringTable& strings,
|
|
||||||
bool unescape);
|
|
||||||
bool WriteStrings(std::ostream& out,
|
|
||||||
const std::string& header,
|
|
||||||
StringTable& strings,
|
|
||||||
bool escape);
|
|
||||||
bool WriteStringsToFile(const std::string& path,
|
|
||||||
const std::string& header,
|
|
||||||
StringTable& strings,
|
|
||||||
bool escape);
|
|
||||||
void LogMessage(const std::string& message);
|
|
||||||
void DeleteDump();
|
|
||||||
bool ShouldEnableSending();
|
|
||||||
|
|
||||||
static const unsigned int kSaveCount = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// implemented in the platform-specific files
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
bool UIInit();
|
|
||||||
void UIShutdown();
|
|
||||||
|
|
||||||
// Run the UI for when the app was launched without a dump file
|
|
||||||
void UIShowDefaultUI();
|
|
||||||
|
|
||||||
// Run the UI for when the app was launched with a dump file
|
|
||||||
// Return true if the user sent (or tried to send) the crash report,
|
|
||||||
// false if they chose not to, and it should be deleted.
|
|
||||||
bool UIShowCrashUI(const StringTable& files,
|
|
||||||
const StringTable& queryParameters,
|
|
||||||
const std::string& sendURL,
|
|
||||||
const std::vector<std::string>& restartArgs);
|
|
||||||
|
|
||||||
void UIError_impl(const std::string& message);
|
|
||||||
|
|
||||||
bool UIGetIniPath(std::string& path);
|
|
||||||
bool UIGetSettingsPath(const std::string& vendor,
|
|
||||||
const std::string& product,
|
|
||||||
std::string& settingsPath);
|
|
||||||
bool UIEnsurePathExists(const std::string& path);
|
|
||||||
bool UIFileExists(const std::string& path);
|
|
||||||
bool UIMoveFile(const std::string& oldfile, const std::string& newfile);
|
|
||||||
bool UIDeleteFile(const std::string& oldfile);
|
|
||||||
std::ifstream* UIOpenRead(const std::string& filename);
|
|
||||||
std::ofstream* UIOpenWrite(const std::string& filename,
|
|
||||||
bool append=false,
|
|
||||||
bool binary=false);
|
|
||||||
void UIPruneSavedDumps(const std::string& directory);
|
|
||||||
void UIRunMinidumpAnalyzer(const std::string& exename,
|
|
||||||
const std::string& filename);
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# pragma warning( pop )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
|
@ -1,148 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
// Microsoft Visual C++ generated resource script.
|
|
||||||
//
|
|
||||||
#include "resource.h"
|
|
||||||
|
|
||||||
#define APSTUDIO_READONLY_SYMBOLS
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Generated from the TEXTINCLUDE 2 resource.
|
|
||||||
//
|
|
||||||
#include "winresrc.h"
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
#undef APSTUDIO_READONLY_SYMBOLS
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// English (U.S.) resources
|
|
||||||
|
|
||||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
|
||||||
#ifdef _WIN32
|
|
||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
|
||||||
#pragma code_page(1252)
|
|
||||||
#endif //_WIN32
|
|
||||||
|
|
||||||
#ifdef APSTUDIO_INVOKED
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// TEXTINCLUDE
|
|
||||||
//
|
|
||||||
|
|
||||||
1 TEXTINCLUDE
|
|
||||||
BEGIN
|
|
||||||
"resource.h\0"
|
|
||||||
END
|
|
||||||
|
|
||||||
2 TEXTINCLUDE
|
|
||||||
BEGIN
|
|
||||||
"#include ""winresrc.h""\r\n"
|
|
||||||
"\0"
|
|
||||||
END
|
|
||||||
|
|
||||||
3 TEXTINCLUDE
|
|
||||||
BEGIN
|
|
||||||
"\r\n"
|
|
||||||
"\0"
|
|
||||||
END
|
|
||||||
|
|
||||||
#endif // APSTUDIO_INVOKED
|
|
||||||
|
|
||||||
1 24 "crashreporter.exe.manifest"
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Icon
|
|
||||||
//
|
|
||||||
|
|
||||||
// Icon with lowest ID value placed first to ensure application icon
|
|
||||||
// remains consistent on all systems.
|
|
||||||
IDI_MAINICON ICON "crashreporter.ico"
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// AVI
|
|
||||||
//
|
|
||||||
|
|
||||||
IDR_THROBBER AVI "Throbber-small.avi"
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Dialog
|
|
||||||
//
|
|
||||||
|
|
||||||
IDD_SENDDIALOG DIALOGEX 0, 0, 241, 187
|
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
|
||||||
EXSTYLE WS_EX_APPWINDOW
|
|
||||||
CAPTION "Sending Crash Report..."
|
|
||||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
|
||||||
BEGIN
|
|
||||||
CONTROL "",IDC_DESCRIPTIONTEXT,"RICHEDIT50W",ES_MULTILINE | ES_READONLY,8,7,226,12,WS_EX_TRANSPARENT
|
|
||||||
CONTROL "tell mozilla about this crash so they can fix it",IDC_SUBMITREPORTCHECK,
|
|
||||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,25,222,10
|
|
||||||
CHECKBOX "details...",IDC_VIEWREPORTBUTTON,24,40,54,14,BS_PUSHLIKE
|
|
||||||
EDITTEXT IDC_COMMENTTEXT,24,59,210,43,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL
|
|
||||||
CONTROL "include the address of the page i was on",IDC_INCLUDEURLCHECK,
|
|
||||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,107,210,10
|
|
||||||
CONTROL "tell mozilla to email me with more information",IDC_EMAILMECHECK,
|
|
||||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,120,210,10
|
|
||||||
EDITTEXT IDC_EMAILTEXT,36,133,198,14,ES_AUTOHSCROLL
|
|
||||||
CONTROL "",IDC_THROBBER,"SysAnimate32",ACS_TRANSPARENT | NOT WS_VISIBLE | WS_TABSTOP,4,152,16,16
|
|
||||||
LTEXT "your crash report will be submitted when you restart",IDC_PROGRESSTEXT,24,152,210,10,SS_NOPREFIX
|
|
||||||
DEFPUSHBUTTON "restart firefox",IDC_RESTARTBUTTON,84,166,68,14
|
|
||||||
PUSHBUTTON "quit without sending",IDC_CLOSEBUTTON,157,166,77,14
|
|
||||||
END
|
|
||||||
|
|
||||||
IDD_VIEWREPORTDIALOG DIALOGEX 0, 0, 208, 126
|
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
|
|
||||||
CAPTION "view report"
|
|
||||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
|
||||||
BEGIN
|
|
||||||
CONTROL "",IDC_VIEWREPORTTEXT,"RICHEDIT50W",ES_MULTILINE | ES_READONLY | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,194,92
|
|
||||||
DEFPUSHBUTTON "OK",IDOK,151,105,50,14
|
|
||||||
END
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// DESIGNINFO
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifdef APSTUDIO_INVOKED
|
|
||||||
GUIDELINES DESIGNINFO
|
|
||||||
BEGIN
|
|
||||||
IDD_SENDDIALOG, DIALOG
|
|
||||||
BEGIN
|
|
||||||
LEFTMARGIN, 8
|
|
||||||
RIGHTMARGIN, 234
|
|
||||||
TOPMARGIN, 7
|
|
||||||
BOTTOMMARGIN, 180
|
|
||||||
END
|
|
||||||
|
|
||||||
IDD_VIEWREPORTDIALOG, DIALOG
|
|
||||||
BEGIN
|
|
||||||
LEFTMARGIN, 7
|
|
||||||
RIGHTMARGIN, 201
|
|
||||||
TOPMARGIN, 7
|
|
||||||
BOTTOMMARGIN, 119
|
|
||||||
END
|
|
||||||
END
|
|
||||||
#endif // APSTUDIO_INVOKED
|
|
||||||
|
|
||||||
#endif // English (U.S.) resources
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef APSTUDIO_INVOKED
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Generated from the TEXTINCLUDE 3 resource.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
#endif // not APSTUDIO_INVOKED
|
|
||||||
|
|
|
@ -1,453 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "crashreporter.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <gdk/gdkkeysyms.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/linux/http_upload.h"
|
|
||||||
#include "crashreporter.h"
|
|
||||||
#include "crashreporter_gtk_common.h"
|
|
||||||
|
|
||||||
#ifndef GDK_KEY_Escape
|
|
||||||
#define GDK_KEY_Escape GDK_Escape
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
using namespace CrashReporter;
|
|
||||||
|
|
||||||
GtkWidget* gWindow = 0;
|
|
||||||
GtkWidget* gSubmitReportCheck = 0;
|
|
||||||
GtkWidget* gIncludeURLCheck = 0;
|
|
||||||
GtkWidget* gThrobber = 0;
|
|
||||||
GtkWidget* gProgressLabel = 0;
|
|
||||||
GtkWidget* gCloseButton = 0;
|
|
||||||
GtkWidget* gRestartButton = 0;
|
|
||||||
|
|
||||||
bool gInitialized = false;
|
|
||||||
bool gDidTrySend = false;
|
|
||||||
StringTable gFiles;
|
|
||||||
StringTable gQueryParameters;
|
|
||||||
string gHttpProxy;
|
|
||||||
string gAuth;
|
|
||||||
string gCACertificateFile;
|
|
||||||
string gSendURL;
|
|
||||||
string gURLParameter;
|
|
||||||
vector<string> gRestartArgs;
|
|
||||||
GThread* gSendThreadID;
|
|
||||||
|
|
||||||
// From crashreporter_linux.cpp
|
|
||||||
void SaveSettings();
|
|
||||||
void SendReport();
|
|
||||||
void TryInitGnome();
|
|
||||||
void UpdateSubmit();
|
|
||||||
|
|
||||||
static bool RestartApplication()
|
|
||||||
{
|
|
||||||
char** argv = reinterpret_cast<char**>(
|
|
||||||
malloc(sizeof(char*) * (gRestartArgs.size() + 1)));
|
|
||||||
|
|
||||||
if (!argv) return false;
|
|
||||||
|
|
||||||
unsigned int i;
|
|
||||||
for (i = 0; i < gRestartArgs.size(); i++) {
|
|
||||||
argv[i] = (char*)gRestartArgs[i].c_str();
|
|
||||||
}
|
|
||||||
argv[i] = 0;
|
|
||||||
|
|
||||||
pid_t pid = fork();
|
|
||||||
if (pid == -1)
|
|
||||||
return false;
|
|
||||||
else if (pid == 0) {
|
|
||||||
(void)execv(argv[0], argv);
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(argv);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quit the app, used as a timeout callback
|
|
||||||
static gboolean CloseApp(gpointer data)
|
|
||||||
{
|
|
||||||
gtk_main_quit();
|
|
||||||
g_thread_join(gSendThreadID);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean ReportCompleted(gpointer success)
|
|
||||||
{
|
|
||||||
gtk_widget_hide(gThrobber);
|
|
||||||
string str = success ? gStrings[ST_REPORTSUBMITSUCCESS]
|
|
||||||
: gStrings[ST_SUBMITFAILED];
|
|
||||||
gtk_label_set_text(GTK_LABEL(gProgressLabel), str.c_str());
|
|
||||||
g_timeout_add(5000, CloseApp, 0);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MOZ_ENABLE_GCONF
|
|
||||||
#define HTTP_PROXY_DIR "/system/http_proxy"
|
|
||||||
|
|
||||||
void LoadProxyinfo()
|
|
||||||
{
|
|
||||||
class GConfClient;
|
|
||||||
typedef GConfClient * (*_gconf_default_fn)();
|
|
||||||
typedef gboolean (*_gconf_bool_fn)(GConfClient *, const gchar *, GError **);
|
|
||||||
typedef gint (*_gconf_int_fn)(GConfClient *, const gchar *, GError **);
|
|
||||||
typedef gchar * (*_gconf_string_fn)(GConfClient *, const gchar *, GError **);
|
|
||||||
|
|
||||||
if (getenv ("http_proxy"))
|
|
||||||
return; // libcurl can use the value from the environment
|
|
||||||
|
|
||||||
static void* gconfLib = dlopen("libgconf-2.so.4", RTLD_LAZY);
|
|
||||||
if (!gconfLib)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_gconf_default_fn gconf_client_get_default =
|
|
||||||
(_gconf_default_fn)dlsym(gconfLib, "gconf_client_get_default");
|
|
||||||
_gconf_bool_fn gconf_client_get_bool =
|
|
||||||
(_gconf_bool_fn)dlsym(gconfLib, "gconf_client_get_bool");
|
|
||||||
_gconf_int_fn gconf_client_get_int =
|
|
||||||
(_gconf_int_fn)dlsym(gconfLib, "gconf_client_get_int");
|
|
||||||
_gconf_string_fn gconf_client_get_string =
|
|
||||||
(_gconf_string_fn)dlsym(gconfLib, "gconf_client_get_string");
|
|
||||||
|
|
||||||
if(!(gconf_client_get_default &&
|
|
||||||
gconf_client_get_bool &&
|
|
||||||
gconf_client_get_int &&
|
|
||||||
gconf_client_get_string)) {
|
|
||||||
dlclose(gconfLib);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GConfClient *conf = gconf_client_get_default();
|
|
||||||
|
|
||||||
if (gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_http_proxy", nullptr)) {
|
|
||||||
gint port;
|
|
||||||
gchar *host = nullptr, *httpproxy = nullptr;
|
|
||||||
|
|
||||||
host = gconf_client_get_string(conf, HTTP_PROXY_DIR "/host", nullptr);
|
|
||||||
port = gconf_client_get_int(conf, HTTP_PROXY_DIR "/port", nullptr);
|
|
||||||
|
|
||||||
if (port && host && *host != '\0') {
|
|
||||||
httpproxy = g_strdup_printf("http://%s:%d/", host, port);
|
|
||||||
gHttpProxy = httpproxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free(host);
|
|
||||||
g_free(httpproxy);
|
|
||||||
|
|
||||||
if (gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_authentication",
|
|
||||||
nullptr)) {
|
|
||||||
gchar *user, *password, *auth = nullptr;
|
|
||||||
|
|
||||||
user = gconf_client_get_string(conf,
|
|
||||||
HTTP_PROXY_DIR "/authentication_user",
|
|
||||||
nullptr);
|
|
||||||
password = gconf_client_get_string(conf,
|
|
||||||
HTTP_PROXY_DIR
|
|
||||||
"/authentication_password",
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
if (user && password) {
|
|
||||||
auth = g_strdup_printf("%s:%s", user, password);
|
|
||||||
gAuth = auth;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free(user);
|
|
||||||
g_free(password);
|
|
||||||
g_free(auth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_unref(conf);
|
|
||||||
|
|
||||||
// Don't dlclose gconfLib as libORBit-2 uses atexit().
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gpointer SendThread(gpointer args)
|
|
||||||
{
|
|
||||||
string response, error;
|
|
||||||
long response_code;
|
|
||||||
|
|
||||||
bool success = google_breakpad::HTTPUpload::SendRequest
|
|
||||||
(gSendURL,
|
|
||||||
gQueryParameters,
|
|
||||||
gFiles,
|
|
||||||
gHttpProxy, gAuth,
|
|
||||||
gCACertificateFile,
|
|
||||||
&response,
|
|
||||||
&response_code,
|
|
||||||
&error);
|
|
||||||
if (success) {
|
|
||||||
LogMessage("Crash report submitted successfully");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LogMessage("Crash report submission failed: " + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
SendCompleted(success, response);
|
|
||||||
// Apparently glib is threadsafe, and will schedule this
|
|
||||||
// on the main thread, see:
|
|
||||||
// http://library.gnome.org/devel/gtk-faq/stable/x499.html
|
|
||||||
g_idle_add(ReportCompleted, (gpointer)success);
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean WindowDeleted(GtkWidget* window,
|
|
||||||
GdkEvent* event,
|
|
||||||
gpointer userData)
|
|
||||||
{
|
|
||||||
SaveSettings();
|
|
||||||
gtk_main_quit();
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean check_escape(GtkWidget* window,
|
|
||||||
GdkEventKey* event,
|
|
||||||
gpointer userData)
|
|
||||||
{
|
|
||||||
if (event->keyval == GDK_KEY_Escape) {
|
|
||||||
gtk_main_quit();
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MaybeSubmitReport()
|
|
||||||
{
|
|
||||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
|
|
||||||
gDidTrySend = true;
|
|
||||||
SendReport();
|
|
||||||
} else {
|
|
||||||
gtk_main_quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CloseClicked(GtkButton* button,
|
|
||||||
gpointer userData)
|
|
||||||
{
|
|
||||||
SaveSettings();
|
|
||||||
MaybeSubmitReport();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestartClicked(GtkButton* button,
|
|
||||||
gpointer userData)
|
|
||||||
{
|
|
||||||
SaveSettings();
|
|
||||||
RestartApplication();
|
|
||||||
MaybeSubmitReport();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void UpdateURL()
|
|
||||||
{
|
|
||||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))) {
|
|
||||||
gQueryParameters["URL"] = gURLParameter;
|
|
||||||
} else {
|
|
||||||
gQueryParameters.erase("URL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SubmitReportChecked(GtkButton* sender, gpointer userData)
|
|
||||||
{
|
|
||||||
UpdateSubmit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IncludeURLClicked(GtkButton* sender, gpointer userData)
|
|
||||||
{
|
|
||||||
UpdateURL();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Crashreporter UI Functions === */
|
|
||||||
|
|
||||||
bool UIInit()
|
|
||||||
{
|
|
||||||
// breakpad probably left us with blocked signals, unblock them here
|
|
||||||
sigset_t signals, old;
|
|
||||||
sigfillset(&signals);
|
|
||||||
sigprocmask(SIG_UNBLOCK, &signals, &old);
|
|
||||||
|
|
||||||
// tell glib we're going to use threads
|
|
||||||
g_thread_init(nullptr);
|
|
||||||
|
|
||||||
if (gtk_init_check(&gArgc, &gArgv)) {
|
|
||||||
gInitialized = true;
|
|
||||||
|
|
||||||
if (gStrings.find("isRTL") != gStrings.end() &&
|
|
||||||
gStrings["isRTL"] == "yes")
|
|
||||||
gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIShowDefaultUI()
|
|
||||||
{
|
|
||||||
GtkWidget* errorDialog =
|
|
||||||
gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL,
|
|
||||||
GTK_MESSAGE_ERROR,
|
|
||||||
GTK_BUTTONS_CLOSE,
|
|
||||||
"%s", gStrings[ST_CRASHREPORTERDEFAULT].c_str());
|
|
||||||
|
|
||||||
gtk_window_set_title(GTK_WINDOW(errorDialog),
|
|
||||||
gStrings[ST_CRASHREPORTERTITLE].c_str());
|
|
||||||
gtk_dialog_run(GTK_DIALOG(errorDialog));
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIError_impl(const string& message)
|
|
||||||
{
|
|
||||||
if (!gInitialized) {
|
|
||||||
// Didn't initialize, this is the best we can do
|
|
||||||
printf("Error: %s\n", message.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GtkWidget* errorDialog =
|
|
||||||
gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL,
|
|
||||||
GTK_MESSAGE_ERROR,
|
|
||||||
GTK_BUTTONS_CLOSE,
|
|
||||||
"%s", message.c_str());
|
|
||||||
|
|
||||||
gtk_window_set_title(GTK_WINDOW(errorDialog),
|
|
||||||
gStrings[ST_CRASHREPORTERTITLE].c_str());
|
|
||||||
gtk_dialog_run(GTK_DIALOG(errorDialog));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIGetIniPath(string& path)
|
|
||||||
{
|
|
||||||
path = gArgv[0];
|
|
||||||
path.append(".ini");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Settings are stored in ~/.vendor/product, or
|
|
||||||
* ~/.product if vendor is empty.
|
|
||||||
*/
|
|
||||||
bool UIGetSettingsPath(const string& vendor,
|
|
||||||
const string& product,
|
|
||||||
string& settingsPath)
|
|
||||||
{
|
|
||||||
char* home = getenv("HOME");
|
|
||||||
|
|
||||||
if (!home)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
settingsPath = home;
|
|
||||||
settingsPath += "/.";
|
|
||||||
if (!vendor.empty()) {
|
|
||||||
string lc_vendor;
|
|
||||||
std::transform(vendor.begin(), vendor.end(), back_inserter(lc_vendor),
|
|
||||||
(int(*)(int)) std::tolower);
|
|
||||||
settingsPath += lc_vendor + "/";
|
|
||||||
}
|
|
||||||
string lc_product;
|
|
||||||
std::transform(product.begin(), product.end(), back_inserter(lc_product),
|
|
||||||
(int(*)(int)) std::tolower);
|
|
||||||
settingsPath += lc_product + "/Crash Reports";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIEnsurePathExists(const string& path)
|
|
||||||
{
|
|
||||||
int ret = mkdir(path.c_str(), S_IRWXU);
|
|
||||||
int e = errno;
|
|
||||||
if (ret == -1 && e != EEXIST)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIFileExists(const string& path)
|
|
||||||
{
|
|
||||||
struct stat sb;
|
|
||||||
int ret = stat(path.c_str(), &sb);
|
|
||||||
if (ret == -1 || !(sb.st_mode & S_IFREG))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIMoveFile(const string& file, const string& newfile)
|
|
||||||
{
|
|
||||||
if (!rename(file.c_str(), newfile.c_str()))
|
|
||||||
return true;
|
|
||||||
if (errno != EXDEV)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// use system /bin/mv instead, time to fork
|
|
||||||
pid_t pID = vfork();
|
|
||||||
if (pID < 0) {
|
|
||||||
// Failed to fork
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (pID == 0) {
|
|
||||||
char* const args[4] = {
|
|
||||||
const_cast<char*>("mv"),
|
|
||||||
strdup(file.c_str()),
|
|
||||||
strdup(newfile.c_str()),
|
|
||||||
0
|
|
||||||
};
|
|
||||||
if (args[1] && args[2])
|
|
||||||
execve("/bin/mv", args, 0);
|
|
||||||
free(args[1]);
|
|
||||||
free(args[2]);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
int status;
|
|
||||||
waitpid(pID, &status, 0);
|
|
||||||
return UIFileExists(newfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIDeleteFile(const string& file)
|
|
||||||
{
|
|
||||||
return (unlink(file.c_str()) != -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream* UIOpenRead(const string& filename)
|
|
||||||
{
|
|
||||||
return new std::ifstream(filename.c_str(), std::ios::in);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ofstream* UIOpenWrite(const string& filename,
|
|
||||||
bool append, // append=false
|
|
||||||
bool binary) // binary=false
|
|
||||||
{
|
|
||||||
std::ios_base::openmode mode = std::ios::out;
|
|
||||||
|
|
||||||
if (append) {
|
|
||||||
mode = mode | std::ios::app;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (binary) {
|
|
||||||
mode = mode | std::ios::binary;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new std::ofstream(filename.c_str(), mode);
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef CRASHREPORTER_GTK_COMMON_H__
|
|
||||||
#define CRASHREPORTER_GTK_COMMON_H__
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
const char kIniFile[] = "crashreporter.ini";
|
|
||||||
|
|
||||||
extern GtkWidget* gWindow;
|
|
||||||
extern GtkWidget* gSubmitReportCheck;
|
|
||||||
extern GtkWidget* gIncludeURLCheck;
|
|
||||||
extern GtkWidget* gThrobber;
|
|
||||||
extern GtkWidget* gProgressLabel;
|
|
||||||
extern GtkWidget* gCloseButton;
|
|
||||||
extern GtkWidget* gRestartButton;
|
|
||||||
|
|
||||||
extern std::vector<std::string> gRestartArgs;
|
|
||||||
extern GThread* gSendThreadID;
|
|
||||||
|
|
||||||
extern bool gInitialized;
|
|
||||||
extern bool gDidTrySend;
|
|
||||||
extern StringTable gFiles;
|
|
||||||
extern StringTable gQueryParameters;
|
|
||||||
extern std::string gHttpProxy;
|
|
||||||
extern std::string gAuth;
|
|
||||||
extern std::string gCACertificateFile;
|
|
||||||
extern std::string gSendURL;
|
|
||||||
extern std::string gURLParameter;
|
|
||||||
|
|
||||||
void LoadProxyinfo();
|
|
||||||
gpointer SendThread(gpointer args);
|
|
||||||
gboolean WindowDeleted(GtkWidget* window,
|
|
||||||
GdkEvent* event,
|
|
||||||
gpointer userData);
|
|
||||||
gboolean check_escape(GtkWidget* window, GdkEventKey* event, gpointer data);
|
|
||||||
void SubmitReportChecked(GtkButton* sender, gpointer userData);
|
|
||||||
void IncludeURLClicked(GtkButton* sender, gpointer userData);
|
|
||||||
void CloseClicked(GtkButton* button,
|
|
||||||
gpointer userData);
|
|
||||||
void RestartClicked(GtkButton* button,
|
|
||||||
gpointer userData);
|
|
||||||
|
|
||||||
#endif // CRASHREPORTER_GTK_COMMON_H__
|
|
|
@ -1,576 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <cctype>
|
|
||||||
|
|
||||||
#include "crashreporter.h"
|
|
||||||
#include "crashreporter_gtk_common.h"
|
|
||||||
|
|
||||||
#define LABEL_MAX_CHAR_WIDTH 48
|
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
using namespace CrashReporter;
|
|
||||||
|
|
||||||
static GtkWidget* gViewReportButton = 0;
|
|
||||||
static GtkWidget* gCommentTextLabel = 0;
|
|
||||||
static GtkWidget* gCommentText = 0;
|
|
||||||
static GtkWidget* gEmailMeCheck = 0;
|
|
||||||
static GtkWidget* gEmailEntryLabel = 0;
|
|
||||||
static GtkWidget* gEmailEntry = 0;
|
|
||||||
|
|
||||||
static bool gEmailFieldHint = true;
|
|
||||||
static bool gCommentFieldHint = true;
|
|
||||||
|
|
||||||
// handle from dlopen'ing libgnome
|
|
||||||
static void* gnomeLib = nullptr;
|
|
||||||
// handle from dlopen'ing libgnomeui
|
|
||||||
static void* gnomeuiLib = nullptr;
|
|
||||||
|
|
||||||
static void LoadSettings()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* NOTE! This code needs to stay in sync with the preference checking
|
|
||||||
* code in in nsExceptionHandler.cpp.
|
|
||||||
*/
|
|
||||||
|
|
||||||
StringTable settings;
|
|
||||||
if (ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true)) {
|
|
||||||
if (settings.find("Email") != settings.end()) {
|
|
||||||
gtk_entry_set_text(GTK_ENTRY(gEmailEntry), settings["Email"].c_str());
|
|
||||||
gEmailFieldHint = false;
|
|
||||||
}
|
|
||||||
if (settings.find("EmailMe") != settings.end()) {
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gEmailMeCheck),
|
|
||||||
settings["EmailMe"][0] != '0');
|
|
||||||
}
|
|
||||||
if (settings.find("IncludeURL") != settings.end() &&
|
|
||||||
gIncludeURLCheck != 0) {
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck),
|
|
||||||
settings["IncludeURL"][0] != '0');
|
|
||||||
}
|
|
||||||
bool enabled;
|
|
||||||
if (settings.find("SubmitReport") != settings.end())
|
|
||||||
enabled = settings["SubmitReport"][0] != '0';
|
|
||||||
else
|
|
||||||
enabled = ShouldEnableSending();
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck),
|
|
||||||
enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveSettings()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* NOTE! This code needs to stay in sync with the preference setting
|
|
||||||
* code in in nsExceptionHandler.cpp.
|
|
||||||
*/
|
|
||||||
|
|
||||||
StringTable settings;
|
|
||||||
|
|
||||||
ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true);
|
|
||||||
if (!gEmailFieldHint)
|
|
||||||
settings["Email"] = gtk_entry_get_text(GTK_ENTRY(gEmailEntry));
|
|
||||||
else
|
|
||||||
settings.erase("Email");
|
|
||||||
|
|
||||||
settings["EmailMe"] =
|
|
||||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck)) ? "1" : "0";
|
|
||||||
if (gIncludeURLCheck != 0)
|
|
||||||
settings["IncludeURL"] =
|
|
||||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))
|
|
||||||
? "1" : "0";
|
|
||||||
settings["SubmitReport"] =
|
|
||||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))
|
|
||||||
? "1" : "0";
|
|
||||||
|
|
||||||
WriteStringsToFile(gSettingsPath + "/" + kIniFile,
|
|
||||||
"Crash Reporter", settings, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendReport()
|
|
||||||
{
|
|
||||||
// disable all our gui controls, show the throbber + change the progress text
|
|
||||||
gtk_widget_set_sensitive(gSubmitReportCheck, FALSE);
|
|
||||||
gtk_widget_set_sensitive(gViewReportButton, FALSE);
|
|
||||||
gtk_widget_set_sensitive(gCommentText, FALSE);
|
|
||||||
if (gIncludeURLCheck)
|
|
||||||
gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
|
|
||||||
gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
|
|
||||||
gtk_widget_set_sensitive(gEmailEntry, FALSE);
|
|
||||||
gtk_widget_set_sensitive(gCloseButton, FALSE);
|
|
||||||
if (gRestartButton)
|
|
||||||
gtk_widget_set_sensitive(gRestartButton, FALSE);
|
|
||||||
gtk_widget_show_all(gThrobber);
|
|
||||||
gtk_label_set_text(GTK_LABEL(gProgressLabel),
|
|
||||||
gStrings[ST_REPORTDURINGSUBMIT].c_str());
|
|
||||||
|
|
||||||
#ifdef MOZ_ENABLE_GCONF
|
|
||||||
LoadProxyinfo();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// and spawn a thread to do the sending
|
|
||||||
GError* err;
|
|
||||||
gSendThreadID = g_thread_create(SendThread, nullptr, TRUE, &err);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ShowReportInfo(GtkTextView* viewReportTextView)
|
|
||||||
{
|
|
||||||
GtkTextBuffer* buffer =
|
|
||||||
gtk_text_view_get_buffer(viewReportTextView);
|
|
||||||
|
|
||||||
GtkTextIter start, end;
|
|
||||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
|
||||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
||||||
|
|
||||||
gtk_text_buffer_delete(buffer, &start, &end);
|
|
||||||
|
|
||||||
for (StringTable::iterator iter = gQueryParameters.begin();
|
|
||||||
iter != gQueryParameters.end();
|
|
||||||
iter++) {
|
|
||||||
gtk_text_buffer_insert(buffer, &end, iter->first.c_str(), -1);
|
|
||||||
gtk_text_buffer_insert(buffer, &end, ": ", -1);
|
|
||||||
gtk_text_buffer_insert(buffer, &end, iter->second.c_str(), -1);
|
|
||||||
gtk_text_buffer_insert(buffer, &end, "\n", -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_text_buffer_insert(buffer, &end, "\n", -1);
|
|
||||||
gtk_text_buffer_insert(buffer, &end,
|
|
||||||
gStrings[ST_EXTRAREPORTINFO].c_str(), -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateSubmit()
|
|
||||||
{
|
|
||||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) {
|
|
||||||
gtk_widget_set_sensitive(gViewReportButton, TRUE);
|
|
||||||
gtk_widget_set_sensitive(gCommentText, TRUE);
|
|
||||||
if (gIncludeURLCheck)
|
|
||||||
gtk_widget_set_sensitive(gIncludeURLCheck, TRUE);
|
|
||||||
gtk_widget_set_sensitive(gEmailMeCheck, TRUE);
|
|
||||||
gtk_widget_set_sensitive(gEmailEntry,
|
|
||||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck)));
|
|
||||||
gtk_label_set_text(GTK_LABEL(gProgressLabel),
|
|
||||||
gStrings[ST_REPORTPRESUBMIT].c_str());
|
|
||||||
} else {
|
|
||||||
gtk_widget_set_sensitive(gViewReportButton, FALSE);
|
|
||||||
gtk_widget_set_sensitive(gCommentText, FALSE);
|
|
||||||
if (gIncludeURLCheck)
|
|
||||||
gtk_widget_set_sensitive(gIncludeURLCheck, FALSE);
|
|
||||||
gtk_widget_set_sensitive(gEmailMeCheck, FALSE);
|
|
||||||
gtk_widget_set_sensitive(gEmailEntry, FALSE);
|
|
||||||
gtk_label_set_text(GTK_LABEL(gProgressLabel), "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ViewReportClicked(GtkButton* button,
|
|
||||||
gpointer userData)
|
|
||||||
{
|
|
||||||
GtkDialog* dialog =
|
|
||||||
GTK_DIALOG(gtk_dialog_new_with_buttons(gStrings[ST_VIEWREPORTTITLE].c_str(),
|
|
||||||
GTK_WINDOW(gWindow),
|
|
||||||
GTK_DIALOG_MODAL,
|
|
||||||
GTK_STOCK_OK,
|
|
||||||
GTK_RESPONSE_OK,
|
|
||||||
nullptr));
|
|
||||||
|
|
||||||
GtkWidget* scrolled = gtk_scrolled_window_new(0, 0);
|
|
||||||
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), scrolled);
|
|
||||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
|
|
||||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
|
|
||||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
|
|
||||||
GTK_SHADOW_IN);
|
|
||||||
#if (MOZ_WIDGET_GTK >= 3)
|
|
||||||
gtk_widget_set_vexpand(scrolled, TRUE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GtkWidget* viewReportTextView = gtk_text_view_new();
|
|
||||||
gtk_container_add(GTK_CONTAINER(scrolled), viewReportTextView);
|
|
||||||
gtk_text_view_set_editable(GTK_TEXT_VIEW(viewReportTextView), FALSE);
|
|
||||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(viewReportTextView),
|
|
||||||
GTK_WRAP_WORD);
|
|
||||||
gtk_widget_set_size_request(GTK_WIDGET(viewReportTextView), -1, 100);
|
|
||||||
|
|
||||||
ShowReportInfo(GTK_TEXT_VIEW(viewReportTextView));
|
|
||||||
|
|
||||||
gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK);
|
|
||||||
gtk_widget_set_size_request(GTK_WIDGET(dialog), 400, 200);
|
|
||||||
gtk_widget_show_all(GTK_WIDGET(dialog));
|
|
||||||
gtk_dialog_run(dialog);
|
|
||||||
gtk_widget_destroy(GTK_WIDGET(dialog));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CommentChanged(GtkTextBuffer* buffer, gpointer userData)
|
|
||||||
{
|
|
||||||
GtkTextIter start, end;
|
|
||||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
|
||||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
||||||
const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
|
|
||||||
if (comment[0] == '\0' || gCommentFieldHint)
|
|
||||||
gQueryParameters.erase("Comments");
|
|
||||||
else
|
|
||||||
gQueryParameters["Comments"] = comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CommentInsert(GtkTextBuffer* buffer,
|
|
||||||
GtkTextIter* location,
|
|
||||||
gchar* text,
|
|
||||||
gint len,
|
|
||||||
gpointer userData)
|
|
||||||
{
|
|
||||||
GtkTextIter start, end;
|
|
||||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
|
||||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
||||||
const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
|
|
||||||
|
|
||||||
// limit to 500 bytes in utf-8
|
|
||||||
if (strlen(comment) + len > MAX_COMMENT_LENGTH) {
|
|
||||||
g_signal_stop_emission_by_name(buffer, "insert-text");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void UpdateHintText(GtkWidget* widget, gboolean gainedFocus,
|
|
||||||
bool* hintShowing, const char* hintText)
|
|
||||||
{
|
|
||||||
GtkTextBuffer* buffer = nullptr;
|
|
||||||
if (GTK_IS_TEXT_VIEW(widget))
|
|
||||||
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
|
|
||||||
|
|
||||||
if (gainedFocus) {
|
|
||||||
if (*hintShowing) {
|
|
||||||
if (buffer == nullptr) { // sort of cheating
|
|
||||||
gtk_entry_set_text(GTK_ENTRY(widget), "");
|
|
||||||
}
|
|
||||||
else { // GtkTextView
|
|
||||||
gtk_text_buffer_set_text(buffer, "", 0);
|
|
||||||
}
|
|
||||||
gtk_widget_modify_text(widget, GTK_STATE_NORMAL, nullptr);
|
|
||||||
*hintShowing = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// lost focus
|
|
||||||
const char* text = nullptr;
|
|
||||||
if (buffer == nullptr) {
|
|
||||||
text = gtk_entry_get_text(GTK_ENTRY(widget));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
GtkTextIter start, end;
|
|
||||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
|
||||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
||||||
text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (text == nullptr || text[0] == '\0') {
|
|
||||||
*hintShowing = true;
|
|
||||||
|
|
||||||
if (buffer == nullptr) {
|
|
||||||
gtk_entry_set_text(GTK_ENTRY(widget), hintText);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gtk_text_buffer_set_text(buffer, hintText, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_widget_modify_text(widget, GTK_STATE_NORMAL,
|
|
||||||
>k_widget_get_style(widget)->text[GTK_STATE_INSENSITIVE]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean CommentFocusChange(GtkWidget* widget, GdkEventFocus* event,
|
|
||||||
gpointer userData)
|
|
||||||
{
|
|
||||||
UpdateHintText(widget, event->in, &gCommentFieldHint,
|
|
||||||
gStrings[ST_COMMENTGRAYTEXT].c_str());
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void UpdateEmail()
|
|
||||||
{
|
|
||||||
const char* email = gtk_entry_get_text(GTK_ENTRY(gEmailEntry));
|
|
||||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck))) {
|
|
||||||
gtk_widget_set_sensitive(gEmailEntry, TRUE);
|
|
||||||
} else {
|
|
||||||
email = "";
|
|
||||||
gtk_widget_set_sensitive(gEmailEntry, FALSE);
|
|
||||||
}
|
|
||||||
if (email[0] == '\0' || gEmailFieldHint)
|
|
||||||
gQueryParameters.erase("Email");
|
|
||||||
else
|
|
||||||
gQueryParameters["Email"] = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void EmailMeClicked(GtkButton* sender, gpointer userData)
|
|
||||||
{
|
|
||||||
UpdateEmail();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void EmailChanged(GtkEditable* editable, gpointer userData)
|
|
||||||
{
|
|
||||||
UpdateEmail();
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean EmailFocusChange(GtkWidget* widget, GdkEventFocus* event,
|
|
||||||
gpointer userData)
|
|
||||||
{
|
|
||||||
UpdateHintText(widget, event->in, &gEmailFieldHint,
|
|
||||||
gStrings[ST_EMAILGRAYTEXT].c_str());
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct _GnomeProgram GnomeProgram;
|
|
||||||
typedef struct _GnomeModuleInfo GnomeModuleInfo;
|
|
||||||
typedef GnomeProgram * (*_gnome_program_init_fn)(const char *, const char *,
|
|
||||||
const GnomeModuleInfo *, int,
|
|
||||||
char **, const char *, ...);
|
|
||||||
typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
|
|
||||||
|
|
||||||
void TryInitGnome()
|
|
||||||
{
|
|
||||||
gnomeLib = dlopen("libgnome-2.so.0", RTLD_LAZY);
|
|
||||||
if (!gnomeLib)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gnomeuiLib = dlopen("libgnomeui-2.so.0", RTLD_LAZY);
|
|
||||||
if (!gnomeuiLib)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_gnome_program_init_fn gnome_program_init =
|
|
||||||
(_gnome_program_init_fn)(dlsym(gnomeLib, "gnome_program_init"));
|
|
||||||
_libgnomeui_module_info_get_fn libgnomeui_module_info_get =
|
|
||||||
(_libgnomeui_module_info_get_fn)(dlsym(gnomeuiLib, "libgnomeui_module_info_get"));
|
|
||||||
|
|
||||||
if (gnome_program_init && libgnomeui_module_info_get) {
|
|
||||||
gnome_program_init("crashreporter", "1.0", libgnomeui_module_info_get(),
|
|
||||||
gArgc, gArgv, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Crashreporter UI Functions === */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Anything not listed here is in crashreporter_gtk_common.cpp:
|
|
||||||
* UIInit
|
|
||||||
* UIShowDefaultUI
|
|
||||||
* UIError_impl
|
|
||||||
* UIGetIniPath
|
|
||||||
* UIGetSettingsPath
|
|
||||||
* UIEnsurePathExists
|
|
||||||
* UIFileExists
|
|
||||||
* UIMoveFile
|
|
||||||
* UIDeleteFile
|
|
||||||
* UIOpenRead
|
|
||||||
* UIOpenWrite
|
|
||||||
*/
|
|
||||||
|
|
||||||
void UIShutdown()
|
|
||||||
{
|
|
||||||
if (gnomeuiLib)
|
|
||||||
dlclose(gnomeuiLib);
|
|
||||||
// Don't dlclose gnomeLib as libgnomevfs and libORBit-2 use atexit().
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIShowCrashUI(const StringTable& files,
|
|
||||||
const StringTable& queryParameters,
|
|
||||||
const string& sendURL,
|
|
||||||
const vector<string>& restartArgs)
|
|
||||||
{
|
|
||||||
gFiles = files;
|
|
||||||
gQueryParameters = queryParameters;
|
|
||||||
gSendURL = sendURL;
|
|
||||||
gRestartArgs = restartArgs;
|
|
||||||
if (gQueryParameters.find("URL") != gQueryParameters.end())
|
|
||||||
gURLParameter = gQueryParameters["URL"];
|
|
||||||
|
|
||||||
gWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
||||||
gtk_window_set_title(GTK_WINDOW(gWindow),
|
|
||||||
gStrings[ST_CRASHREPORTERTITLE].c_str());
|
|
||||||
gtk_window_set_resizable(GTK_WINDOW(gWindow), FALSE);
|
|
||||||
gtk_window_set_position(GTK_WINDOW(gWindow), GTK_WIN_POS_CENTER);
|
|
||||||
gtk_container_set_border_width(GTK_CONTAINER(gWindow), 12);
|
|
||||||
g_signal_connect(gWindow, "delete-event", G_CALLBACK(WindowDeleted), 0);
|
|
||||||
g_signal_connect(gWindow, "key_press_event", G_CALLBACK(check_escape), nullptr);
|
|
||||||
|
|
||||||
GtkWidget* vbox = gtk_vbox_new(FALSE, 6);
|
|
||||||
gtk_container_add(GTK_CONTAINER(gWindow), vbox);
|
|
||||||
|
|
||||||
GtkWidget* titleLabel = gtk_label_new("");
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), titleLabel, FALSE, FALSE, 0);
|
|
||||||
gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5);
|
|
||||||
char* markup = g_strdup_printf("<b>%s</b>",
|
|
||||||
gStrings[ST_CRASHREPORTERHEADER].c_str());
|
|
||||||
gtk_label_set_markup(GTK_LABEL(titleLabel), markup);
|
|
||||||
g_free(markup);
|
|
||||||
|
|
||||||
GtkWidget* descriptionLabel =
|
|
||||||
gtk_label_new(gStrings[ST_CRASHREPORTERDESCRIPTION].c_str());
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), descriptionLabel, TRUE, TRUE, 0);
|
|
||||||
// force the label to line wrap
|
|
||||||
#if (MOZ_WIDGET_GTK == 2)
|
|
||||||
gtk_widget_set_size_request(descriptionLabel, 400, -1);
|
|
||||||
#else
|
|
||||||
gtk_label_set_max_width_chars(GTK_LABEL(descriptionLabel), LABEL_MAX_CHAR_WIDTH);
|
|
||||||
#endif
|
|
||||||
gtk_label_set_line_wrap(GTK_LABEL(descriptionLabel), TRUE);
|
|
||||||
gtk_label_set_selectable(GTK_LABEL(descriptionLabel), TRUE);
|
|
||||||
gtk_misc_set_alignment(GTK_MISC(descriptionLabel), 0, 0.5);
|
|
||||||
|
|
||||||
// this is honestly how they suggest you indent a section
|
|
||||||
GtkWidget* indentBox = gtk_hbox_new(FALSE, 0);
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), indentBox, FALSE, FALSE, 0);
|
|
||||||
gtk_box_pack_start(GTK_BOX(indentBox), gtk_label_new(""), FALSE, FALSE, 6);
|
|
||||||
|
|
||||||
GtkWidget* innerVBox1 = gtk_vbox_new(FALSE, 0);
|
|
||||||
gtk_box_pack_start(GTK_BOX(indentBox), innerVBox1, TRUE, TRUE, 0);
|
|
||||||
|
|
||||||
gSubmitReportCheck =
|
|
||||||
gtk_check_button_new_with_label(gStrings[ST_CHECKSUBMIT].c_str());
|
|
||||||
gtk_box_pack_start(GTK_BOX(innerVBox1), gSubmitReportCheck, FALSE, FALSE, 0);
|
|
||||||
g_signal_connect(gSubmitReportCheck, "clicked",
|
|
||||||
G_CALLBACK(SubmitReportChecked), 0);
|
|
||||||
|
|
||||||
// indent again, below the "submit report" checkbox
|
|
||||||
GtkWidget* indentBox2 = gtk_hbox_new(FALSE, 0);
|
|
||||||
gtk_box_pack_start(GTK_BOX(innerVBox1), indentBox2, FALSE, FALSE, 0);
|
|
||||||
gtk_box_pack_start(GTK_BOX(indentBox2), gtk_label_new(""), FALSE, FALSE, 6);
|
|
||||||
|
|
||||||
GtkWidget* innerVBox = gtk_vbox_new(FALSE, 0);
|
|
||||||
gtk_box_pack_start(GTK_BOX(indentBox2), innerVBox, TRUE, TRUE, 0);
|
|
||||||
gtk_box_set_spacing(GTK_BOX(innerVBox), 6);
|
|
||||||
|
|
||||||
GtkWidget* viewReportButtonBox = gtk_hbutton_box_new();
|
|
||||||
gtk_box_pack_start(GTK_BOX(innerVBox), viewReportButtonBox, FALSE, FALSE, 0);
|
|
||||||
gtk_box_set_spacing(GTK_BOX(viewReportButtonBox), 6);
|
|
||||||
gtk_button_box_set_layout(GTK_BUTTON_BOX(viewReportButtonBox), GTK_BUTTONBOX_START);
|
|
||||||
|
|
||||||
gViewReportButton =
|
|
||||||
gtk_button_new_with_label(gStrings[ST_VIEWREPORT].c_str());
|
|
||||||
gtk_box_pack_start(GTK_BOX(viewReportButtonBox), gViewReportButton, FALSE, FALSE, 0);
|
|
||||||
g_signal_connect(gViewReportButton, "clicked", G_CALLBACK(ViewReportClicked), 0);
|
|
||||||
|
|
||||||
GtkWidget* scrolled = gtk_scrolled_window_new(0, 0);
|
|
||||||
gtk_container_add(GTK_CONTAINER(innerVBox), scrolled);
|
|
||||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
|
|
||||||
GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
|
|
||||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
|
|
||||||
GTK_SHADOW_IN);
|
|
||||||
#if (MOZ_WIDGET_GTK >= 3)
|
|
||||||
gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), 100);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gCommentTextLabel = gtk_label_new(gStrings[ST_COMMENTGRAYTEXT].c_str());
|
|
||||||
gCommentText = gtk_text_view_new();
|
|
||||||
gtk_label_set_mnemonic_widget(GTK_LABEL(gCommentTextLabel), gCommentText);
|
|
||||||
gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(gCommentText), FALSE);
|
|
||||||
g_signal_connect(gCommentText, "focus-in-event", G_CALLBACK(CommentFocusChange), 0);
|
|
||||||
g_signal_connect(gCommentText, "focus-out-event", G_CALLBACK(CommentFocusChange), 0);
|
|
||||||
|
|
||||||
GtkTextBuffer* commentBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gCommentText));
|
|
||||||
g_signal_connect(commentBuffer, "changed", G_CALLBACK(CommentChanged), 0);
|
|
||||||
g_signal_connect(commentBuffer, "insert-text", G_CALLBACK(CommentInsert), 0);
|
|
||||||
|
|
||||||
gtk_container_add(GTK_CONTAINER(scrolled), gCommentText);
|
|
||||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gCommentText),
|
|
||||||
GTK_WRAP_WORD);
|
|
||||||
gtk_widget_set_size_request(GTK_WIDGET(gCommentText), -1, 100);
|
|
||||||
|
|
||||||
if (gQueryParameters.find("URL") != gQueryParameters.end()) {
|
|
||||||
gIncludeURLCheck =
|
|
||||||
gtk_check_button_new_with_label(gStrings[ST_CHECKURL].c_str());
|
|
||||||
gtk_box_pack_start(GTK_BOX(innerVBox), gIncludeURLCheck, FALSE, FALSE, 0);
|
|
||||||
g_signal_connect(gIncludeURLCheck, "clicked", G_CALLBACK(IncludeURLClicked), 0);
|
|
||||||
// on by default
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
gEmailMeCheck =
|
|
||||||
gtk_check_button_new_with_label(gStrings[ST_CHECKEMAIL].c_str());
|
|
||||||
gtk_box_pack_start(GTK_BOX(innerVBox), gEmailMeCheck, FALSE, FALSE, 0);
|
|
||||||
g_signal_connect(gEmailMeCheck, "clicked", G_CALLBACK(EmailMeClicked), 0);
|
|
||||||
|
|
||||||
GtkWidget* emailIndentBox = gtk_hbox_new(FALSE, 0);
|
|
||||||
gtk_box_pack_start(GTK_BOX(innerVBox), emailIndentBox, FALSE, FALSE, 0);
|
|
||||||
gtk_box_pack_start(GTK_BOX(emailIndentBox), gtk_label_new(""),
|
|
||||||
FALSE, FALSE, 9);
|
|
||||||
|
|
||||||
gEmailEntryLabel = gtk_label_new(gStrings[ST_EMAILGRAYTEXT].c_str());
|
|
||||||
gEmailEntry = gtk_entry_new();
|
|
||||||
gtk_label_set_mnemonic_widget(GTK_LABEL(gEmailEntryLabel), gEmailEntry);
|
|
||||||
gtk_box_pack_start(GTK_BOX(emailIndentBox), gEmailEntry, TRUE, TRUE, 0);
|
|
||||||
g_signal_connect(gEmailEntry, "changed", G_CALLBACK(EmailChanged), 0);
|
|
||||||
g_signal_connect(gEmailEntry, "focus-in-event", G_CALLBACK(EmailFocusChange), 0);
|
|
||||||
g_signal_connect(gEmailEntry, "focus-out-event", G_CALLBACK(EmailFocusChange), 0);
|
|
||||||
|
|
||||||
GtkWidget* progressBox = gtk_hbox_new(FALSE, 6);
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), progressBox, TRUE, TRUE, 0);
|
|
||||||
|
|
||||||
// Get the throbber image from alongside the executable
|
|
||||||
char* dir = g_path_get_dirname(gArgv[0]);
|
|
||||||
char* path = g_build_filename(dir, "Throbber-small.gif", nullptr);
|
|
||||||
g_free(dir);
|
|
||||||
gThrobber = gtk_image_new_from_file(path);
|
|
||||||
gtk_box_pack_start(GTK_BOX(progressBox), gThrobber, FALSE, FALSE, 0);
|
|
||||||
|
|
||||||
gProgressLabel =
|
|
||||||
gtk_label_new(gStrings[ST_REPORTPRESUBMIT].c_str());
|
|
||||||
gtk_box_pack_start(GTK_BOX(progressBox), gProgressLabel, TRUE, TRUE, 0);
|
|
||||||
// force the label to line wrap
|
|
||||||
#if (MOZ_WIDGET_GTK == 2)
|
|
||||||
gtk_widget_set_size_request(gProgressLabel, 400, -1);
|
|
||||||
#else
|
|
||||||
gtk_label_set_max_width_chars(GTK_LABEL(gProgressLabel), LABEL_MAX_CHAR_WIDTH);
|
|
||||||
#endif
|
|
||||||
gtk_label_set_line_wrap(GTK_LABEL(gProgressLabel), TRUE);
|
|
||||||
|
|
||||||
GtkWidget* buttonBox = gtk_hbutton_box_new();
|
|
||||||
gtk_box_pack_end(GTK_BOX(vbox), buttonBox, FALSE, FALSE, 0);
|
|
||||||
gtk_box_set_spacing(GTK_BOX(buttonBox), 6);
|
|
||||||
gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonBox), GTK_BUTTONBOX_END);
|
|
||||||
|
|
||||||
gCloseButton =
|
|
||||||
gtk_button_new_with_label(gStrings[ST_QUIT].c_str());
|
|
||||||
gtk_box_pack_start(GTK_BOX(buttonBox), gCloseButton, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_set_can_default(gCloseButton, TRUE);
|
|
||||||
g_signal_connect(gCloseButton, "clicked", G_CALLBACK(CloseClicked), 0);
|
|
||||||
|
|
||||||
gRestartButton = 0;
|
|
||||||
if (restartArgs.size() > 0) {
|
|
||||||
gRestartButton = gtk_button_new_with_label(gStrings[ST_RESTART].c_str());
|
|
||||||
gtk_box_pack_start(GTK_BOX(buttonBox), gRestartButton, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_set_can_default(gRestartButton, TRUE);
|
|
||||||
g_signal_connect(gRestartButton, "clicked", G_CALLBACK(RestartClicked), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_widget_grab_focus(gSubmitReportCheck);
|
|
||||||
|
|
||||||
gtk_widget_grab_default(gRestartButton ? gRestartButton : gCloseButton);
|
|
||||||
|
|
||||||
LoadSettings();
|
|
||||||
|
|
||||||
UpdateEmail();
|
|
||||||
UpdateSubmit();
|
|
||||||
|
|
||||||
UpdateHintText(gCommentText, FALSE, &gCommentFieldHint,
|
|
||||||
gStrings[ST_COMMENTGRAYTEXT].c_str());
|
|
||||||
UpdateHintText(gEmailEntry, FALSE, &gEmailFieldHint,
|
|
||||||
gStrings[ST_EMAILGRAYTEXT].c_str());
|
|
||||||
|
|
||||||
gtk_widget_show_all(gWindow);
|
|
||||||
// stick this here to avoid the show_all above...
|
|
||||||
gtk_widget_hide(gThrobber);
|
|
||||||
|
|
||||||
gtk_main();
|
|
||||||
|
|
||||||
return gDidTrySend;
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef CRASHREPORTER_OSX_H__
|
|
||||||
#define CRASHREPORTER_OSX_H__
|
|
||||||
|
|
||||||
#include <Cocoa/Cocoa.h>
|
|
||||||
#include "HTTPMultipartUpload.h"
|
|
||||||
#include "crashreporter.h"
|
|
||||||
|
|
||||||
// Defined below
|
|
||||||
@class TextViewWithPlaceHolder;
|
|
||||||
|
|
||||||
@interface CrashReporterUI : NSObject
|
|
||||||
{
|
|
||||||
IBOutlet NSWindow* mWindow;
|
|
||||||
|
|
||||||
/* Crash reporter view */
|
|
||||||
IBOutlet NSTextField* mHeaderLabel;
|
|
||||||
IBOutlet NSTextField* mDescriptionLabel;
|
|
||||||
IBOutlet NSButton* mViewReportButton;
|
|
||||||
IBOutlet NSScrollView* mCommentScrollView;
|
|
||||||
IBOutlet TextViewWithPlaceHolder* mCommentText;
|
|
||||||
IBOutlet NSButton* mSubmitReportButton;
|
|
||||||
IBOutlet NSButton* mIncludeURLButton;
|
|
||||||
IBOutlet NSButton* mEmailMeButton;
|
|
||||||
IBOutlet NSTextField* mEmailText;
|
|
||||||
IBOutlet NSButton* mCloseButton;
|
|
||||||
IBOutlet NSButton* mRestartButton;
|
|
||||||
IBOutlet NSProgressIndicator* mProgressIndicator;
|
|
||||||
IBOutlet NSTextField* mProgressText;
|
|
||||||
|
|
||||||
/* Error view */
|
|
||||||
IBOutlet NSView* mErrorView;
|
|
||||||
IBOutlet NSTextField* mErrorHeaderLabel;
|
|
||||||
IBOutlet NSTextField* mErrorLabel;
|
|
||||||
IBOutlet NSButton* mErrorCloseButton;
|
|
||||||
|
|
||||||
/* For "show info" alert */
|
|
||||||
IBOutlet NSWindow* mViewReportWindow;
|
|
||||||
IBOutlet NSTextView* mViewReportTextView;
|
|
||||||
IBOutlet NSButton* mViewReportOkButton;
|
|
||||||
|
|
||||||
HTTPMultipartUpload* mPost;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)showCrashUI:(const StringTable&)files
|
|
||||||
queryParameters:(const StringTable&)queryParameters
|
|
||||||
sendURL:(const std::string&)sendURL;
|
|
||||||
- (void)showErrorUI:(const std::string&)message;
|
|
||||||
- (void)showReportInfo;
|
|
||||||
- (void)maybeSubmitReport;
|
|
||||||
- (void)closeMeDown:(id)unused;
|
|
||||||
|
|
||||||
- (IBAction)submitReportClicked:(id)sender;
|
|
||||||
- (IBAction)viewReportClicked:(id)sender;
|
|
||||||
- (IBAction)viewReportOkClicked:(id)sender;
|
|
||||||
- (IBAction)closeClicked:(id)sender;
|
|
||||||
- (IBAction)restartClicked:(id)sender;
|
|
||||||
- (IBAction)includeURLClicked:(id)sender;
|
|
||||||
- (IBAction)emailMeClicked:(id)sender;
|
|
||||||
|
|
||||||
- (void)controlTextDidChange:(NSNotification *)note;
|
|
||||||
- (void)textDidChange:(NSNotification *)aNotification;
|
|
||||||
- (BOOL)textView:(NSTextView *)aTextView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(NSString *)replacementString;
|
|
||||||
|
|
||||||
- (void)doInitialResizing;
|
|
||||||
- (float)setStringFitVertically:(NSControl*)control
|
|
||||||
string:(NSString*)str
|
|
||||||
resizeWindow:(BOOL)resizeWindow;
|
|
||||||
- (void)setView:(NSView*)v animate: (BOOL) animate;
|
|
||||||
- (void)enableControls:(BOOL)enabled;
|
|
||||||
- (void)updateSubmit;
|
|
||||||
- (void)updateURL;
|
|
||||||
- (void)updateEmail;
|
|
||||||
- (void)sendReport;
|
|
||||||
- (bool)setupPost;
|
|
||||||
- (void)uploadThread:(HTTPMultipartUpload*)post;
|
|
||||||
- (void)uploadComplete:(NSData*)data;
|
|
||||||
|
|
||||||
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication;
|
|
||||||
-(void)applicationWillTerminate:(NSNotification *)aNotification;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Subclass NSTextView to provide a text view with placeholder text.
|
|
||||||
* Also provide a setEnabled implementation.
|
|
||||||
*/
|
|
||||||
@interface TextViewWithPlaceHolder : NSTextView {
|
|
||||||
NSMutableAttributedString *mPlaceHolderString;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)becomeFirstResponder;
|
|
||||||
- (void)drawRect:(NSRect)rect;
|
|
||||||
- (BOOL)resignFirstResponder;
|
|
||||||
- (void)setPlaceholder:(NSString*)placeholder;
|
|
||||||
- (void)insertTab:(id)sender;
|
|
||||||
- (void)insertBacktab:(id)sender;
|
|
||||||
- (void)setEnabled:(BOOL)enabled;
|
|
||||||
- (void)dealloc;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,922 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import <CoreFoundation/CoreFoundation.h>
|
|
||||||
#include "crashreporter.h"
|
|
||||||
#include "crashreporter_osx.h"
|
|
||||||
#include <crt_externs.h>
|
|
||||||
#include <spawn.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
using std::ostringstream;
|
|
||||||
|
|
||||||
using namespace CrashReporter;
|
|
||||||
|
|
||||||
static NSAutoreleasePool* gMainPool;
|
|
||||||
static CrashReporterUI* gUI = 0;
|
|
||||||
static StringTable gFiles;
|
|
||||||
static StringTable gQueryParameters;
|
|
||||||
static string gURLParameter;
|
|
||||||
static string gSendURL;
|
|
||||||
static vector<string> gRestartArgs;
|
|
||||||
static bool gDidTrySend = false;
|
|
||||||
static bool gRTLlayout = false;
|
|
||||||
|
|
||||||
static cpu_type_t pref_cpu_types[2] = {
|
|
||||||
#if defined(__i386__)
|
|
||||||
CPU_TYPE_X86,
|
|
||||||
#elif defined(__x86_64__)
|
|
||||||
CPU_TYPE_X86_64,
|
|
||||||
#elif defined(__ppc__)
|
|
||||||
CPU_TYPE_POWERPC,
|
|
||||||
#endif
|
|
||||||
CPU_TYPE_ANY };
|
|
||||||
|
|
||||||
#define NSSTR(s) [NSString stringWithUTF8String:(s).c_str()]
|
|
||||||
|
|
||||||
static NSString* Str(const char* aName)
|
|
||||||
{
|
|
||||||
string str = gStrings[aName];
|
|
||||||
if (str.empty()) str = "?";
|
|
||||||
return NSSTR(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool RestartApplication()
|
|
||||||
{
|
|
||||||
vector<char*> argv(gRestartArgs.size() + 1);
|
|
||||||
|
|
||||||
posix_spawnattr_t spawnattr;
|
|
||||||
if (posix_spawnattr_init(&spawnattr) != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set spawn attributes.
|
|
||||||
size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]);
|
|
||||||
size_t attr_ocount = 0;
|
|
||||||
if (posix_spawnattr_setbinpref_np(&spawnattr,
|
|
||||||
attr_count,
|
|
||||||
pref_cpu_types,
|
|
||||||
&attr_ocount) != 0 ||
|
|
||||||
attr_ocount != attr_count) {
|
|
||||||
posix_spawnattr_destroy(&spawnattr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int i;
|
|
||||||
for (i = 0; i < gRestartArgs.size(); i++) {
|
|
||||||
argv[i] = (char*)gRestartArgs[i].c_str();
|
|
||||||
}
|
|
||||||
argv[i] = 0;
|
|
||||||
|
|
||||||
char **env = NULL;
|
|
||||||
char ***nsEnv = _NSGetEnviron();
|
|
||||||
if (nsEnv)
|
|
||||||
env = *nsEnv;
|
|
||||||
int result = posix_spawnp(NULL,
|
|
||||||
argv[0],
|
|
||||||
NULL,
|
|
||||||
&spawnattr,
|
|
||||||
&argv[0],
|
|
||||||
env);
|
|
||||||
|
|
||||||
posix_spawnattr_destroy(&spawnattr);
|
|
||||||
|
|
||||||
return result == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation CrashReporterUI
|
|
||||||
|
|
||||||
-(void)awakeFromNib
|
|
||||||
{
|
|
||||||
gUI = self;
|
|
||||||
[mWindow center];
|
|
||||||
|
|
||||||
[mWindow setTitle:[[NSBundle mainBundle]
|
|
||||||
objectForInfoDictionaryKey:@"CFBundleName"]];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)showCrashUI:(const StringTable&)files
|
|
||||||
queryParameters:(const StringTable&)queryParameters
|
|
||||||
sendURL:(const string&)sendURL
|
|
||||||
{
|
|
||||||
gFiles = files;
|
|
||||||
gQueryParameters = queryParameters;
|
|
||||||
gSendURL = sendURL;
|
|
||||||
|
|
||||||
[mWindow setTitle:Str(ST_CRASHREPORTERTITLE)];
|
|
||||||
[mHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
|
|
||||||
|
|
||||||
NSRect viewReportFrame = [mViewReportButton frame];
|
|
||||||
[mViewReportButton setTitle:Str(ST_VIEWREPORT)];
|
|
||||||
[mViewReportButton sizeToFit];
|
|
||||||
if (gRTLlayout) {
|
|
||||||
// sizeToFit will keep the left side fixed, so realign
|
|
||||||
float oldWidth = viewReportFrame.size.width;
|
|
||||||
viewReportFrame = [mViewReportButton frame];
|
|
||||||
viewReportFrame.origin.x += oldWidth - viewReportFrame.size.width;
|
|
||||||
[mViewReportButton setFrame: viewReportFrame];
|
|
||||||
}
|
|
||||||
|
|
||||||
[mSubmitReportButton setTitle:Str(ST_CHECKSUBMIT)];
|
|
||||||
[mIncludeURLButton setTitle:Str(ST_CHECKURL)];
|
|
||||||
[mEmailMeButton setTitle:Str(ST_CHECKEMAIL)];
|
|
||||||
[mViewReportOkButton setTitle:Str(ST_OK)];
|
|
||||||
|
|
||||||
[mCommentText setPlaceholder:Str(ST_COMMENTGRAYTEXT)];
|
|
||||||
if (gRTLlayout)
|
|
||||||
[mCommentText toggleBaseWritingDirection:self];
|
|
||||||
[[mEmailText cell] setPlaceholderString:Str(ST_EMAILGRAYTEXT)];
|
|
||||||
|
|
||||||
if (gQueryParameters.find("URL") != gQueryParameters.end()) {
|
|
||||||
// save the URL value in case the checkbox gets unchecked
|
|
||||||
gURLParameter = gQueryParameters["URL"];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// no URL specified, hide checkbox
|
|
||||||
[mIncludeURLButton removeFromSuperview];
|
|
||||||
// shrink window to fit
|
|
||||||
NSRect frame = [mWindow frame];
|
|
||||||
NSRect includeURLFrame = [mIncludeURLButton frame];
|
|
||||||
NSRect emailFrame = [mEmailMeButton frame];
|
|
||||||
int buttonMask = [mViewReportButton autoresizingMask];
|
|
||||||
int checkMask = [mSubmitReportButton autoresizingMask];
|
|
||||||
int commentScrollMask = [mCommentScrollView autoresizingMask];
|
|
||||||
|
|
||||||
[mViewReportButton setAutoresizingMask:NSViewMinYMargin];
|
|
||||||
[mSubmitReportButton setAutoresizingMask:NSViewMinYMargin];
|
|
||||||
[mCommentScrollView setAutoresizingMask:NSViewMinYMargin];
|
|
||||||
|
|
||||||
// remove all the space in between
|
|
||||||
frame.size.height -= includeURLFrame.origin.y - emailFrame.origin.y;
|
|
||||||
[mWindow setFrame:frame display: true animate:NO];
|
|
||||||
|
|
||||||
[mViewReportButton setAutoresizingMask:buttonMask];
|
|
||||||
[mSubmitReportButton setAutoresizingMask:checkMask];
|
|
||||||
[mCommentScrollView setAutoresizingMask:commentScrollMask];
|
|
||||||
}
|
|
||||||
|
|
||||||
// resize some buttons horizontally and possibly some controls vertically
|
|
||||||
[self doInitialResizing];
|
|
||||||
|
|
||||||
// load default state of submit checkbox
|
|
||||||
// we don't just do this via IB because we want the default to be
|
|
||||||
// off a certain percentage of the time
|
|
||||||
BOOL submitChecked = NO;
|
|
||||||
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
|
||||||
if (nil != [userDefaults objectForKey:@"submitReport"]) {
|
|
||||||
submitChecked = [userDefaults boolForKey:@"submitReport"];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// use compile-time specified enable percentage
|
|
||||||
submitChecked = ShouldEnableSending();
|
|
||||||
[userDefaults setBool:submitChecked forKey:@"submitReport"];
|
|
||||||
}
|
|
||||||
[mSubmitReportButton setState:(submitChecked ? NSOnState : NSOffState)];
|
|
||||||
|
|
||||||
[self updateSubmit];
|
|
||||||
[self updateURL];
|
|
||||||
[self updateEmail];
|
|
||||||
|
|
||||||
[mWindow makeKeyAndOrderFront:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)showErrorUI:(const string&)message
|
|
||||||
{
|
|
||||||
[self setView: mErrorView animate: NO];
|
|
||||||
|
|
||||||
[mErrorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
|
|
||||||
[self setStringFitVertically:mErrorLabel
|
|
||||||
string:NSSTR(message)
|
|
||||||
resizeWindow:YES];
|
|
||||||
[mErrorCloseButton setTitle:Str(ST_OK)];
|
|
||||||
|
|
||||||
[mErrorCloseButton setKeyEquivalent:@"\r"];
|
|
||||||
[mWindow makeFirstResponder:mErrorCloseButton];
|
|
||||||
[mWindow makeKeyAndOrderFront:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)showReportInfo
|
|
||||||
{
|
|
||||||
NSDictionary* boldAttr = [NSDictionary
|
|
||||||
dictionaryWithObject:
|
|
||||||
[NSFont boldSystemFontOfSize:
|
|
||||||
[NSFont smallSystemFontSize]]
|
|
||||||
forKey:NSFontAttributeName];
|
|
||||||
NSDictionary* normalAttr = [NSDictionary
|
|
||||||
dictionaryWithObject:
|
|
||||||
[NSFont systemFontOfSize:
|
|
||||||
[NSFont smallSystemFontSize]]
|
|
||||||
forKey:NSFontAttributeName];
|
|
||||||
|
|
||||||
[mViewReportTextView setString:@""];
|
|
||||||
for (StringTable::iterator iter = gQueryParameters.begin();
|
|
||||||
iter != gQueryParameters.end();
|
|
||||||
iter++) {
|
|
||||||
NSAttributedString* key = [[NSAttributedString alloc]
|
|
||||||
initWithString:NSSTR(iter->first + ": ")
|
|
||||||
attributes:boldAttr];
|
|
||||||
NSAttributedString* value = [[NSAttributedString alloc]
|
|
||||||
initWithString:NSSTR(iter->second + "\n")
|
|
||||||
attributes:normalAttr];
|
|
||||||
[[mViewReportTextView textStorage] appendAttributedString: key];
|
|
||||||
[[mViewReportTextView textStorage] appendAttributedString: value];
|
|
||||||
[key release];
|
|
||||||
[value release];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSAttributedString* extra = [[NSAttributedString alloc]
|
|
||||||
initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO])
|
|
||||||
attributes:normalAttr];
|
|
||||||
[[mViewReportTextView textStorage] appendAttributedString: extra];
|
|
||||||
[extra release];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)maybeSubmitReport
|
|
||||||
{
|
|
||||||
if ([mSubmitReportButton state] == NSOnState) {
|
|
||||||
[self setStringFitVertically:mProgressText
|
|
||||||
string:Str(ST_REPORTDURINGSUBMIT)
|
|
||||||
resizeWindow:YES];
|
|
||||||
// disable all the controls
|
|
||||||
[self enableControls:NO];
|
|
||||||
[mSubmitReportButton setEnabled:NO];
|
|
||||||
[mRestartButton setEnabled:NO];
|
|
||||||
[mCloseButton setEnabled:NO];
|
|
||||||
[mProgressIndicator startAnimation:self];
|
|
||||||
gDidTrySend = true;
|
|
||||||
[self sendReport];
|
|
||||||
} else {
|
|
||||||
[NSApp terminate:self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)closeMeDown:(id)unused
|
|
||||||
{
|
|
||||||
[NSApp terminate:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(IBAction)submitReportClicked:(id)sender
|
|
||||||
{
|
|
||||||
[self updateSubmit];
|
|
||||||
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
|
||||||
[userDefaults setBool:([mSubmitReportButton state] == NSOnState)
|
|
||||||
forKey:@"submitReport"];
|
|
||||||
[userDefaults synchronize];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(IBAction)viewReportClicked:(id)sender
|
|
||||||
{
|
|
||||||
[self showReportInfo];
|
|
||||||
[NSApp beginSheet:mViewReportWindow modalForWindow:mWindow
|
|
||||||
modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (IBAction)viewReportOkClicked:(id)sender
|
|
||||||
{
|
|
||||||
[mViewReportWindow orderOut:nil];
|
|
||||||
[NSApp endSheet:mViewReportWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(IBAction)closeClicked:(id)sender
|
|
||||||
{
|
|
||||||
[self maybeSubmitReport];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(IBAction)restartClicked:(id)sender
|
|
||||||
{
|
|
||||||
RestartApplication();
|
|
||||||
[self maybeSubmitReport];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (IBAction)includeURLClicked:(id)sender
|
|
||||||
{
|
|
||||||
[self updateURL];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(IBAction)emailMeClicked:(id)sender
|
|
||||||
{
|
|
||||||
[self updateEmail];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)controlTextDidChange:(NSNotification *)note
|
|
||||||
{
|
|
||||||
[self updateEmail];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)textDidChange:(NSNotification *)aNotification
|
|
||||||
{
|
|
||||||
// update comment parameter
|
|
||||||
if ([[[mCommentText textStorage] mutableString] length] > 0)
|
|
||||||
gQueryParameters["Comments"] = [[[mCommentText textStorage] mutableString]
|
|
||||||
UTF8String];
|
|
||||||
else
|
|
||||||
gQueryParameters.erase("Comments");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit the comment field to 500 bytes in UTF-8
|
|
||||||
- (BOOL)textView:(NSTextView *)aTextView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(NSString *)replacementString
|
|
||||||
{
|
|
||||||
// current string length + replacement text length - replaced range length
|
|
||||||
if (([[aTextView string]
|
|
||||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding]
|
|
||||||
+ [replacementString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]
|
|
||||||
- [[[aTextView string] substringWithRange:affectedCharRange]
|
|
||||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding])
|
|
||||||
> MAX_COMMENT_LENGTH) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)doInitialResizing
|
|
||||||
{
|
|
||||||
NSRect windowFrame = [mWindow frame];
|
|
||||||
NSRect restartFrame = [mRestartButton frame];
|
|
||||||
NSRect closeFrame = [mCloseButton frame];
|
|
||||||
// resize close button to fit text
|
|
||||||
float oldCloseWidth = closeFrame.size.width;
|
|
||||||
[mCloseButton setTitle:Str(ST_QUIT)];
|
|
||||||
[mCloseButton sizeToFit];
|
|
||||||
closeFrame = [mCloseButton frame];
|
|
||||||
// move close button left if it grew
|
|
||||||
if (!gRTLlayout) {
|
|
||||||
closeFrame.origin.x -= closeFrame.size.width - oldCloseWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gRestartArgs.size() == 0) {
|
|
||||||
[mRestartButton removeFromSuperview];
|
|
||||||
if (!gRTLlayout) {
|
|
||||||
closeFrame.origin.x = restartFrame.origin.x +
|
|
||||||
(restartFrame.size.width - closeFrame.size.width);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
closeFrame.origin.x = restartFrame.origin.x;
|
|
||||||
}
|
|
||||||
[mCloseButton setFrame: closeFrame];
|
|
||||||
[mCloseButton setKeyEquivalent:@"\r"];
|
|
||||||
} else {
|
|
||||||
[mRestartButton setTitle:Str(ST_RESTART)];
|
|
||||||
// resize "restart" button
|
|
||||||
float oldRestartWidth = restartFrame.size.width;
|
|
||||||
[mRestartButton sizeToFit];
|
|
||||||
restartFrame = [mRestartButton frame];
|
|
||||||
if (!gRTLlayout) {
|
|
||||||
// move left by the amount that the button grew
|
|
||||||
restartFrame.origin.x -= restartFrame.size.width - oldRestartWidth;
|
|
||||||
closeFrame.origin.x -= restartFrame.size.width - oldRestartWidth;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// shift the close button right in RTL
|
|
||||||
closeFrame.origin.x += restartFrame.size.width - oldRestartWidth;
|
|
||||||
}
|
|
||||||
[mRestartButton setFrame: restartFrame];
|
|
||||||
[mCloseButton setFrame: closeFrame];
|
|
||||||
// possibly resize window if both buttons no longer fit
|
|
||||||
// leave 20 px from either side of the window, and 12 px
|
|
||||||
// between the buttons
|
|
||||||
float neededWidth = closeFrame.size.width + restartFrame.size.width +
|
|
||||||
2*20 + 12;
|
|
||||||
|
|
||||||
if (neededWidth > windowFrame.size.width) {
|
|
||||||
windowFrame.size.width = neededWidth;
|
|
||||||
[mWindow setFrame:windowFrame display: true animate: NO];
|
|
||||||
}
|
|
||||||
[mRestartButton setKeyEquivalent:@"\r"];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSButton *checkboxes[] = {
|
|
||||||
mSubmitReportButton,
|
|
||||||
mIncludeURLButton,
|
|
||||||
mEmailMeButton
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i=0; i<3; i++) {
|
|
||||||
NSRect frame = [checkboxes[i] frame];
|
|
||||||
[checkboxes[i] sizeToFit];
|
|
||||||
if (gRTLlayout) {
|
|
||||||
// sizeToFit will keep the left side fixed, so realign
|
|
||||||
float oldWidth = frame.size.width;
|
|
||||||
frame = [checkboxes[i] frame];
|
|
||||||
frame.origin.x += oldWidth - frame.size.width;
|
|
||||||
[checkboxes[i] setFrame: frame];
|
|
||||||
}
|
|
||||||
// keep existing spacing on left side, + 20 px spare on right
|
|
||||||
float neededWidth = frame.origin.x + frame.size.width + 20;
|
|
||||||
if (neededWidth > windowFrame.size.width) {
|
|
||||||
windowFrame.size.width = neededWidth;
|
|
||||||
[mWindow setFrame:windowFrame display: true animate: NO];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// do this down here because we may have made the window wider
|
|
||||||
// up above
|
|
||||||
[self setStringFitVertically:mDescriptionLabel
|
|
||||||
string:Str(ST_CRASHREPORTERDESCRIPTION)
|
|
||||||
resizeWindow:YES];
|
|
||||||
|
|
||||||
// now pin all the controls (except quit/submit) in place,
|
|
||||||
// if we lengthen the window after this, it's just to lengthen
|
|
||||||
// the progress text, so nothing above that text should move.
|
|
||||||
NSView* views[] = {
|
|
||||||
mSubmitReportButton,
|
|
||||||
mViewReportButton,
|
|
||||||
mCommentScrollView,
|
|
||||||
mIncludeURLButton,
|
|
||||||
mEmailMeButton,
|
|
||||||
mEmailText,
|
|
||||||
mProgressIndicator,
|
|
||||||
mProgressText
|
|
||||||
};
|
|
||||||
for (unsigned int i=0; i<sizeof(views)/sizeof(views[0]); i++) {
|
|
||||||
[views[i] setAutoresizingMask:NSViewMinYMargin];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(float)setStringFitVertically:(NSControl*)control
|
|
||||||
string:(NSString*)str
|
|
||||||
resizeWindow:(BOOL)resizeWindow
|
|
||||||
{
|
|
||||||
// hack to make the text field grow vertically
|
|
||||||
NSRect frame = [control frame];
|
|
||||||
float oldHeight = frame.size.height;
|
|
||||||
|
|
||||||
frame.size.height = 10000;
|
|
||||||
NSSize oldCellSize = [[control cell] cellSizeForBounds: frame];
|
|
||||||
[control setStringValue: str];
|
|
||||||
NSSize newCellSize = [[control cell] cellSizeForBounds: frame];
|
|
||||||
|
|
||||||
float delta = newCellSize.height - oldCellSize.height;
|
|
||||||
frame.origin.y -= delta;
|
|
||||||
frame.size.height = oldHeight + delta;
|
|
||||||
[control setFrame: frame];
|
|
||||||
|
|
||||||
if (resizeWindow) {
|
|
||||||
NSRect frame = [mWindow frame];
|
|
||||||
frame.origin.y -= delta;
|
|
||||||
frame.size.height += delta;
|
|
||||||
[mWindow setFrame:frame display: true animate: NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
return delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)setView: (NSView*)v animate: (BOOL)animate
|
|
||||||
{
|
|
||||||
NSRect frame = [mWindow frame];
|
|
||||||
|
|
||||||
NSRect oldViewFrame = [[mWindow contentView] frame];
|
|
||||||
NSRect newViewFrame = [v frame];
|
|
||||||
|
|
||||||
frame.origin.y += oldViewFrame.size.height - newViewFrame.size.height;
|
|
||||||
frame.size.height -= oldViewFrame.size.height - newViewFrame.size.height;
|
|
||||||
|
|
||||||
frame.origin.x += oldViewFrame.size.width - newViewFrame.size.width;
|
|
||||||
frame.size.width -= oldViewFrame.size.width - newViewFrame.size.width;
|
|
||||||
|
|
||||||
[mWindow setContentView:v];
|
|
||||||
[mWindow setFrame:frame display:true animate:animate];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)enableControls:(BOOL)enabled
|
|
||||||
{
|
|
||||||
[mViewReportButton setEnabled:enabled];
|
|
||||||
[mIncludeURLButton setEnabled:enabled];
|
|
||||||
[mEmailMeButton setEnabled:enabled];
|
|
||||||
[mCommentText setEnabled:enabled];
|
|
||||||
[mCommentScrollView setHasVerticalScroller:enabled];
|
|
||||||
[self updateEmail];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)updateSubmit
|
|
||||||
{
|
|
||||||
if ([mSubmitReportButton state] == NSOnState) {
|
|
||||||
[self setStringFitVertically:mProgressText
|
|
||||||
string:Str(ST_REPORTPRESUBMIT)
|
|
||||||
resizeWindow:YES];
|
|
||||||
[mProgressText setHidden:NO];
|
|
||||||
// enable all the controls
|
|
||||||
[self enableControls:YES];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// not submitting, disable all the controls under
|
|
||||||
// the submit checkbox, and hide the status text
|
|
||||||
[mProgressText setHidden:YES];
|
|
||||||
[self enableControls:NO];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)updateURL
|
|
||||||
{
|
|
||||||
if ([mIncludeURLButton state] == NSOnState && !gURLParameter.empty()) {
|
|
||||||
gQueryParameters["URL"] = gURLParameter;
|
|
||||||
} else {
|
|
||||||
gQueryParameters.erase("URL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)updateEmail
|
|
||||||
{
|
|
||||||
if ([mEmailMeButton state] == NSOnState &&
|
|
||||||
[mSubmitReportButton state] == NSOnState) {
|
|
||||||
NSString* email = [mEmailText stringValue];
|
|
||||||
gQueryParameters["Email"] = [email UTF8String];
|
|
||||||
[mEmailText setEnabled:YES];
|
|
||||||
} else {
|
|
||||||
gQueryParameters.erase("Email");
|
|
||||||
[mEmailText setEnabled:NO];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)sendReport
|
|
||||||
{
|
|
||||||
if (![self setupPost]) {
|
|
||||||
LogMessage("Crash report submission failed: could not set up POST data");
|
|
||||||
[self setStringFitVertically:mProgressText
|
|
||||||
string:Str(ST_SUBMITFAILED)
|
|
||||||
resizeWindow:YES];
|
|
||||||
// quit after 5 seconds
|
|
||||||
[self performSelector:@selector(closeMeDown:) withObject:nil
|
|
||||||
afterDelay:5.0];
|
|
||||||
}
|
|
||||||
|
|
||||||
[NSThread detachNewThreadSelector:@selector(uploadThread:)
|
|
||||||
toTarget:self
|
|
||||||
withObject:mPost];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(bool)setupPost
|
|
||||||
{
|
|
||||||
NSURL* url = [NSURL URLWithString:[NSSTR(gSendURL) stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
|
||||||
if (!url) return false;
|
|
||||||
|
|
||||||
mPost = [[HTTPMultipartUpload alloc] initWithURL: url];
|
|
||||||
if (!mPost) return false;
|
|
||||||
|
|
||||||
NSMutableDictionary* parameters =
|
|
||||||
[[NSMutableDictionary alloc] initWithCapacity: gQueryParameters.size()];
|
|
||||||
if (!parameters) return false;
|
|
||||||
|
|
||||||
StringTable::const_iterator end = gQueryParameters.end();
|
|
||||||
for (StringTable::const_iterator i = gQueryParameters.begin();
|
|
||||||
i != end;
|
|
||||||
i++) {
|
|
||||||
NSString* key = NSSTR(i->first);
|
|
||||||
NSString* value = NSSTR(i->second);
|
|
||||||
if (key && value) {
|
|
||||||
[parameters setObject: value forKey: key];
|
|
||||||
} else {
|
|
||||||
ostringstream message;
|
|
||||||
message << "Warning: skipping annotation '" << i->first
|
|
||||||
<< "' due to malformed UTF-8 encoding";
|
|
||||||
LogMessage(message.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (StringTable::const_iterator i = gFiles.begin();
|
|
||||||
i != gFiles.end();
|
|
||||||
i++) {
|
|
||||||
[mPost addFileAtPath: NSSTR(i->second) name: NSSTR(i->first)];
|
|
||||||
}
|
|
||||||
|
|
||||||
[mPost setParameters: parameters];
|
|
||||||
[parameters release];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)uploadComplete:(NSData*)data
|
|
||||||
{
|
|
||||||
NSHTTPURLResponse* response = [mPost response];
|
|
||||||
[mPost release];
|
|
||||||
|
|
||||||
bool success;
|
|
||||||
string reply;
|
|
||||||
if (!data || !response || [response statusCode] != 200) {
|
|
||||||
success = false;
|
|
||||||
reply = "";
|
|
||||||
|
|
||||||
// if data is nil, we probably logged an error in uploadThread
|
|
||||||
if (data != nil && response != nil) {
|
|
||||||
ostringstream message;
|
|
||||||
message << "Crash report submission failed: server returned status "
|
|
||||||
<< [response statusCode];
|
|
||||||
LogMessage(message.str());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
success = true;
|
|
||||||
LogMessage("Crash report submitted successfully");
|
|
||||||
|
|
||||||
NSString* encodingName = [response textEncodingName];
|
|
||||||
NSStringEncoding encoding;
|
|
||||||
if (encodingName) {
|
|
||||||
encoding = CFStringConvertEncodingToNSStringEncoding(
|
|
||||||
CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName));
|
|
||||||
} else {
|
|
||||||
encoding = NSISOLatin1StringEncoding;
|
|
||||||
}
|
|
||||||
NSString* r = [[NSString alloc] initWithData: data encoding: encoding];
|
|
||||||
reply = [r UTF8String];
|
|
||||||
[r release];
|
|
||||||
}
|
|
||||||
|
|
||||||
SendCompleted(success, reply);
|
|
||||||
|
|
||||||
[mProgressIndicator stopAnimation:self];
|
|
||||||
if (success) {
|
|
||||||
[self setStringFitVertically:mProgressText
|
|
||||||
string:Str(ST_REPORTSUBMITSUCCESS)
|
|
||||||
resizeWindow:YES];
|
|
||||||
} else {
|
|
||||||
[self setStringFitVertically:mProgressText
|
|
||||||
string:Str(ST_SUBMITFAILED)
|
|
||||||
resizeWindow:YES];
|
|
||||||
}
|
|
||||||
// quit after 5 seconds
|
|
||||||
[self performSelector:@selector(closeMeDown:) withObject:nil
|
|
||||||
afterDelay:5.0];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)uploadThread:(HTTPMultipartUpload*)post
|
|
||||||
{
|
|
||||||
NSAutoreleasePool* autoreleasepool = [[NSAutoreleasePool alloc] init];
|
|
||||||
NSError* error = nil;
|
|
||||||
NSData* data = [post send: &error];
|
|
||||||
if (error) {
|
|
||||||
data = nil;
|
|
||||||
NSString* errorDesc = [error localizedDescription];
|
|
||||||
string message = [errorDesc UTF8String];
|
|
||||||
LogMessage("Crash report submission failed: " + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
[self performSelectorOnMainThread: @selector(uploadComplete:)
|
|
||||||
withObject: data
|
|
||||||
waitUntilDone: YES];
|
|
||||||
|
|
||||||
[autoreleasepool release];
|
|
||||||
}
|
|
||||||
|
|
||||||
// to get auto-quit when we close the window
|
|
||||||
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)applicationWillTerminate:(NSNotification *)aNotification
|
|
||||||
{
|
|
||||||
// since we use [NSApp terminate:] we never return to main,
|
|
||||||
// so do our cleanup here
|
|
||||||
if (!gDidTrySend)
|
|
||||||
DeleteDump();
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation TextViewWithPlaceHolder
|
|
||||||
|
|
||||||
- (BOOL)becomeFirstResponder
|
|
||||||
{
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
return [super becomeFirstResponder];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)drawRect:(NSRect)rect
|
|
||||||
{
|
|
||||||
[super drawRect:rect];
|
|
||||||
if (mPlaceHolderString && [[self string] isEqualToString:@""] &&
|
|
||||||
self != [[self window] firstResponder])
|
|
||||||
[mPlaceHolderString drawInRect:[self frame]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)resignFirstResponder
|
|
||||||
{
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
return [super resignFirstResponder];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setPlaceholder:(NSString*)placeholder
|
|
||||||
{
|
|
||||||
NSColor* txtColor = [NSColor disabledControlTextColor];
|
|
||||||
NSDictionary* txtDict = [NSDictionary
|
|
||||||
dictionaryWithObjectsAndKeys:txtColor,
|
|
||||||
NSForegroundColorAttributeName, nil];
|
|
||||||
mPlaceHolderString = [[NSMutableAttributedString alloc]
|
|
||||||
initWithString:placeholder attributes:txtDict];
|
|
||||||
if (gRTLlayout)
|
|
||||||
[mPlaceHolderString setAlignment:NSRightTextAlignment
|
|
||||||
range:NSMakeRange(0, [placeholder length])];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)insertTab:(id)sender
|
|
||||||
{
|
|
||||||
// don't actually want to insert tabs, just tab to next control
|
|
||||||
[[self window] selectNextKeyView:sender];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)insertBacktab:(id)sender
|
|
||||||
{
|
|
||||||
[[self window] selectPreviousKeyView:sender];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setEnabled:(BOOL)enabled
|
|
||||||
{
|
|
||||||
[self setSelectable:enabled];
|
|
||||||
[self setEditable:enabled];
|
|
||||||
if (![[self string] isEqualToString:@""]) {
|
|
||||||
NSAttributedString* colorString;
|
|
||||||
NSColor* txtColor;
|
|
||||||
if (enabled)
|
|
||||||
txtColor = [NSColor textColor];
|
|
||||||
else
|
|
||||||
txtColor = [NSColor disabledControlTextColor];
|
|
||||||
NSDictionary *txtDict = [NSDictionary
|
|
||||||
dictionaryWithObjectsAndKeys:txtColor,
|
|
||||||
NSForegroundColorAttributeName, nil];
|
|
||||||
colorString = [[NSAttributedString alloc]
|
|
||||||
initWithString:[self string]
|
|
||||||
attributes:txtDict];
|
|
||||||
[[self textStorage] setAttributedString: colorString];
|
|
||||||
[self setInsertionPointColor:txtColor];
|
|
||||||
[colorString release];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc
|
|
||||||
{
|
|
||||||
[mPlaceHolderString release];
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
/* === Crashreporter UI Functions === */
|
|
||||||
|
|
||||||
bool UIInit()
|
|
||||||
{
|
|
||||||
gMainPool = [[NSAutoreleasePool alloc] init];
|
|
||||||
[NSApplication sharedApplication];
|
|
||||||
|
|
||||||
if (gStrings.find("isRTL") != gStrings.end() &&
|
|
||||||
gStrings["isRTL"] == "yes")
|
|
||||||
gRTLlayout = true;
|
|
||||||
|
|
||||||
[NSBundle loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu")
|
|
||||||
owner:NSApp];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIShutdown()
|
|
||||||
{
|
|
||||||
[gMainPool release];
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIShowDefaultUI()
|
|
||||||
{
|
|
||||||
[gUI showErrorUI: gStrings[ST_CRASHREPORTERDEFAULT]];
|
|
||||||
[NSApp run];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIShowCrashUI(const StringTable& files,
|
|
||||||
const StringTable& queryParameters,
|
|
||||||
const string& sendURL,
|
|
||||||
const vector<string>& restartArgs)
|
|
||||||
{
|
|
||||||
gRestartArgs = restartArgs;
|
|
||||||
|
|
||||||
[gUI showCrashUI: files
|
|
||||||
queryParameters: queryParameters
|
|
||||||
sendURL: sendURL];
|
|
||||||
[NSApp run];
|
|
||||||
|
|
||||||
return gDidTrySend;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIError_impl(const string& message)
|
|
||||||
{
|
|
||||||
if (!gUI) {
|
|
||||||
// UI failed to initialize, printing is the best we can do
|
|
||||||
printf("Error: %s\n", message.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[gUI showErrorUI: message];
|
|
||||||
[NSApp run];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIGetIniPath(string& path)
|
|
||||||
{
|
|
||||||
NSString* tmpPath = [NSString stringWithUTF8String:gArgv[0]];
|
|
||||||
NSString* iniName = [tmpPath lastPathComponent];
|
|
||||||
iniName = [iniName stringByAppendingPathExtension:@"ini"];
|
|
||||||
tmpPath = [tmpPath stringByDeletingLastPathComponent];
|
|
||||||
tmpPath = [tmpPath stringByDeletingLastPathComponent];
|
|
||||||
tmpPath = [tmpPath stringByAppendingPathComponent:@"Resources"];
|
|
||||||
tmpPath = [tmpPath stringByAppendingPathComponent:iniName];
|
|
||||||
path = [tmpPath UTF8String];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIGetSettingsPath(const string& vendor,
|
|
||||||
const string& product,
|
|
||||||
string& settingsPath)
|
|
||||||
{
|
|
||||||
FSRef foundRef;
|
|
||||||
OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType,
|
|
||||||
kCreateFolder, &foundRef);
|
|
||||||
if (err != noErr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
unsigned char path[PATH_MAX];
|
|
||||||
FSRefMakePath(&foundRef, path, sizeof(path));
|
|
||||||
NSString* destPath = [NSString stringWithUTF8String:reinterpret_cast<char*>(path)];
|
|
||||||
|
|
||||||
// Note that MacOS ignores the vendor when creating the profile hierarchy -
|
|
||||||
// all application preferences directories live alongside one another in
|
|
||||||
// ~/Library/Application Support/
|
|
||||||
destPath = [destPath stringByAppendingPathComponent: NSSTR(product)];
|
|
||||||
// Thunderbird stores its profile in ~/Library/Thunderbird,
|
|
||||||
// but we're going to put stuff in ~/Library/Application Support/Thunderbird
|
|
||||||
// anyway, so we have to ensure that path exists.
|
|
||||||
string tempPath = [destPath UTF8String];
|
|
||||||
if (!UIEnsurePathExists(tempPath))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
destPath = [destPath stringByAppendingPathComponent: @"Crash Reports"];
|
|
||||||
|
|
||||||
settingsPath = [destPath UTF8String];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIEnsurePathExists(const string& path)
|
|
||||||
{
|
|
||||||
int ret = mkdir(path.c_str(), S_IRWXU);
|
|
||||||
int e = errno;
|
|
||||||
if (ret == -1 && e != EEXIST)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIFileExists(const string& path)
|
|
||||||
{
|
|
||||||
struct stat sb;
|
|
||||||
int ret = stat(path.c_str(), &sb);
|
|
||||||
if (ret == -1 || !(sb.st_mode & S_IFREG))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIMoveFile(const string& file, const string& newfile)
|
|
||||||
{
|
|
||||||
if (!rename(file.c_str(), newfile.c_str()))
|
|
||||||
return true;
|
|
||||||
if (errno != EXDEV)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
||||||
NSString *source = [fileManager stringWithFileSystemRepresentation:file.c_str() length:file.length()];
|
|
||||||
NSString *dest = [fileManager stringWithFileSystemRepresentation:newfile.c_str() length:newfile.length()];
|
|
||||||
if (!source || !dest)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
[fileManager moveItemAtPath:source toPath:dest error:NULL];
|
|
||||||
return UIFileExists(newfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UIDeleteFile(const string& file)
|
|
||||||
{
|
|
||||||
return (unlink(file.c_str()) != -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream* UIOpenRead(const string& filename)
|
|
||||||
{
|
|
||||||
return new std::ifstream(filename.c_str(), std::ios::in);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ofstream* UIOpenWrite(const string& filename,
|
|
||||||
bool append, // append=false
|
|
||||||
bool binary) // binary=false
|
|
||||||
{
|
|
||||||
std::ios_base::openmode mode = std::ios::out;
|
|
||||||
|
|
||||||
if (append) {
|
|
||||||
mode = mode | std::ios::app;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (binary) {
|
|
||||||
mode = mode | std::ios::binary;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new std::ofstream(filename.c_str(), mode);
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "crashreporter.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
using namespace CrashReporter;
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
using std::sort;
|
|
||||||
|
|
||||||
struct FileData
|
|
||||||
{
|
|
||||||
time_t timestamp;
|
|
||||||
string path;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool CompareFDTime(const FileData& fd1, const FileData& fd2)
|
|
||||||
{
|
|
||||||
return fd1.timestamp > fd2.timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIPruneSavedDumps(const std::string& directory)
|
|
||||||
{
|
|
||||||
DIR *dirfd = opendir(directory.c_str());
|
|
||||||
if (!dirfd)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vector<FileData> dumpfiles;
|
|
||||||
|
|
||||||
while (dirent *dir = readdir(dirfd)) {
|
|
||||||
FileData fd;
|
|
||||||
fd.path = directory + '/' + dir->d_name;
|
|
||||||
if (fd.path.size() < 5)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (fd.path.compare(fd.path.size() - 4, 4, ".dmp") != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
if (stat(fd.path.c_str(), &st)) {
|
|
||||||
closedir(dirfd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd.timestamp = st.st_mtime;
|
|
||||||
|
|
||||||
dumpfiles.push_back(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
sort(dumpfiles.begin(), dumpfiles.end(), CompareFDTime);
|
|
||||||
|
|
||||||
while (dumpfiles.size() > kSaveCount) {
|
|
||||||
// get the path of the oldest file
|
|
||||||
string path = dumpfiles[dumpfiles.size() - 1].path;
|
|
||||||
UIDeleteFile(path.c_str());
|
|
||||||
|
|
||||||
// s/.dmp/.extra/
|
|
||||||
path.replace(path.size() - 4, 4, ".extra");
|
|
||||||
UIDeleteFile(path.c_str());
|
|
||||||
|
|
||||||
dumpfiles.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UIRunMinidumpAnalyzer(const string& exename, const string& filename)
|
|
||||||
{
|
|
||||||
// Run the minidump analyzer and wait for it to finish
|
|
||||||
pid_t pid = fork();
|
|
||||||
|
|
||||||
if (pid == -1) {
|
|
||||||
return; // Nothing to do upon failure
|
|
||||||
} else if (pid == 0) {
|
|
||||||
execl(exename.c_str(), exename.c_str(), filename.c_str(), nullptr);
|
|
||||||
} else {
|
|
||||||
waitpid(pid, nullptr, 0);
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,32 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>English</string>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>crashreporter</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>crashreporter</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>crashreporter.icns</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>org.mozilla.crashreporter</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>crashreporter</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>LSHasLocalizedDisplayName</key>
|
|
||||||
<true/>
|
|
||||||
<key>NSMainNibFile</key>
|
|
||||||
<string>MainMenu</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string>NSApplication</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -1,2 +0,0 @@
|
||||||
APPL????
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
/* Localized versions of Info.plist keys */
|
|
||||||
|
|
||||||
CFBundleName = "Crash Reporter";
|
|
||||||
CFBundleDisplayName = "Crash Reporter";
|
|
|
@ -1,102 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IBClasses</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>ACTIONS</key>
|
|
||||||
<dict>
|
|
||||||
<key>closeClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>emailMeClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>includeURLClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>restartClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>submitReportClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>viewReportClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>viewReportOkClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
</dict>
|
|
||||||
<key>CLASS</key>
|
|
||||||
<string>CrashReporterUI</string>
|
|
||||||
<key>LANGUAGE</key>
|
|
||||||
<string>ObjC</string>
|
|
||||||
<key>OUTLETS</key>
|
|
||||||
<dict>
|
|
||||||
<key>mCloseButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mCommentScrollView</key>
|
|
||||||
<string>NSScrollView</string>
|
|
||||||
<key>mCommentText</key>
|
|
||||||
<string>TextViewWithPlaceHolder</string>
|
|
||||||
<key>mDescriptionLabel</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mEmailMeButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mEmailText</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mErrorCloseButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mErrorHeaderLabel</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mErrorLabel</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mErrorView</key>
|
|
||||||
<string>NSView</string>
|
|
||||||
<key>mHeaderLabel</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mIncludeURLButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mProgressIndicator</key>
|
|
||||||
<string>NSProgressIndicator</string>
|
|
||||||
<key>mProgressText</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mRestartButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mSubmitReportButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mViewReportButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mViewReportOkButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mViewReportTextView</key>
|
|
||||||
<string>NSTextView</string>
|
|
||||||
<key>mViewReportWindow</key>
|
|
||||||
<string>NSWindow</string>
|
|
||||||
<key>mWindow</key>
|
|
||||||
<string>NSWindow</string>
|
|
||||||
</dict>
|
|
||||||
<key>SUPERCLASS</key>
|
|
||||||
<string>NSObject</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>ACTIONS</key>
|
|
||||||
<dict>
|
|
||||||
<key>insertTab</key>
|
|
||||||
<string>id</string>
|
|
||||||
</dict>
|
|
||||||
<key>CLASS</key>
|
|
||||||
<string>TextViewWithPlaceHolder</string>
|
|
||||||
<key>LANGUAGE</key>
|
|
||||||
<string>ObjC</string>
|
|
||||||
<key>SUPERCLASS</key>
|
|
||||||
<string>NSTextView</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>CLASS</key>
|
|
||||||
<string>FirstResponder</string>
|
|
||||||
<key>LANGUAGE</key>
|
|
||||||
<string>ObjC</string>
|
|
||||||
<key>SUPERCLASS</key>
|
|
||||||
<string>NSObject</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>IBVersion</key>
|
|
||||||
<string>1</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IBFramework Version</key>
|
|
||||||
<string>629</string>
|
|
||||||
<key>IBOldestOS</key>
|
|
||||||
<integer>5</integer>
|
|
||||||
<key>IBOpenObjects</key>
|
|
||||||
<array>
|
|
||||||
<integer>2</integer>
|
|
||||||
</array>
|
|
||||||
<key>IBSystem Version</key>
|
|
||||||
<string>9C7010</string>
|
|
||||||
<key>targetFramework</key>
|
|
||||||
<string>IBCocoaFramework</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
Binary file not shown.
|
@ -1,102 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IBClasses</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>ACTIONS</key>
|
|
||||||
<dict>
|
|
||||||
<key>closeClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>emailMeClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>includeURLClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>restartClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>submitReportClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>viewReportClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
<key>viewReportOkClicked</key>
|
|
||||||
<string>id</string>
|
|
||||||
</dict>
|
|
||||||
<key>CLASS</key>
|
|
||||||
<string>CrashReporterUI</string>
|
|
||||||
<key>LANGUAGE</key>
|
|
||||||
<string>ObjC</string>
|
|
||||||
<key>OUTLETS</key>
|
|
||||||
<dict>
|
|
||||||
<key>mCloseButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mCommentScrollView</key>
|
|
||||||
<string>NSScrollView</string>
|
|
||||||
<key>mCommentText</key>
|
|
||||||
<string>TextViewWithPlaceHolder</string>
|
|
||||||
<key>mDescriptionLabel</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mEmailMeButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mEmailText</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mErrorCloseButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mErrorHeaderLabel</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mErrorLabel</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mErrorView</key>
|
|
||||||
<string>NSView</string>
|
|
||||||
<key>mHeaderLabel</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mIncludeURLButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mProgressIndicator</key>
|
|
||||||
<string>NSProgressIndicator</string>
|
|
||||||
<key>mProgressText</key>
|
|
||||||
<string>NSTextField</string>
|
|
||||||
<key>mRestartButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mSubmitReportButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mViewReportButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mViewReportOkButton</key>
|
|
||||||
<string>NSButton</string>
|
|
||||||
<key>mViewReportTextView</key>
|
|
||||||
<string>NSTextView</string>
|
|
||||||
<key>mViewReportWindow</key>
|
|
||||||
<string>NSWindow</string>
|
|
||||||
<key>mWindow</key>
|
|
||||||
<string>NSWindow</string>
|
|
||||||
</dict>
|
|
||||||
<key>SUPERCLASS</key>
|
|
||||||
<string>NSObject</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>ACTIONS</key>
|
|
||||||
<dict>
|
|
||||||
<key>insertTab</key>
|
|
||||||
<string>id</string>
|
|
||||||
</dict>
|
|
||||||
<key>CLASS</key>
|
|
||||||
<string>TextViewWithPlaceHolder</string>
|
|
||||||
<key>LANGUAGE</key>
|
|
||||||
<string>ObjC</string>
|
|
||||||
<key>SUPERCLASS</key>
|
|
||||||
<string>NSTextView</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>CLASS</key>
|
|
||||||
<string>FirstResponder</string>
|
|
||||||
<key>LANGUAGE</key>
|
|
||||||
<string>ObjC</string>
|
|
||||||
<key>SUPERCLASS</key>
|
|
||||||
<string>NSObject</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>IBVersion</key>
|
|
||||||
<string>1</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IBFramework Version</key>
|
|
||||||
<string>629</string>
|
|
||||||
<key>IBOldestOS</key>
|
|
||||||
<integer>5</integer>
|
|
||||||
<key>IBOpenObjects</key>
|
|
||||||
<array>
|
|
||||||
<integer>2</integer>
|
|
||||||
</array>
|
|
||||||
<key>IBSystem Version</key>
|
|
||||||
<string>9D34</string>
|
|
||||||
<key>targetFramework</key>
|
|
||||||
<string>IBCocoaFramework</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,78 +0,0 @@
|
||||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
|
||||||
# vim: set filetype=python:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
if CONFIG['OS_TARGET'] != 'Android':
|
|
||||||
Program('crashreporter')
|
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
|
||||||
'crashreporter.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
|
||||||
UNIFIED_SOURCES += [
|
|
||||||
'crashreporter_win.cpp',
|
|
||||||
]
|
|
||||||
DEFINES['UNICODE'] = True
|
|
||||||
DEFINES['_UNICODE'] = True
|
|
||||||
USE_LIBS += [
|
|
||||||
'google_breakpad_libxul_s',
|
|
||||||
]
|
|
||||||
OS_LIBS += [
|
|
||||||
'comctl32',
|
|
||||||
'shell32',
|
|
||||||
'wininet',
|
|
||||||
'shlwapi',
|
|
||||||
]
|
|
||||||
elif CONFIG['OS_ARCH'] == 'Darwin':
|
|
||||||
UNIFIED_SOURCES += [
|
|
||||||
'crashreporter_osx.mm',
|
|
||||||
'crashreporter_unix_common.cpp',
|
|
||||||
]
|
|
||||||
LOCAL_INCLUDES += [
|
|
||||||
'../google-breakpad/src/common/mac',
|
|
||||||
]
|
|
||||||
OS_LIBS += ['-framework Cocoa']
|
|
||||||
USE_LIBS += [
|
|
||||||
'breakpad_common_s',
|
|
||||||
'breakpad_mac_common_s',
|
|
||||||
]
|
|
||||||
elif CONFIG['OS_ARCH'] == 'SunOS':
|
|
||||||
SOURCES += [
|
|
||||||
'crashreporter_linux.cpp',
|
|
||||||
'crashreporter_unix.cpp',
|
|
||||||
]
|
|
||||||
USE_LIBS += [
|
|
||||||
'breakpad_solaris_common_s',
|
|
||||||
]
|
|
||||||
|
|
||||||
if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
|
||||||
UNIFIED_SOURCES += [
|
|
||||||
'crashreporter_gtk_common.cpp',
|
|
||||||
'crashreporter_linux.cpp',
|
|
||||||
'crashreporter_unix_common.cpp'
|
|
||||||
]
|
|
||||||
USE_LIBS += [
|
|
||||||
'breakpad_linux_common_s',
|
|
||||||
]
|
|
||||||
OS_LIBS += CONFIG['TK_LIBS']
|
|
||||||
OS_LIBS += CONFIG['MOZ_GTHREAD_LIBS']
|
|
||||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
|
||||||
CXXFLAGS += CONFIG['MOZ_GTHREAD_CFLAGS']
|
|
||||||
|
|
||||||
if CONFIG['OS_ARCH'] == 'Linux' or CONFIG['OS_ARCH'] == 'SunOS':
|
|
||||||
FINAL_TARGET_FILES += [
|
|
||||||
'/toolkit/themes/windows/global/throbber/Throbber-small.gif',
|
|
||||||
]
|
|
||||||
|
|
||||||
DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
|
|
||||||
|
|
||||||
RCINCLUDE = 'crashreporter.rc'
|
|
||||||
|
|
||||||
# Don't use the STL wrappers in the crashreporter clients; they don't
|
|
||||||
# link with -lmozalloc, and it really doesn't matter here anyway.
|
|
||||||
DISABLE_STL_WRAPPING = True
|
|
||||||
|
|
||||||
include('/toolkit/crashreporter/crashreporter.mozbuild')
|
|
|
@ -1,37 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
//{{NO_DEPENDENCIES}}
|
|
||||||
// Microsoft Visual C++ generated include file.
|
|
||||||
// Used by crashreporter.rc
|
|
||||||
//
|
|
||||||
#define IDD_SENDDIALOG 102
|
|
||||||
#define IDR_THROBBER 103
|
|
||||||
#define IDD_VIEWREPORTDIALOG 104
|
|
||||||
#define IDI_MAINICON 105
|
|
||||||
#define IDC_PROGRESS 1003
|
|
||||||
#define IDC_DESCRIPTIONTEXT 1004
|
|
||||||
#define IDC_CLOSEBUTTON 1005
|
|
||||||
#define IDC_VIEWREPORTBUTTON 1006
|
|
||||||
#define IDC_SUBMITREPORTCHECK 1007
|
|
||||||
#define IDC_EMAILMECHECK 1008
|
|
||||||
#define IDC_EMAILTEXT 1009
|
|
||||||
#define IDC_INCLUDEURLCHECK 1010
|
|
||||||
#define IDC_COMMENTTEXT 1011
|
|
||||||
#define IDC_RESTARTBUTTON 1012
|
|
||||||
#define IDC_DESCRIPTIONLABEL 1013
|
|
||||||
#define IDC_PROGRESSTEXT 1014
|
|
||||||
#define IDC_THROBBER 1015
|
|
||||||
#define IDC_VIEWREPORTTEXT 1016
|
|
||||||
|
|
||||||
// Next default values for new objects
|
|
||||||
//
|
|
||||||
#ifdef APSTUDIO_INVOKED
|
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 106
|
|
||||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
|
||||||
#define _APS_NEXT_CONTROL_VALUE 1017
|
|
||||||
#define _APS_NEXT_SYMED_VALUE 101
|
|
||||||
#endif
|
|
||||||
#endif
|
|
|
@ -1,179 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
var { classes: Cc, utils: Cu, interfaces: Ci } = Components;
|
|
||||||
|
|
||||||
var reportURL;
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/CrashReports.jsm");
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
Cu.import("resource://gre/modules/Task.jsm");
|
|
||||||
Cu.import("resource://gre/modules/osfile.jsm");
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
|
|
||||||
"resource://gre/modules/CrashSubmit.jsm");
|
|
||||||
|
|
||||||
const buildID = Services.appinfo.appBuildID;
|
|
||||||
|
|
||||||
function submitPendingReport(event) {
|
|
||||||
let link = event.target;
|
|
||||||
let id = link.firstChild.textContent;
|
|
||||||
link.className = "submitting";
|
|
||||||
CrashSubmit.submit(id, { noThrottle: true }).then(
|
|
||||||
(remoteCrashID) => {
|
|
||||||
link.className = "";
|
|
||||||
// Reset the link to point at our new crash report. This way, if the
|
|
||||||
// user clicks "Back", the link will be correct.
|
|
||||||
link.firstChild.textContent = remoteCrashID;
|
|
||||||
link.setAttribute("id", remoteCrashID);
|
|
||||||
link.removeEventListener("click", submitPendingReport, true);
|
|
||||||
|
|
||||||
if (reportURL) {
|
|
||||||
link.setAttribute("href", reportURL + remoteCrashID);
|
|
||||||
// redirect the user to their brand new crash report
|
|
||||||
window.location.href = reportURL + remoteCrashID;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
// XXX: do something more useful here
|
|
||||||
link.className = "";
|
|
||||||
|
|
||||||
// Dispatch an event, useful for testing
|
|
||||||
let event = document.createEvent("Events");
|
|
||||||
event.initEvent("CrashSubmitFailed", true, false);
|
|
||||||
document.dispatchEvent(event);
|
|
||||||
});
|
|
||||||
event.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateReportList() {
|
|
||||||
|
|
||||||
Services.telemetry.getHistogramById("ABOUTCRASHES_OPENED_COUNT").add(1);
|
|
||||||
|
|
||||||
var prefService = Cc["@mozilla.org/preferences-service;1"].
|
|
||||||
getService(Ci.nsIPrefBranch);
|
|
||||||
|
|
||||||
try {
|
|
||||||
reportURL = prefService.getCharPref("breakpad.reportURL");
|
|
||||||
// Ignore any non http/https urls
|
|
||||||
if (!/^https?:/i.test(reportURL))
|
|
||||||
reportURL = null;
|
|
||||||
}
|
|
||||||
catch (e) { }
|
|
||||||
if (!reportURL) {
|
|
||||||
document.getElementById("clear-reports").style.display = "none";
|
|
||||||
document.getElementById("reportList").style.display = "none";
|
|
||||||
document.getElementById("noConfig").style.display = "block";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let reports = CrashReports.getReports();
|
|
||||||
|
|
||||||
if (reports.length == 0) {
|
|
||||||
document.getElementById("clear-reports").style.display = "none";
|
|
||||||
document.getElementById("reportList").style.display = "none";
|
|
||||||
document.getElementById("noReports").style.display = "block";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
|
||||||
.getService(Ci.nsIXULChromeRegistry)
|
|
||||||
.getSelectedLocale("global", true);
|
|
||||||
var dateFormatter = new Intl.DateTimeFormat(locale, { year: '2-digit',
|
|
||||||
month: 'numeric',
|
|
||||||
day: 'numeric' });
|
|
||||||
var timeFormatter = new Intl.DateTimeFormat(locale, { hour: 'numeric',
|
|
||||||
minute: 'numeric' });
|
|
||||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
|
||||||
getService(Ci.nsIIOService);
|
|
||||||
var reportURI = ios.newURI(reportURL, null, null);
|
|
||||||
// resolving this URI relative to /report/index
|
|
||||||
var aboutThrottling = ios.newURI("../../about/throttling", null, reportURI);
|
|
||||||
|
|
||||||
for (var i = 0; i < reports.length; i++) {
|
|
||||||
var row = document.createElement("tr");
|
|
||||||
var cell = document.createElement("td");
|
|
||||||
row.appendChild(cell);
|
|
||||||
var link = document.createElement("a");
|
|
||||||
if (reports[i].pending) {
|
|
||||||
link.setAttribute("href", aboutThrottling.spec);
|
|
||||||
link.addEventListener("click", submitPendingReport, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
link.setAttribute("href", reportURL + reports[i].id);
|
|
||||||
}
|
|
||||||
link.setAttribute("id", reports[i].id);
|
|
||||||
link.classList.add("crashReport");
|
|
||||||
link.appendChild(document.createTextNode(reports[i].id));
|
|
||||||
cell.appendChild(link);
|
|
||||||
|
|
||||||
var date = new Date(reports[i].date);
|
|
||||||
cell = document.createElement("td");
|
|
||||||
cell.appendChild(document.createTextNode(dateFormatter.format(date)));
|
|
||||||
row.appendChild(cell);
|
|
||||||
cell = document.createElement("td");
|
|
||||||
cell.appendChild(document.createTextNode(timeFormatter.format(date)));
|
|
||||||
row.appendChild(cell);
|
|
||||||
if (reports[i].pending) {
|
|
||||||
document.getElementById("unsubmitted").appendChild(row);
|
|
||||||
} else {
|
|
||||||
document.getElementById("submitted").appendChild(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var clearReports = Task.async(function*() {
|
|
||||||
let bundle = Services.strings.createBundle("chrome://global/locale/crashes.properties");
|
|
||||||
|
|
||||||
if (!Services.
|
|
||||||
prompt.confirm(window,
|
|
||||||
bundle.GetStringFromName("deleteconfirm.title"),
|
|
||||||
bundle.GetStringFromName("deleteconfirm.description"))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cleanupFolder = Task.async(function*(path, filter) {
|
|
||||||
let iterator = new OS.File.DirectoryIterator(path);
|
|
||||||
try {
|
|
||||||
yield iterator.forEach(Task.async(function*(aEntry) {
|
|
||||||
if (!filter || (yield filter(aEntry))) {
|
|
||||||
yield OS.File.remove(aEntry.path);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} catch (e) {
|
|
||||||
if (!(e instanceof OS.File.Error) || !e.becauseNoSuchFile) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
iterator.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
yield cleanupFolder(CrashReports.submittedDir.path, function*(aEntry) {
|
|
||||||
return aEntry.name.startsWith("bp-") && aEntry.name.endsWith(".txt");
|
|
||||||
});
|
|
||||||
|
|
||||||
let oneYearAgo = Date.now() - 31586000000;
|
|
||||||
yield cleanupFolder(CrashReports.reportsDir.path, function*(aEntry) {
|
|
||||||
if (!aEntry.name.startsWith("InstallTime") ||
|
|
||||||
aEntry.name == "InstallTime" + buildID) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let date = aEntry.winLastWriteDate;
|
|
||||||
if (!date) {
|
|
||||||
let stat = yield OS.File.stat(aEntry.path);
|
|
||||||
date = stat.lastModificationDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (date < oneYearAgo);
|
|
||||||
});
|
|
||||||
|
|
||||||
yield cleanupFolder(CrashReports.pendingDir.path);
|
|
||||||
|
|
||||||
document.getElementById("clear-reports").style.display = "none";
|
|
||||||
document.getElementById("reportList").style.display = "none";
|
|
||||||
document.getElementById("noReports").style.display = "block";
|
|
||||||
});
|
|
|
@ -1,123 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
|
||||||
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
|
|
||||||
[
|
|
||||||
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
|
|
||||||
<!ENTITY % crashesDTD SYSTEM "chrome://global/locale/crashes.dtd">
|
|
||||||
%globalDTD;
|
|
||||||
%crashesDTD;
|
|
||||||
]>
|
|
||||||
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<style type="text/css">
|
|
||||||
:root {
|
|
||||||
font-family: sans-serif;
|
|
||||||
margin: 40px auto;
|
|
||||||
min-width: 30em;
|
|
||||||
max-width: 60em;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
clear: both;
|
|
||||||
width: 90%;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding-bottom: 2em;
|
|
||||||
}
|
|
||||||
th {
|
|
||||||
font-size: 130%;
|
|
||||||
text-align: left;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
th[chromedir="rtl"] {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
/* name */
|
|
||||||
th:first-child {
|
|
||||||
padding-inline-end: 2em;
|
|
||||||
}
|
|
||||||
/* submitted */
|
|
||||||
th:last-child {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
:link, :visited {
|
|
||||||
display: block;
|
|
||||||
min-height: 17px;
|
|
||||||
}
|
|
||||||
/* date */
|
|
||||||
td:first-child + td {
|
|
||||||
width: 0;
|
|
||||||
padding-inline-start: 1em;
|
|
||||||
padding-inline-end: .5em;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
/* time */
|
|
||||||
td:last-child {
|
|
||||||
width: 0;
|
|
||||||
padding-inline-start: .5em;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
#clear-reports {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
#clear-reports[chromedir="rtl"] {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submitting {
|
|
||||||
background-image: url(chrome://global/skin/icons/loading.png);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: right;
|
|
||||||
background-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-resolution: 1.1dppx) {
|
|
||||||
.submitting {
|
|
||||||
background-image: url(chrome://global/skin/icons/loading@2x.png);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" media="screen, projection" type="text/css"
|
|
||||||
href="chrome://global/skin/in-content/common.css"/>
|
|
||||||
<script type="application/javascript;version=1.8" src="chrome://global/content/crashes.js"/>
|
|
||||||
|
|
||||||
<title>&crashReports.title;</title>
|
|
||||||
</head><body onload="populateReportList()" dir="&locale.dir;">
|
|
||||||
<button chromedir="&locale.dir;" id="clear-reports"
|
|
||||||
onclick="clearReports().then(null, Cu.reportError)">&clearAllReports.label;</button>
|
|
||||||
<div id="reportList">
|
|
||||||
<div id="reportListUnsubmitted">
|
|
||||||
<h1>&crashesUnsubmitted.label;</h1>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th chromedir="&locale.dir;">&id.heading;</th>
|
|
||||||
<th chromedir="&locale.dir;" colspan="2">&dateCrashed.heading;</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="unsubmitted">
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div id="reportListSubmitted">
|
|
||||||
<h1>&crashesSubmitted.label;</h1>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th chromedir="&locale.dir;">&id.heading;</th>
|
|
||||||
<th chromedir="&locale.dir;" colspan="2">&dateSubmitted.heading;</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="submitted">
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p id="noReports" style="display: none">&noReports.label;</p>
|
|
||||||
<p id="noConfig" style="display: none">&noConfig.label;</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,24 +0,0 @@
|
||||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
|
||||||
# vim: set filetype=python:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
|
||||||
'/toolkit/crashreporter/google-breakpad/src',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Suppress warnings in third-party code.
|
|
||||||
if CONFIG['_MSC_VER']:
|
|
||||||
CXXFLAGS += [
|
|
||||||
'-wd4005', # macro redefinition
|
|
||||||
]
|
|
||||||
elif CONFIG['GNU_CXX']:
|
|
||||||
CXXFLAGS += [
|
|
||||||
'-Wno-unused-local-typedefs',
|
|
||||||
'-Wno-shadow',
|
|
||||||
]
|
|
||||||
if CONFIG['CLANG_CXX']:
|
|
||||||
CXXFLAGS += ['-Wno-implicit-fallthrough']
|
|
||||||
|
|
||||||
DEFINES['NO_STABS_SUPPORT'] = True
|
|
|
@ -1,195 +0,0 @@
|
||||||
==============
|
|
||||||
Crash Reporter
|
|
||||||
==============
|
|
||||||
|
|
||||||
Overview
|
|
||||||
========
|
|
||||||
|
|
||||||
The **crash reporter** is a subsystem to record and manage application
|
|
||||||
crash data.
|
|
||||||
|
|
||||||
While the subsystem is known as *crash reporter*, it helps to think of
|
|
||||||
it more as a *process dump manager*. This is because the heart of this
|
|
||||||
subsystem is really managing process dump files and these files are
|
|
||||||
created not only from process crashes but also from hangs and other
|
|
||||||
exceptional events.
|
|
||||||
|
|
||||||
The crash reporter subsystem is composed of a number of pieces working
|
|
||||||
together.
|
|
||||||
|
|
||||||
Breakpad
|
|
||||||
Breakpad is a library and set of tools to make collecting process
|
|
||||||
information (notably dumps from crashes) easy. Breakpad is a 3rd
|
|
||||||
party project (originaly developed by Google) that is imported into
|
|
||||||
the tree.
|
|
||||||
|
|
||||||
Dump files
|
|
||||||
Breakpad produces files called *dump files* that hold process data
|
|
||||||
(stacks, heap data, etc).
|
|
||||||
|
|
||||||
Crash Reporter Client
|
|
||||||
The crash reporter client is a standalone executable that is launched
|
|
||||||
to handle dump files. This application optionally submits crashes to
|
|
||||||
Mozilla (or the configured server).
|
|
||||||
|
|
||||||
Minidump Analyzer
|
|
||||||
The minidump analyzer is a standalone executable that is launched by the
|
|
||||||
crash reporter client or by the browser itself to extract stack traces from
|
|
||||||
the dump files generated during a crash. It appends the stack traces to the
|
|
||||||
.extra file associated with the crash dump.
|
|
||||||
|
|
||||||
How Main-Process Crash Handling Works
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
The crash handler is hooked up very early in the Gecko process lifetime.
|
|
||||||
It all starts in ``XREMain::XRE_mainInit()`` from ``nsAppRunner.cpp``.
|
|
||||||
Assuming crash reporting is enabled, this startup function registers an
|
|
||||||
exception handler for the process and tells the crash reporter subsystem
|
|
||||||
about basic metadata such as the application name and version.
|
|
||||||
|
|
||||||
The registration of the crash reporter exception handler doubles as
|
|
||||||
initialization of the crash reporter itself. This happens in
|
|
||||||
``CrashReporter::SetExceptionHandler()`` from ``nsExceptionHandler.cpp``.
|
|
||||||
The crash reporter figures out what application to use for reporting
|
|
||||||
dumped crashes and where to store these dump files on disk. The Breakpad
|
|
||||||
exception handler (really just a mechanism for dumping process state) is
|
|
||||||
initialized as part of this function. The Breakpad exception handler is
|
|
||||||
a ``google_breakpad::ExceptionHandler`` instance and it's stored as
|
|
||||||
``gExceptionHandler``.
|
|
||||||
|
|
||||||
As the application runs, various other systems may write *annotations*
|
|
||||||
or *notes* to the crash reporter to indicate state of the application,
|
|
||||||
help with possible reasons for a current or future crash, etc. These are
|
|
||||||
performed via ``CrashReporter::AnnotateCrashReport()`` and
|
|
||||||
``CrashReporter::AppendAppNotesToCrashReport()`` from
|
|
||||||
``nsExceptionHandler.h``.
|
|
||||||
|
|
||||||
For well running applications, this is all that happens. However, if a
|
|
||||||
crash or similar exceptional event occurs (such as a hang), we need to
|
|
||||||
write a crash report.
|
|
||||||
|
|
||||||
When an event worthy of writing a dump occurs, the Breakpad exception
|
|
||||||
handler is invoked and Breakpad does its thing. When Breakpad has
|
|
||||||
finished, it calls back into ``CrashReporter::MinidumpCallback()`` from
|
|
||||||
``nsExceptionHandler.cpp`` to tell the crash reporter about what was
|
|
||||||
written.
|
|
||||||
|
|
||||||
``MinidumpCallback()`` performs a number of actions once a dump has been
|
|
||||||
written. It writes a file with the time of the crash so other systems can
|
|
||||||
easily determine the time of the last crash. It supplements the dump
|
|
||||||
file with an *extra* file containing Mozilla-specific metadata. This data
|
|
||||||
includes the annotations set via ``CrashReporter::AnnotateCrashReport()``
|
|
||||||
as well as time since last crash, whether garbage collection was active at
|
|
||||||
the time of the crash, memory statistics, etc.
|
|
||||||
|
|
||||||
If the *crash reporter client* is enabled, ``MinidumpCallback()`` invokes
|
|
||||||
it. It simply tries to create a new *crash reporter client* process (e.g.
|
|
||||||
*crashreporter.exe*) with the path to the written minidump file as an
|
|
||||||
argument.
|
|
||||||
|
|
||||||
The *crash reporter client* performs a number of roles. There's a lot going
|
|
||||||
on, so you may want to look at ``main()`` in ``crashreporter.cpp``. First,
|
|
||||||
stack traces are extracted from the dump via the *minidump analyzer* tool.
|
|
||||||
The resulting traces are appended to the .extra file of the crash. Then, the
|
|
||||||
*crash reporter client* verifies that the dump data is sane. If it isn't
|
|
||||||
(e.g. required metadata is missing), the dump data is ignored. If dump data
|
|
||||||
looks sane, the dump data
|
|
||||||
is moved into the *pending* directory for the configured data directory
|
|
||||||
(defined via the ``MOZ_CRASHREPORTER_DATA_DIRECTORY`` environment variable
|
|
||||||
or from the UI). Once this is done, the main crash reporter UI is displayed
|
|
||||||
via ``UIShowCrashUI()``. The crash reporter UI is platform specific: there
|
|
||||||
are separate versions for Windows, OS X, and various \*NIX presentation
|
|
||||||
flavors (such as GTK). The basic gist is a dialog is displayed to the user
|
|
||||||
and the user has the opportunity to submit this dump data to a remote
|
|
||||||
server.
|
|
||||||
|
|
||||||
If a dump is submitted via the crash reporter, the raw dump files are
|
|
||||||
removed from the *pending* directory and a file containing the
|
|
||||||
crash ID from the remote server for the submitted dump is created in the
|
|
||||||
*submitted* directory.
|
|
||||||
|
|
||||||
If the user chooses not to submit a dump in the crash reporter UI, the dump
|
|
||||||
files are deleted.
|
|
||||||
|
|
||||||
And that's pretty much what happens when a crash/dump is written!
|
|
||||||
|
|
||||||
Plugin and Child Process Crashes
|
|
||||||
================================
|
|
||||||
|
|
||||||
Crashes in plugin and child processes are also managed by the crash
|
|
||||||
reporting subsystem.
|
|
||||||
|
|
||||||
Child process crashes are handled by the ``mozilla::dom::CrashReporterParent``
|
|
||||||
class defined in ``dom/ipc``. When a child process crashes, the toplevel IPDL
|
|
||||||
actor should check for it by calling TakeMinidump in its ``ActorDestroy``
|
|
||||||
Method: see ``mozilla::plugins::PluginModuleParent::ActorDestroy`` and
|
|
||||||
``mozilla::plugins::PluginModuleParent::ProcessFirstMinidump``. That method
|
|
||||||
is responsible for calling
|
|
||||||
``mozilla::dom::CrashReporterParent::GenerateCrashReportForMinidump`` with
|
|
||||||
appropriate crash annotations specific to the crash. All child-process
|
|
||||||
crashes are annotated with a ``ProcessType`` annotation, such as "content" or
|
|
||||||
"plugin".
|
|
||||||
|
|
||||||
Submission of child process crashes is handled by application code. This
|
|
||||||
code prompts the user to submit crashes in context-appropriate UI and then
|
|
||||||
submits the crashes using ``CrashSubmit.jsm``.
|
|
||||||
|
|
||||||
Memory Reports
|
|
||||||
==============
|
|
||||||
|
|
||||||
When a process detects that it is running low on memory, a memory report is
|
|
||||||
saved. If the process crashes, the memory report will be included with the crash
|
|
||||||
report. ``nsThread::SaveMemoryReportNearOOM()`` checks to see if the process is
|
|
||||||
low on memory every 30 seconds at most and saves a report every 3 minutes at
|
|
||||||
most. Since a child process cannot actually save to the hard drive, it instead
|
|
||||||
notifies its parent process, which saves the report for it. If a crash does
|
|
||||||
occur, the memory report is moved to the *pending* directory with the other dump
|
|
||||||
data and an annotation is added to indicate the presence of the report. This
|
|
||||||
happens in ``nsExceptionHandler.cpp``, but occurs in different functions
|
|
||||||
depending on what process crashed. When the main process crashes, this happens
|
|
||||||
in ``MinidumpCallback()``. When a child process crashes, it happens in
|
|
||||||
``OnChildProcessDumpRequested()``, with the annotation being added in
|
|
||||||
``WriteExtraData()``.
|
|
||||||
|
|
||||||
Flash Process Crashes
|
|
||||||
=====================
|
|
||||||
|
|
||||||
On Windows Vista+, the Adobe Flash plugin creates two extra processes in its
|
|
||||||
Firefox plugin to implement OS-level sandboxing. In order to catch crashes in
|
|
||||||
these processes, Firefox injects a crash report handler into the process using the code at ``InjectCrashReporter.cpp``. When these crashes occur, the
|
|
||||||
ProcessType=plugin annotation is present, and an additional annotation
|
|
||||||
FlashProcessDump has the value "Sandbox" or "Broker".
|
|
||||||
|
|
||||||
Plugin Hangs
|
|
||||||
============
|
|
||||||
|
|
||||||
Plugin hangs are handled as crash reports. If a plugin doesn't respond to an
|
|
||||||
IPC message after 60 seconds, the plugin IPC code will take minidumps of all
|
|
||||||
of the processes involved and then kill the plugin.
|
|
||||||
|
|
||||||
In this case, there will be only one .ini file with the crash report metadata,
|
|
||||||
but there will be multiple dump files: at least one for the browser process and
|
|
||||||
one for the plugin process, and perhaps also additional dumps for the Flash
|
|
||||||
sandbox and broker processes. All of these files are submitted together as a
|
|
||||||
unit. Before submission, the filenames of the files are linked:
|
|
||||||
|
|
||||||
- **uuid.ini** - *annotations, includes an additional_minidumps field*
|
|
||||||
- **uuid.dmp** - *plugin process dump file*
|
|
||||||
- **uuid-<other>.dmp** - *other process dump file as listed in additional_minidumps*
|
|
||||||
|
|
||||||
Browser Hangs
|
|
||||||
=============
|
|
||||||
|
|
||||||
There is a feature of Firefox that will crash Firefox if it stops processing
|
|
||||||
messages after a certain period of time. This feature doesn't work well and is
|
|
||||||
disabled by default. See ``xpcom/threads/HangMonitor.cpp``. Hang crashes
|
|
||||||
are annotated with ``Hang=1``.
|
|
||||||
|
|
||||||
about:crashes
|
|
||||||
=============
|
|
||||||
|
|
||||||
If the crash reporter subsystem is enabled, the *about:crashes*
|
|
||||||
page will be registered with the application. This page provides
|
|
||||||
information about previous and submitted crashes.
|
|
||||||
|
|
||||||
It is also possible to submit crashes from *about:crashes*.
|
|
82
toolkit/crashreporter/google-breakpad/.gitignore
vendored
82
toolkit/crashreporter/google-breakpad/.gitignore
vendored
|
@ -1,82 +0,0 @@
|
||||||
# Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are
|
|
||||||
# met:
|
|
||||||
#
|
|
||||||
# * Redistributions of source code must retain the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above
|
|
||||||
# copyright notice, this list of conditions and the following disclaimer
|
|
||||||
# in the documentation and/or other materials provided with the
|
|
||||||
# distribution.
|
|
||||||
# * Neither the name of Google Inc. nor the names of its
|
|
||||||
# contributors may be used to endorse or promote products derived from
|
|
||||||
# this software without specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
# Ignore other VCSs.
|
|
||||||
.svn/
|
|
||||||
|
|
||||||
# Ignore common compiled artifacts.
|
|
||||||
*~
|
|
||||||
*.dwo
|
|
||||||
*.o
|
|
||||||
lib*.a
|
|
||||||
/breakpad.pc
|
|
||||||
/breakpad-client.pc
|
|
||||||
/src/client/linux/linux_client_unittest_shlib
|
|
||||||
/src/client/linux/linux_dumper_unittest_helper
|
|
||||||
/src/processor/microdump_stackwalk
|
|
||||||
/src/processor/minidump_dump
|
|
||||||
/src/processor/minidump_stackwalk
|
|
||||||
/src/tools/linux/core2md/core2md
|
|
||||||
/src/tools/linux/dump_syms/dump_syms
|
|
||||||
/src/tools/linux/md2core/minidump-2-core
|
|
||||||
/src/tools/linux/symupload/minidump_upload
|
|
||||||
/src/tools/linux/symupload/sym_upload
|
|
||||||
/src/tools/mac/dump_syms/dump_syms
|
|
||||||
|
|
||||||
# Ignore autotools generated artifacts.
|
|
||||||
.deps
|
|
||||||
.dirstamp
|
|
||||||
autom4te.cache/
|
|
||||||
/config.cache
|
|
||||||
config.h
|
|
||||||
/config.log
|
|
||||||
/config.status
|
|
||||||
/Makefile
|
|
||||||
stamp-h1
|
|
||||||
|
|
||||||
# Ignore GYP generated Visual Studio artifacts.
|
|
||||||
*.filters
|
|
||||||
*.sdf
|
|
||||||
*.sln
|
|
||||||
*.suo
|
|
||||||
*.vcproj
|
|
||||||
*.vcxproj
|
|
||||||
|
|
||||||
# Ignore GYP generated Makefiles
|
|
||||||
src/Makefile
|
|
||||||
*.Makefile
|
|
||||||
*.target.mk
|
|
||||||
|
|
||||||
# Ignore compiled Python files.
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Ignore directories gclient syncs.
|
|
||||||
src/testing
|
|
||||||
src/third_party/glog
|
|
||||||
src/third_party/protobuf
|
|
||||||
src/tools/gyp
|
|
|
@ -1 +0,0 @@
|
||||||
opensource@google.com
|
|
|
@ -1,75 +0,0 @@
|
||||||
# Copyright 2010 Google Inc. All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are
|
|
||||||
# met:
|
|
||||||
#
|
|
||||||
# * Redistributions of source code must retain the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above
|
|
||||||
# copyright notice, this list of conditions and the following disclaimer
|
|
||||||
# in the documentation and/or other materials provided with the
|
|
||||||
# distribution.
|
|
||||||
# * Neither the name of Google Inc. nor the names of its
|
|
||||||
# contributors may be used to endorse or promote products derived from
|
|
||||||
# this software without specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
# This is used to mimic the svn:externals mechanism for gclient (both Git and
|
|
||||||
# SVN) based checkouts of Breakpad. As such, its use is entirely optional. If
|
|
||||||
# using a manually managed SVN checkout as opposed to a gclient managed checkout
|
|
||||||
# you can still use the hooks mechanism for generating project files by calling
|
|
||||||
# 'gclient runhooks' rather than 'gclient sync'.
|
|
||||||
|
|
||||||
deps = {
|
|
||||||
# Logging code.
|
|
||||||
"src/src/third_party/glog":
|
|
||||||
"https://github.com/google/glog.git" +
|
|
||||||
"@v0.3.4",
|
|
||||||
|
|
||||||
# Testing libraries and utilities.
|
|
||||||
"src/src/testing":
|
|
||||||
"https://github.com/google/googlemock.git" +
|
|
||||||
"@release-1.7.0",
|
|
||||||
"src/src/testing/gtest":
|
|
||||||
"https://github.com/google/googletest.git" +
|
|
||||||
"@release-1.7.0",
|
|
||||||
|
|
||||||
# Protobuf.
|
|
||||||
"src/src/third_party/protobuf/protobuf":
|
|
||||||
"https://github.com/google/protobuf.git" +
|
|
||||||
"@cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac",
|
|
||||||
|
|
||||||
# GYP project generator.
|
|
||||||
"src/src/tools/gyp":
|
|
||||||
"https://chromium.googlesource.com/external/gyp/" +
|
|
||||||
"@e8ab0833a42691cd2184bd4c45d779e43821d3e0",
|
|
||||||
|
|
||||||
# Linux syscall support.
|
|
||||||
"src/src/third_party/lss":
|
|
||||||
"https://chromium.googlesource.com/linux-syscall-support/" +
|
|
||||||
"@3f6478ac95edf86cd3da300c2c0d34a438f5dbeb",
|
|
||||||
}
|
|
||||||
|
|
||||||
hooks = [
|
|
||||||
{
|
|
||||||
# TODO(chrisha): Fix the GYP files so that they work without
|
|
||||||
# --no-circular-check.
|
|
||||||
"pattern": ".",
|
|
||||||
"action": ["python",
|
|
||||||
"src/src/tools/gyp/gyp_main.py",
|
|
||||||
"--no-circular-check",
|
|
||||||
"src/src/client/windows/breakpad_client.gyp"],
|
|
||||||
},
|
|
||||||
]
|
|
|
@ -1 +0,0 @@
|
||||||
704f41ec901c419f8c321742114b415e6f5ceacc
|
|
|
@ -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.
|
|
|
@ -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
|
@ -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
|
|
|
@ -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 they’re 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 CC’d.
|
|
1297
toolkit/crashreporter/google-breakpad/aclocal.m4
vendored
1297
toolkit/crashreporter/google-breakpad/aclocal.m4
vendored
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
|
@ -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.
|
|
|
@ -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."
|
|
||||||
|
|
|
@ -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).
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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='[0;31m' # Red.
|
|
||||||
grn='[0;32m' # Green.
|
|
||||||
lgn='[1;32m' # Light green.
|
|
||||||
blu='[1;34m' # Blue.
|
|
||||||
mgn='[0;35m' # Magenta.
|
|
||||||
std='[m' # 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:
|
|
|
@ -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.
|
|
|
@ -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
|
@ -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:
|
|
|
@ -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
|
@ -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:
|
|
|
@ -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='[0;31m' # Red.
|
|
||||||
grn='[0;32m' # Green.
|
|
||||||
lgn='[1;32m' # Light green.
|
|
||||||
blu='[1;34m' # Blue.
|
|
||||||
mgn='[0;35m' # Magenta.
|
|
||||||
std='[m' # 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:
|
|
|
@ -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@
|
|
|
@ -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@
|
|
|
@ -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/+/
|
|
9255
toolkit/crashreporter/google-breakpad/configure
vendored
9255
toolkit/crashreporter/google-breakpad/configure
vendored
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
|
@ -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
|
|
7377
toolkit/crashreporter/google-breakpad/m4/libtool.m4
vendored
7377
toolkit/crashreporter/google-breakpad/m4/libtool.m4
vendored
File diff suppressed because it is too large
Load Diff
|
@ -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])])
|
|
123
toolkit/crashreporter/google-breakpad/m4/ltsugar.m4
vendored
123
toolkit/crashreporter/google-breakpad/m4/ltsugar.m4
vendored
|
@ -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
|
|
||||||
])
|
|
|
@ -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)
|
|
||||||
])
|
|
|
@ -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])])
|
|
|
@ -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__
|
|
|
@ -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
|
@ -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/'],
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
}
|
|
|
@ -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())
|
|
|
@ -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',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
|
@ -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"
|
|
|
@ -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
|
|
|
@ -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, ¶ms, 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,
|
|
||||||
¶ms,
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 */;
|
|
||||||
}
|
|
|
@ -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_
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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_
|
|
|
@ -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
|
|
|
@ -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
Loading…
Reference in New Issue
Block a user