Remove crashreporter toolkit files.
parent
b2628357b3
commit
e26c5e1e50
|
@ -70,7 +70,6 @@ IPDL_SOURCES = [
|
|||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/ipc',
|
||||
'/toolkit/crashreporter',
|
||||
'/xpcom/threads',
|
||||
]
|
||||
|
||||
|
|
|
@ -177,7 +177,6 @@ IPDL_SOURCES = [
|
|||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/ipc',
|
||||
'/toolkit/crashreporter',
|
||||
'/toolkit/xre',
|
||||
'/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*.
|
|
@ -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.
|
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/+/
|
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
|
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])])
|
|
@ -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