added breakpad support for os x

This commit is contained in:
John Preston 2016-02-01 13:12:37 +03:00
parent 56fa8a0ee2
commit daa0adfff9
48 changed files with 9082 additions and 72 deletions

View file

@ -656,60 +656,6 @@ namespace SignalHandlers {
return stream;
}
google_breakpad::ExceptionHandler* BreakpadExceptionHandler = 0;
#ifdef Q_OS_WIN
bool DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success)
#elif defined Q_OS_MAC
bool DumpCallback(const char* _dump_dir, const char* _minidump_id, void *context, bool success)
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32
bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success)
#endif
{
return success;
}
void StartBreakpad() {
QString dumpPath = cWorkingDir() + qsl("tdumps");
QDir().mkpath(dumpPath);
#ifdef Q_OS_WIN
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
dumpPath.toStdWString(),
/*FilterCallback*/ 0,
DumpCallback,
/*context*/ 0,
true
);
#elif defined Q_OS_MAC
pHandler = new google_breakpad::ExceptionHandler(
dumpPath.toStdString(),
/*FilterCallback*/ 0,
DumpCallback,
/*context*/ 0,
true,
0
);
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32
pHandler = new google_breakpad::ExceptionHandler(
google_breakpad::MinidumpDescriptor(dumpPath.toStdString()),
/*FilterCallback*/ 0,
DumpCallback,
/*context*/ 0,
true,
-1
);
#endif
}
void FinishBreakpad() {
if (BreakpadExceptionHandler) {
google_breakpad::ExceptionHandler *h = BreakpadExceptionHandler;
BreakpadExceptionHandler = 0;
delete h;
}
}
Qt::HANDLE LoggingCrashThreadId = 0;
bool LoggingCrashHeaderWritten = false;
QMutex LoggingCrashMutex;
@ -719,7 +665,9 @@ namespace SignalHandlers {
struct sigaction SIG_def[32];
void Handler(int signum, siginfo_t *info, void *ucontext) {
sigaction(signum, &SIG_def[signum], 0);
if (signum > 0) {
sigaction(signum, &SIG_def[signum], 0);
}
#else
void Handler(int signum) {
@ -780,6 +728,7 @@ namespace SignalHandlers {
ucontext_t *uc = (ucontext_t*)ucontext;
void *caller = 0;
if (uc) {
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
/* OSX < 10.6 */
#if defined(__x86_64__)
@ -807,6 +756,7 @@ namespace SignalHandlers {
#endif
#endif
}
void *addresses[132] = { 0 };
size_t size = backtrace(addresses, 128);
@ -849,6 +799,63 @@ namespace SignalHandlers {
LoggingCrashThreadId = 0;
}
google_breakpad::ExceptionHandler* BreakpadExceptionHandler = 0;
#ifdef Q_OS_WIN
bool DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success)
#elif defined Q_OS_MAC
bool DumpCallback(const char* _dump_dir, const char* _minidump_id, void *context, bool success)
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32
bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success)
#endif
{
#ifdef Q_OS_MAC
Handler(-1, 0, 0);
#endif
return success;
}
void StartBreakpad() {
QString dumpPath = cWorkingDir() + qsl("tdumps");
QDir().mkpath(dumpPath);
#ifdef Q_OS_WIN
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
dumpPath.toStdWString(),
/*FilterCallback*/ 0,
DumpCallback,
/*context*/ 0,
true
);
#elif defined Q_OS_MAC
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
dumpPath.toStdString(),
/*FilterCallback*/ 0,
DumpCallback,
/*context*/ 0,
true,
0
);
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
google_breakpad::MinidumpDescriptor(dumpPath.toStdString()),
/*FilterCallback*/ 0,
DumpCallback,
/*context*/ 0,
true,
-1
);
#endif
}
void FinishBreakpad() {
if (BreakpadExceptionHandler) {
google_breakpad::ExceptionHandler *h = BreakpadExceptionHandler;
BreakpadExceptionHandler = 0;
delete h;
}
}
Status start() {
CrashDumpPath = (cWorkingDir() + qsl("tdata/working")).toUtf8();
if (FILE *f = fopen(CrashDumpPath.constData(), "rb")) {
@ -893,7 +900,9 @@ namespace SignalHandlers {
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
#ifndef Q_OS_MAC // let breakpad handle this
sigaction(SIGABRT, &sigact, &SIG_def[SIGABRT]);
#endif
sigaction(SIGSEGV, &sigact, &SIG_def[SIGSEGV]);
sigaction(SIGILL, &sigact, &SIG_def[SIGILL]);
sigaction(SIGFPE, &sigact, &SIG_def[SIGFPE]);

View file

@ -22,7 +22,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#define PSAPI_VERSION 1 // fix WinXP
//#define Q_NO_TEMPLATE_FRIENDS // fix some compiler difference issues
#include <signal.h>
#define __STDC_FORMAT_MACROS // fix breakpad for mac
#ifdef __cplusplus
#include <openssl/bn.h>
#include <openssl/rsa.h>
@ -52,12 +54,18 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
extern "C" {
#endif
#include "zip.h"
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
}
#include "types.h"
@ -79,3 +87,5 @@ extern "C" {
#include "gui/flatlabel.h"
#include "app.h"
#endif

View file

@ -41,8 +41,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "mediaview.h"
#include "localstorage.h"
#include "zip.h"
ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : QWidget(parent), _shadow(st::boxShadow), _reconnect(this, QString()) {
set(text, reconnect);
connect(&_reconnect, SIGNAL(clicked()), this, SLOT(onReconnect()));
@ -2019,7 +2017,6 @@ LastCrashedWindow::LastCrashedWindow()
#endif
{
#ifdef Q_OS_WIN
if (_sendingState != SendingNoReport) {
QString maxDump, maxDumpFull;
QDateTime maxDumpModified, workingModified = QFileInfo(cWorkingDir() + qsl("tdata/working")).lastModified();
@ -2044,7 +2041,6 @@ LastCrashedWindow::LastCrashedWindow()
_minidump.setText(qsl("+ %1 (%2 KB)").arg(_minidumpName).arg(maxDumpSize / 1024));
}
#endif
_networkSettings.setText(qsl("NETWORK SETTINGS"));
connect(&_networkSettings, SIGNAL(clicked()), this, SLOT(onNetworkSettings()));
@ -2306,10 +2302,9 @@ void LastCrashedWindow::onCheckingFinished() {
reportPart.setBody(Global::LastCrashDump());
multipart->append(reportPart);
#ifdef Q_OS_WIN
QFileInfo dmpFile(_minidumpFull);
if (dmpFile.exists() && dmpFile.size() > 0 && dmpFile.size() < 20 * 1024 * 1024 &&
QRegularExpression(qsl("^[a-z0-9\\-]{1,64}\\.dmp$")).match(dmpFile.fileName()).hasMatch()) {
QRegularExpression(qsl("^[a-zA-Z0-9\\-]{1,64}\\.dmp$")).match(dmpFile.fileName()).hasMatch()) {
QFile file(_minidumpFull);
if (file.open(QIODevice::ReadOnly)) {
QByteArray minidump = file.readAll();
@ -2330,9 +2325,9 @@ void LastCrashedWindow::onCheckingFinished() {
zfuncs.ztell_file = zByteArrayTellFile;
if (zipFile zf = zipOpen2(0, APPEND_STATUS_CREATE, 0, &zfuncs)) {
zip_fileinfo zfi = { 0 };
zip_fileinfo zfi = { { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 };
std::wstring fileName = dmpFile.fileName().toStdWString();
if (zipOpenNewFileInZip(zf, std::string(fileName.begin(), fileName.end()).c_str(), &zfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != S_OK) {
if (zipOpenNewFileInZip(zf, std::string(fileName.begin(), fileName.end()).c_str(), &zfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != ZIP_OK) {
failed = true;
} else if (zipWriteInFileInZip(zf, minidump.constData(), minidump.size()) != 0) {
failed = true;
@ -2358,7 +2353,6 @@ void LastCrashedWindow::onCheckingFinished() {
}
}
}
#endif
_sendReply = _sendManager.post(QNetworkRequest(qsl("https://tdesktop.com/crash.php?act=report")), multipart);
multipart->setParent(_sendReply);

View file

@ -44,6 +44,26 @@
0710CA051B0B9404001B4272 /* moc_stickersetbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 0710CA041B0B9404001B4272 /* moc_stickersetbox.cpp */; };
07129D6A1C16D230002DC495 /* mtpAuthKey.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07129D691C16D230002DC495 /* mtpAuthKey.cpp */; };
07129D6E1C16D245002DC495 /* facades.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07129D6C1C16D245002DC495 /* facades.cpp */; };
071AD8D21C5E8E6D008C9E90 /* zip.c in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8D11C5E8E6D008C9E90 /* zip.c */; };
071AD8D71C5E8F35008C9E90 /* breakpad_nlist_64.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8D31C5E8F35008C9E90 /* breakpad_nlist_64.cc */; };
071AD8D81C5E8F35008C9E90 /* dynamic_images.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8D41C5E8F35008C9E90 /* dynamic_images.cc */; };
071AD8D91C5E8F35008C9E90 /* exception_handler.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8D51C5E8F35008C9E90 /* exception_handler.cc */; };
071AD8DA1C5E8F35008C9E90 /* minidump_generator.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8D61C5E8F35008C9E90 /* minidump_generator.cc */; };
071AD8DE1C5E912C008C9E90 /* crash_generation_client.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8DC1C5E912C008C9E90 /* crash_generation_client.cc */; };
071AD8DF1C5E912C008C9E90 /* crash_generation_server.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8DD1C5E912C008C9E90 /* crash_generation_server.cc */; };
071AD8E21C5E9143008C9E90 /* minidump_file_writer.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8E11C5E9143008C9E90 /* minidump_file_writer.cc */; };
071AD8E61C5E9196008C9E90 /* convert_UTF.c in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8E31C5E9196008C9E90 /* convert_UTF.c */; };
071AD8E71C5E9196008C9E90 /* md5.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8E41C5E9196008C9E90 /* md5.cc */; };
071AD8E81C5E9196008C9E90 /* string_conversion.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8E51C5E9196008C9E90 /* string_conversion.cc */; };
071AD8F01C5E91E3008C9E90 /* bootstrap_compat.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8E91C5E91E3008C9E90 /* bootstrap_compat.cc */; };
071AD8F11C5E91E3008C9E90 /* file_id.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8EA1C5E91E3008C9E90 /* file_id.cc */; };
071AD8F21C5E91E3008C9E90 /* MachIPC.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8EB1C5E91E3008C9E90 /* MachIPC.mm */; };
071AD8F31C5E91E3008C9E90 /* macho_id.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8EC1C5E91E3008C9E90 /* macho_id.cc */; };
071AD8F41C5E91E3008C9E90 /* macho_utilities.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8ED1C5E91E3008C9E90 /* macho_utilities.cc */; };
071AD8F51C5E91E3008C9E90 /* macho_walker.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8EE1C5E91E3008C9E90 /* macho_walker.cc */; };
071AD8F61C5E91E3008C9E90 /* string_utilities.cc in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8EF1C5E91E3008C9E90 /* string_utilities.cc */; };
071AD8F81C5E99D6008C9E90 /* ioapi.c in Compile Sources */ = {isa = PBXBuildFile; fileRef = 071AD8F71C5E99D6008C9E90 /* ioapi.c */; };
071AD90A1C5EA2A5008C9E90 /* Breakpad.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 071AD9091C5EA2A5008C9E90 /* Breakpad.framework */; };
0732E4A9199E262300D50FE7 /* overviewwidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 0732E4A7199E262300D50FE7 /* overviewwidget.cpp */; };
0732E4AC199E268A00D50FE7 /* moc_overviewwidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 0732E4AB199E268A00D50FE7 /* moc_overviewwidget.cpp */; };
074756191A1372C600CA07F7 /* moc_types.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 074756181A1372C600CA07F7 /* moc_types.cpp */; };
@ -276,6 +296,73 @@
07129D691C16D230002DC495 /* mtpAuthKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mtpAuthKey.cpp; path = SourceFiles/mtproto/mtpAuthKey.cpp; sourceTree = SOURCE_ROOT; };
07129D6C1C16D245002DC495 /* facades.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = facades.cpp; path = SourceFiles/facades.cpp; sourceTree = SOURCE_ROOT; };
07129D6D1C16D245002DC495 /* facades.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = facades.h; path = SourceFiles/facades.h; sourceTree = SOURCE_ROOT; };
071AD86B1C5E8536008C9E90 /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crypt.h; path = ThirdParty/minizip/crypt.h; sourceTree = SOURCE_ROOT; };
071AD86C1C5E8536008C9E90 /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ioapi.h; path = ThirdParty/minizip/ioapi.h; sourceTree = SOURCE_ROOT; };
071AD86E1C5E8536008C9E90 /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zip.h; path = ThirdParty/minizip/zip.h; sourceTree = SOURCE_ROOT; };
071AD8751C5E85A0008C9E90 /* exception_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = exception_handler.h; path = ThirdParty/breakpad/client/mac/handler/exception_handler.h; sourceTree = SOURCE_ROOT; };
071AD8791C5E8672008C9E90 /* crash_generation_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crash_generation_client.h; sourceTree = "<group>"; };
071AD87B1C5E8688008C9E90 /* ucontext_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ucontext_compat.h; path = ThirdParty/breakpad/client/mac/handler/ucontext_compat.h; sourceTree = SOURCE_ROOT; };
071AD87F1C5E87AA008C9E90 /* scoped_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = scoped_ptr.h; path = ThirdParty/breakpad/common/scoped_ptr.h; sourceTree = SOURCE_ROOT; };
071AD8811C5E87C2008C9E90 /* MachIPC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MachIPC.h; path = ThirdParty/breakpad/common/mac/MachIPC.h; sourceTree = SOURCE_ROOT; };
071AD8851C5E8853008C9E90 /* bootstrap_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bootstrap_compat.h; path = ThirdParty/breakpad/common/mac/bootstrap_compat.h; sourceTree = SOURCE_ROOT; };
071AD8881C5E8886008C9E90 /* minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_generator.h; path = ThirdParty/breakpad/client/mac/handler/minidump_generator.h; sourceTree = SOURCE_ROOT; };
071AD88B1C5E88AA008C9E90 /* crash_generation_server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crash_generation_server.h; sourceTree = "<group>"; };
071AD88D1C5E88CD008C9E90 /* minidump_file_writer-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "minidump_file_writer-inl.h"; path = "ThirdParty/breakpad/client/minidump_file_writer-inl.h"; sourceTree = SOURCE_ROOT; };
071AD88F1C5E88CD008C9E90 /* minidump_file_writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_file_writer.h; path = ThirdParty/breakpad/client/minidump_file_writer.h; sourceTree = SOURCE_ROOT; };
071AD8911C5E88EA008C9E90 /* client_info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = client_info.h; sourceTree = "<group>"; };
071AD8921C5E8994008C9E90 /* memory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = memory.h; path = ThirdParty/breakpad/common/memory.h; sourceTree = SOURCE_ROOT; };
071AD8951C5E89D1008C9E90 /* breakpad_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = breakpad_types.h; path = ThirdParty/breakpad/google_breakpad/common/breakpad_types.h; sourceTree = SOURCE_ROOT; };
071AD8961C5E89D1008C9E90 /* minidump_cpu_amd64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_cpu_amd64.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_cpu_amd64.h; sourceTree = SOURCE_ROOT; };
071AD8971C5E89D1008C9E90 /* minidump_cpu_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_cpu_arm.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_cpu_arm.h; sourceTree = SOURCE_ROOT; };
071AD8981C5E89D1008C9E90 /* minidump_cpu_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_cpu_arm64.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_cpu_arm64.h; sourceTree = SOURCE_ROOT; };
071AD8991C5E89D1008C9E90 /* minidump_cpu_mips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_cpu_mips.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_cpu_mips.h; sourceTree = SOURCE_ROOT; };
071AD89A1C5E89D1008C9E90 /* minidump_cpu_ppc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_cpu_ppc.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_cpu_ppc.h; sourceTree = SOURCE_ROOT; };
071AD89B1C5E89D1008C9E90 /* minidump_cpu_ppc64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_cpu_ppc64.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_cpu_ppc64.h; sourceTree = SOURCE_ROOT; };
071AD89C1C5E89D1008C9E90 /* minidump_cpu_sparc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_cpu_sparc.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_cpu_sparc.h; sourceTree = SOURCE_ROOT; };
071AD89D1C5E89D1008C9E90 /* minidump_cpu_x86.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_cpu_x86.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_cpu_x86.h; sourceTree = SOURCE_ROOT; };
071AD89E1C5E89D1008C9E90 /* minidump_exception_linux.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_exception_linux.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_exception_linux.h; sourceTree = SOURCE_ROOT; };
071AD89F1C5E89D1008C9E90 /* minidump_exception_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_exception_mac.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_exception_mac.h; sourceTree = SOURCE_ROOT; };
071AD8A01C5E89D1008C9E90 /* minidump_exception_ps3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_exception_ps3.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_exception_ps3.h; sourceTree = SOURCE_ROOT; };
071AD8A11C5E89D1008C9E90 /* minidump_exception_solaris.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_exception_solaris.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_exception_solaris.h; sourceTree = SOURCE_ROOT; };
071AD8A21C5E89D1008C9E90 /* minidump_exception_win32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_exception_win32.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_exception_win32.h; sourceTree = SOURCE_ROOT; };
071AD8A31C5E89D1008C9E90 /* minidump_format.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_format.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_format.h; sourceTree = SOURCE_ROOT; };
071AD8A41C5E89D1008C9E90 /* minidump_size.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = minidump_size.h; path = ThirdParty/breakpad/google_breakpad/common/minidump_size.h; sourceTree = SOURCE_ROOT; };
071AD8A61C5E8A30008C9E90 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ThirdParty/breakpad/common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; };
071AD8A91C5E8A7B008C9E90 /* dynamic_images.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dynamic_images.h; path = ThirdParty/breakpad/client/mac/handler/dynamic_images.h; sourceTree = SOURCE_ROOT; };
071AD8AB1C5E8A99008C9E90 /* mach_vm_compat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mach_vm_compat.h; path = ThirdParty/breakpad/client/mac/handler/mach_vm_compat.h; sourceTree = SOURCE_ROOT; };
071AD8AD1C5E8B07008C9E90 /* breakpad_nlist_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = breakpad_nlist_64.h; path = ThirdParty/breakpad/client/mac/handler/breakpad_nlist_64.h; sourceTree = SOURCE_ROOT; };
071AD8AF1C5E8B16008C9E90 /* byteswap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ThirdParty/breakpad/common/mac/byteswap.h; sourceTree = SOURCE_ROOT; };
071AD8B11C5E8B23008C9E90 /* linux_libc_support.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = linux_libc_support.h; path = ThirdParty/breakpad/common/linux/linux_libc_support.h; sourceTree = SOURCE_ROOT; };
071AD8B31C5E8B43008C9E90 /* string_conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = string_conversion.h; path = ThirdParty/breakpad/common/string_conversion.h; sourceTree = SOURCE_ROOT; };
071AD8B61C5E8B5C008C9E90 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ThirdParty/breakpad/common/mac/file_id.h; sourceTree = SOURCE_ROOT; };
071AD8B81C5E8B81008C9E90 /* scoped_task_suspend-inl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "scoped_task_suspend-inl.h"; path = "ThirdParty/breakpad/common/mac/scoped_task_suspend-inl.h"; sourceTree = SOURCE_ROOT; };
071AD8BA1C5E8B9B008C9E90 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ThirdParty/breakpad/common/mac/macho_id.h; sourceTree = SOURCE_ROOT; };
071AD8BD1C5E8BB0008C9E90 /* convert_UTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = convert_UTF.h; path = ThirdParty/breakpad/common/convert_UTF.h; sourceTree = SOURCE_ROOT; };
071AD8BF1C5E8BC8008C9E90 /* using_std_string.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = using_std_string.h; path = ThirdParty/breakpad/common/using_std_string.h; sourceTree = SOURCE_ROOT; };
071AD8C11C5E8BE5008C9E90 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ThirdParty/breakpad/common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; };
071AD8C41C5E8BFD008C9E90 /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = md5.h; path = ThirdParty/breakpad/common/md5.h; sourceTree = SOURCE_ROOT; };
071AD8C71C5E8C14008C9E90 /* string_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = string_utilities.h; path = ThirdParty/breakpad/common/mac/string_utilities.h; sourceTree = SOURCE_ROOT; };
071AD8D11C5E8E6D008C9E90 /* zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zip.c; path = ThirdParty/minizip/zip.c; sourceTree = SOURCE_ROOT; };
071AD8D31C5E8F35008C9E90 /* breakpad_nlist_64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = breakpad_nlist_64.cc; path = ThirdParty/breakpad/client/mac/handler/breakpad_nlist_64.cc; sourceTree = SOURCE_ROOT; };
071AD8D41C5E8F35008C9E90 /* dynamic_images.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dynamic_images.cc; path = ThirdParty/breakpad/client/mac/handler/dynamic_images.cc; sourceTree = SOURCE_ROOT; };
071AD8D51C5E8F35008C9E90 /* exception_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exception_handler.cc; path = ThirdParty/breakpad/client/mac/handler/exception_handler.cc; sourceTree = SOURCE_ROOT; };
071AD8D61C5E8F35008C9E90 /* minidump_generator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_generator.cc; path = ThirdParty/breakpad/client/mac/handler/minidump_generator.cc; sourceTree = SOURCE_ROOT; };
071AD8DC1C5E912C008C9E90 /* crash_generation_client.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crash_generation_client.cc; sourceTree = "<group>"; };
071AD8DD1C5E912C008C9E90 /* crash_generation_server.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crash_generation_server.cc; sourceTree = "<group>"; };
071AD8E11C5E9143008C9E90 /* minidump_file_writer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_file_writer.cc; path = ThirdParty/breakpad/client/minidump_file_writer.cc; sourceTree = SOURCE_ROOT; };
071AD8E31C5E9196008C9E90 /* convert_UTF.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = convert_UTF.c; path = ThirdParty/breakpad/common/convert_UTF.c; sourceTree = SOURCE_ROOT; };
071AD8E41C5E9196008C9E90 /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = md5.cc; path = ThirdParty/breakpad/common/md5.cc; sourceTree = SOURCE_ROOT; };
071AD8E51C5E9196008C9E90 /* string_conversion.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_conversion.cc; path = ThirdParty/breakpad/common/string_conversion.cc; sourceTree = SOURCE_ROOT; };
071AD8E91C5E91E3008C9E90 /* bootstrap_compat.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bootstrap_compat.cc; path = ThirdParty/breakpad/common/mac/bootstrap_compat.cc; sourceTree = SOURCE_ROOT; };
071AD8EA1C5E91E3008C9E90 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ThirdParty/breakpad/common/mac/file_id.cc; sourceTree = SOURCE_ROOT; };
071AD8EB1C5E91E3008C9E90 /* MachIPC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MachIPC.mm; path = ThirdParty/breakpad/common/mac/MachIPC.mm; sourceTree = SOURCE_ROOT; };
071AD8EC1C5E91E3008C9E90 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ThirdParty/breakpad/common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; };
071AD8ED1C5E91E3008C9E90 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ThirdParty/breakpad/common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; };
071AD8EE1C5E91E3008C9E90 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ThirdParty/breakpad/common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; };
071AD8EF1C5E91E3008C9E90 /* string_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_utilities.cc; path = ThirdParty/breakpad/common/mac/string_utilities.cc; sourceTree = SOURCE_ROOT; };
071AD8F71C5E99D6008C9E90 /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ioapi.c; path = ThirdParty/minizip/ioapi.c; sourceTree = SOURCE_ROOT; };
071AD9091C5EA2A5008C9E90 /* Breakpad.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Breakpad.framework; path = Users/antanubis/TBuild/Libraries/breakpad/Breakpad.framework; sourceTree = "<group>"; };
071AD90B1C5EA37D008C9E90 /* Breakpad.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Breakpad.framework; path = "Users/antanubis/Library/Developer/Xcode/DerivedData/Breakpad-ffxagkgqghkohhawycvgjexmnjhs/Build/Products/Debug/Breakpad.framework"; sourceTree = "<group>"; };
072E117A1A56EB9400A87ACC /* lang_pt_BR.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = lang_pt_BR.strings; path = SourceFiles/langs/lang_pt_BR.strings; sourceTree = SOURCE_ROOT; };
0732E4A7199E262300D50FE7 /* overviewwidget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = overviewwidget.cpp; path = SourceFiles/overviewwidget.cpp; sourceTree = SOURCE_ROOT; };
0732E4A8199E262300D50FE7 /* overviewwidget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = overviewwidget.h; path = SourceFiles/overviewwidget.h; sourceTree = SOURCE_ROOT; };
@ -700,6 +787,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
071AD90A1C5EA2A5008C9E90 /* Breakpad.framework in Link Binary With Libraries */,
0752F8751C2C89F40026D0BC /* VideoToolbox.framework in Link Binary With Libraries */,
0752F8731C2C89220026D0BC /* VideoDecodeAcceleration.framework in Link Binary With Libraries */,
07CAACD81AEA64F00058E508 /* AudioUnit.framework in Link Binary With Libraries */,
@ -755,6 +843,167 @@
name = Products;
sourceTree = "<group>";
};
071AD8691C5E8504008C9E90 /* ThirdParty */ = {
isa = PBXGroup;
children = (
071AD8701C5E8546008C9E90 /* breakpad */,
071AD86A1C5E8522008C9E90 /* minizip */,
);
name = ThirdParty;
sourceTree = "<group>";
};
071AD86A1C5E8522008C9E90 /* minizip */ = {
isa = PBXGroup;
children = (
071AD86B1C5E8536008C9E90 /* crypt.h */,
071AD86C1C5E8536008C9E90 /* ioapi.h */,
071AD8F71C5E99D6008C9E90 /* ioapi.c */,
071AD86E1C5E8536008C9E90 /* zip.h */,
071AD8D11C5E8E6D008C9E90 /* zip.c */,
);
name = minizip;
sourceTree = "<group>";
};
071AD8701C5E8546008C9E90 /* breakpad */ = {
isa = PBXGroup;
children = (
071AD8931C5E89BE008C9E90 /* google_breakpad */,
071AD87E1C5E8792008C9E90 /* common */,
071AD8711C5E8569008C9E90 /* client */,
);
name = breakpad;
sourceTree = "<group>";
};
071AD8711C5E8569008C9E90 /* client */ = {
isa = PBXGroup;
children = (
071AD88D1C5E88CD008C9E90 /* minidump_file_writer-inl.h */,
071AD88F1C5E88CD008C9E90 /* minidump_file_writer.h */,
071AD8E11C5E9143008C9E90 /* minidump_file_writer.cc */,
071AD8721C5E8575008C9E90 /* mac */,
);
name = client;
sourceTree = "<group>";
};
071AD8721C5E8575008C9E90 /* mac */ = {
isa = PBXGroup;
children = (
071AD8771C5E8672008C9E90 /* crash_generation */,
071AD8731C5E8579008C9E90 /* handler */,
);
name = mac;
sourceTree = "<group>";
};
071AD8731C5E8579008C9E90 /* handler */ = {
isa = PBXGroup;
children = (
071AD8D31C5E8F35008C9E90 /* breakpad_nlist_64.cc */,
071AD8AD1C5E8B07008C9E90 /* breakpad_nlist_64.h */,
071AD8D41C5E8F35008C9E90 /* dynamic_images.cc */,
071AD8A91C5E8A7B008C9E90 /* dynamic_images.h */,
071AD8751C5E85A0008C9E90 /* exception_handler.h */,
071AD8D51C5E8F35008C9E90 /* exception_handler.cc */,
071AD8AB1C5E8A99008C9E90 /* mach_vm_compat.h */,
071AD8881C5E8886008C9E90 /* minidump_generator.h */,
071AD8D61C5E8F35008C9E90 /* minidump_generator.cc */,
071AD87B1C5E8688008C9E90 /* ucontext_compat.h */,
);
name = handler;
sourceTree = "<group>";
};
071AD8771C5E8672008C9E90 /* crash_generation */ = {
isa = PBXGroup;
children = (
071AD8911C5E88EA008C9E90 /* client_info.h */,
071AD8791C5E8672008C9E90 /* crash_generation_client.h */,
071AD8DC1C5E912C008C9E90 /* crash_generation_client.cc */,
071AD88B1C5E88AA008C9E90 /* crash_generation_server.h */,
071AD8DD1C5E912C008C9E90 /* crash_generation_server.cc */,
);
name = crash_generation;
path = ThirdParty/breakpad/client/mac/crash_generation;
sourceTree = SOURCE_ROOT;
};
071AD87E1C5E8792008C9E90 /* common */ = {
isa = PBXGroup;
children = (
071AD8B01C5E8B1B008C9E90 /* linux */,
071AD8801C5E87B5008C9E90 /* mac */,
071AD8BD1C5E8BB0008C9E90 /* convert_UTF.h */,
071AD8E31C5E9196008C9E90 /* convert_UTF.c */,
071AD8C41C5E8BFD008C9E90 /* md5.h */,
071AD8E41C5E9196008C9E90 /* md5.cc */,
071AD8921C5E8994008C9E90 /* memory.h */,
071AD87F1C5E87AA008C9E90 /* scoped_ptr.h */,
071AD8B31C5E8B43008C9E90 /* string_conversion.h */,
071AD8E51C5E9196008C9E90 /* string_conversion.cc */,
071AD8BF1C5E8BC8008C9E90 /* using_std_string.h */,
);
name = common;
sourceTree = "<group>";
};
071AD8801C5E87B5008C9E90 /* mac */ = {
isa = PBXGroup;
children = (
071AD8851C5E8853008C9E90 /* bootstrap_compat.h */,
071AD8E91C5E91E3008C9E90 /* bootstrap_compat.cc */,
071AD8AF1C5E8B16008C9E90 /* byteswap.h */,
071AD8B61C5E8B5C008C9E90 /* file_id.h */,
071AD8EA1C5E91E3008C9E90 /* file_id.cc */,
071AD8811C5E87C2008C9E90 /* MachIPC.h */,
071AD8EB1C5E91E3008C9E90 /* MachIPC.mm */,
071AD8BA1C5E8B9B008C9E90 /* macho_id.h */,
071AD8EC1C5E91E3008C9E90 /* macho_id.cc */,
071AD8A61C5E8A30008C9E90 /* macho_utilities.h */,
071AD8ED1C5E91E3008C9E90 /* macho_utilities.cc */,
071AD8C11C5E8BE5008C9E90 /* macho_walker.h */,
071AD8EE1C5E91E3008C9E90 /* macho_walker.cc */,
071AD8B81C5E8B81008C9E90 /* scoped_task_suspend-inl.h */,
071AD8C71C5E8C14008C9E90 /* string_utilities.h */,
071AD8EF1C5E91E3008C9E90 /* string_utilities.cc */,
);
name = mac;
sourceTree = "<group>";
};
071AD8931C5E89BE008C9E90 /* google_breakpad */ = {
isa = PBXGroup;
children = (
071AD8941C5E89C4008C9E90 /* common */,
);
name = google_breakpad;
sourceTree = "<group>";
};
071AD8941C5E89C4008C9E90 /* common */ = {
isa = PBXGroup;
children = (
071AD8951C5E89D1008C9E90 /* breakpad_types.h */,
071AD8961C5E89D1008C9E90 /* minidump_cpu_amd64.h */,
071AD8971C5E89D1008C9E90 /* minidump_cpu_arm.h */,
071AD8981C5E89D1008C9E90 /* minidump_cpu_arm64.h */,
071AD8991C5E89D1008C9E90 /* minidump_cpu_mips.h */,
071AD89A1C5E89D1008C9E90 /* minidump_cpu_ppc.h */,
071AD89B1C5E89D1008C9E90 /* minidump_cpu_ppc64.h */,
071AD89C1C5E89D1008C9E90 /* minidump_cpu_sparc.h */,
071AD89D1C5E89D1008C9E90 /* minidump_cpu_x86.h */,
071AD89E1C5E89D1008C9E90 /* minidump_exception_linux.h */,
071AD89F1C5E89D1008C9E90 /* minidump_exception_mac.h */,
071AD8A01C5E89D1008C9E90 /* minidump_exception_ps3.h */,
071AD8A11C5E89D1008C9E90 /* minidump_exception_solaris.h */,
071AD8A21C5E89D1008C9E90 /* minidump_exception_win32.h */,
071AD8A31C5E89D1008C9E90 /* minidump_format.h */,
071AD8A41C5E89D1008C9E90 /* minidump_size.h */,
);
name = common;
sourceTree = "<group>";
};
071AD8B01C5E8B1B008C9E90 /* linux */ = {
isa = PBXGroup;
children = (
071AD8B11C5E8B23008C9E90 /* linux_libc_support.h */,
);
name = linux;
sourceTree = "<group>";
};
074968CB1A44D0B800394F46 /* langs */ = {
isa = PBXGroup;
children = (
@ -1222,6 +1471,8 @@
AF39DD055C3EF8226FBE929D /* Frameworks */ = {
isa = PBXGroup;
children = (
071AD90B1C5EA37D008C9E90 /* Breakpad.framework */,
071AD9091C5EA2A5008C9E90 /* Breakpad.framework */,
0752F8741C2C89F40026D0BC /* VideoToolbox.framework */,
0752F8721C2C89220026D0BC /* VideoDecodeAcceleration.framework */,
07CAACD71AEA64F00058E508 /* AudioUnit.framework */,
@ -1291,6 +1542,7 @@
07084684195445A600B5AE3A /* Updater.xcodeproj */,
2EB56BE3C2D93CDAB0C52E67 /* Sources */,
25B08E2869634E9BCBA333A2 /* Generated Sources */,
071AD8691C5E8504008C9E90 /* ThirdParty */,
74B182DB50CB5611B5C1C297 /* Supporting Files */,
AF39DD055C3EF8226FBE929D /* Frameworks */,
FE0A091FDBFB3E9C31B7A1BD /* Products */,
@ -1522,6 +1774,7 @@
0732E4A9199E262300D50FE7 /* overviewwidget.cpp in Compile Sources */,
1DF53374E3B6A31661548D08 /* historywidget.cpp in Compile Sources */,
078A2FCD1A811CA600CCC7A0 /* backgroundbox.cpp in Compile Sources */,
071AD8D81C5E8F35008C9E90 /* dynamic_images.cc in Compile Sources */,
37A3C6C782A0E4BC7B09536B /* langloaderplain.cpp in Compile Sources */,
19A66ECD6EE2F8356F27D32D /* layerwidget.cpp in Compile Sources */,
89ADB41E48A3B5E24ABB626C /* profilewidget.cpp in Compile Sources */,
@ -1535,23 +1788,28 @@
4078D5D614EB3ECF7F1848C7 /* types.cpp in Compile Sources */,
68FFEB7CA30BF0149161B809 /* window.cpp in Compile Sources */,
0CB7DE9A54CC9BF86FB7B5CA /* mtp.cpp in Compile Sources */,
071AD8E71C5E9196008C9E90 /* md5.cc in Compile Sources */,
DF259E9677CC63AF8754032B /* mtpConnection.cpp in Compile Sources */,
074FCB9119D36E60004C6EB2 /* moc_popupmenu.cpp in Compile Sources */,
B6346B66B0A2228A91D8A5D9 /* mtpDC.cpp in Compile Sources */,
0755AEDF1AD12A80004D738A /* moc_sessionsbox.cpp in Compile Sources */,
07129D6E1C16D245002DC495 /* facades.cpp in Compile Sources */,
B8CA3E1E11A7E0E7DF9E1CDE /* mtpFileLoader.cpp in Compile Sources */,
071AD8DF1C5E912C008C9E90 /* crash_generation_server.cc in Compile Sources */,
0755AEDD1AD12A80004D738A /* moc_abstractbox.cpp in Compile Sources */,
99F0A9B2AFE5ABDCBFC04510 /* mtpRPC.cpp in Compile Sources */,
A297B1E3CE33CC501DFEDB6E /* mtpSession.cpp in Compile Sources */,
D1FC601FC2F9F3E33F3A14E9 /* animation.cpp in Compile Sources */,
8F65F0D95B1F0CEB859F2FB3 /* boxshadow.cpp in Compile Sources */,
071AD8F41C5E91E3008C9E90 /* macho_utilities.cc in Compile Sources */,
D7EF8F129FCCE9AB3F3F081F /* button.cpp in Compile Sources */,
07DC42A01B5EA15300B6B888 /* numbers.cpp in Compile Sources */,
C03447C9A7D9FF73463B8BB5 /* countryinput.cpp in Compile Sources */,
07BE850F1A2093C9008ACB9F /* localstorage.cpp in Compile Sources */,
CDB0266A8B7CB20A95266BCD /* emoji_config.cpp in Compile Sources */,
071AD8DA1C5E8F35008C9E90 /* minidump_generator.cc in Compile Sources */,
0732E4AC199E268A00D50FE7 /* moc_overviewwidget.cpp in Compile Sources */,
071AD8F01C5E91E3008C9E90 /* bootstrap_compat.cc in Compile Sources */,
7C2B2DEE467A4C4679F1C3C9 /* filedialog.cpp in Compile Sources */,
832C50BFD7D09AF042A51D4F /* flatbutton.cpp in Compile Sources */,
B91D13BCC3963CB9C12D24A4 /* flatcheckbox.cpp in Compile Sources */,
@ -1560,11 +1818,13 @@
03270F718426CFE84729079E /* flattextarea.cpp in Compile Sources */,
E3D7A5CA24541D5DB69D6606 /* images.cpp in Compile Sources */,
ADE99904299B99EB6135E8D9 /* scrollarea.cpp in Compile Sources */,
071AD8F11C5E91E3008C9E90 /* file_id.cc in Compile Sources */,
07129D6A1C16D230002DC495 /* mtpAuthKey.cpp in Compile Sources */,
90085DF442550A0845D5AF37 /* style_core.cpp in Compile Sources */,
074FCB8E19D36851004C6EB2 /* popupmenu.cpp in Compile Sources */,
3AA6E7264581F82856FB37F7 /* text.cpp in Compile Sources */,
FCE6518C548DF7BC82228A4A /* twidget.cpp in Compile Sources */,
071AD8D21C5E8E6D008C9E90 /* zip.c in Compile Sources */,
E9F1CE7F9B18C7C85A50E62D /* style_auto.cpp in Compile Sources */,
EBE29731916DB43BF49FE7A4 /* aboutbox.cpp in Compile Sources */,
4426AF526AAD86D6F73CE36F /* addcontactbox.cpp in Compile Sources */,
@ -1578,6 +1838,7 @@
07DB67511AD07CB800A51329 /* intropwdcheck.cpp in Compile Sources */,
3ABE4F9B2264F770D944106D /* emojibox.cpp in Compile Sources */,
07D703BB19B88FB900C4EED2 /* moc_audio.cpp in Compile Sources */,
071AD8E81C5E9196008C9E90 /* string_conversion.cc in Compile Sources */,
77B998AC22A13EF3DDEE07AC /* photocropbox.cpp in Compile Sources */,
F278C423357CA99797EA30AB /* photosendbox.cpp in Compile Sources */,
E8D95529CED88F18818C9A8B /* intro.cpp in Compile Sources */,
@ -1595,25 +1856,33 @@
352349751855EF76DECA4D60 /* moc_historywidget.cpp in Compile Sources */,
4B0036C794BEA27AF9419768 /* moc_layerwidget.cpp in Compile Sources */,
C14E6C902F6435B3149ECD64 /* moc_profilewidget.cpp in Compile Sources */,
071AD8F81C5E99D6008C9E90 /* ioapi.c in Compile Sources */,
074756191A1372C600CA07F7 /* moc_types.cpp in Compile Sources */,
98E4F55DB5D8E64AB9F08C83 /* moc_localimageloader.cpp in Compile Sources */,
A24E4B5B683764E07683ECEC /* moc_mainwidget.cpp in Compile Sources */,
0710CA051B0B9404001B4272 /* moc_stickersetbox.cpp in Compile Sources */,
07DE92A71AA4925B00A18F6F /* autolockbox.cpp in Compile Sources */,
071AD8F51C5E91E3008C9E90 /* macho_walker.cc in Compile Sources */,
07D8509919F8320900623D75 /* usernamebox.cpp in Compile Sources */,
071AD8F21C5E91E3008C9E90 /* MachIPC.mm in Compile Sources */,
071AD8DE1C5E912C008C9E90 /* crash_generation_client.cc in Compile Sources */,
A469EC9C4C367E0B773A9BB7 /* moc_settingswidget.cpp in Compile Sources */,
FD2FE0C564A7389A2E609EC7 /* moc_sysbuttons.cpp in Compile Sources */,
E97B3CFAB59B49BACFFC5F7C /* moc_title.cpp in Compile Sources */,
07D8510819F8340A00623D75 /* moc_usernamebox.cpp in Compile Sources */,
9A0D5DDC7816FC2538EB6A96 /* moc_window.cpp in Compile Sources */,
071AD8D91C5E8F35008C9E90 /* exception_handler.cc in Compile Sources */,
06EABCC49D2EEE4076322BE7 /* moc_mtp.cpp in Compile Sources */,
0755AEDE1AD12A80004D738A /* moc_intropwdcheck.cpp in Compile Sources */,
07DE92AA1AA4928200A18F6F /* moc_autolockbox.cpp in Compile Sources */,
07B604351B46A20900CA29FE /* moc_playerwidget.cpp in Compile Sources */,
8F6F5D7F82036331E8C6DAE6 /* moc_mtpConnection.cpp in Compile Sources */,
B780F9E21269259B90A1F32A /* moc_mtpDC.cpp in Compile Sources */,
071AD8F31C5E91E3008C9E90 /* macho_id.cc in Compile Sources */,
07080BCF1A43588C00741A51 /* lang_auto.cpp in Compile Sources */,
07539B1D1A1416AF00083EFC /* moc_history.cpp in Compile Sources */,
071AD8E61C5E9196008C9E90 /* convert_UTF.c in Compile Sources */,
071AD8F61C5E91E3008C9E90 /* string_utilities.cc in Compile Sources */,
2A500B102B7CE80F3EB6E13E /* moc_mtpFileLoader.cpp in Compile Sources */,
07A6933519927B160099CB9F /* moc_mediaview.cpp in Compile Sources */,
07A69332199277BA0099CB9F /* mediaview.cpp in Compile Sources */,
@ -1625,6 +1894,7 @@
07DE92A01AA4923300A18F6F /* passcodewidget.cpp in Compile Sources */,
B0B88EFE444C0DE673389418 /* moc_flatbutton.cpp in Compile Sources */,
1BD711B4C358EA7D727BF358 /* moc_flatcheckbox.cpp in Compile Sources */,
071AD8D71C5E8F35008C9E90 /* breakpad_nlist_64.cc in Compile Sources */,
565F748438E6CE0148C54AFE /* moc_flatinput.cpp in Compile Sources */,
8B71D1C7BB9DCEE6511219C2 /* moc_flatlabel.cpp in Compile Sources */,
0710C9FE1B0B9376001B4272 /* stickersetbox.cpp in Compile Sources */,
@ -1638,6 +1908,7 @@
7062978F12EEA525893A5E6F /* moc_aboutbox.cpp in Compile Sources */,
E8B28580819B882A5964561A /* moc_addcontactbox.cpp in Compile Sources */,
07B604321B46A0EC00CA29FE /* playerwidget.cpp in Compile Sources */,
071AD8E21C5E9143008C9E90 /* minidump_file_writer.cc in Compile Sources */,
D6874C00733283846ACA9AB2 /* moc_confirmbox.cpp in Compile Sources */,
ED2557A57C6782721DC494AF /* moc_connectionbox.cpp in Compile Sources */,
5FC914F652D1B16FDA8F0634 /* moc_contactsbox.cpp in Compile Sources */,
@ -1752,7 +2023,7 @@
DYLIB_COMPATIBILITY_VERSION = 0.9;
DYLIB_CURRENT_VERSION = 0.9.19;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
FRAMEWORK_SEARCH_PATHS = ./../../Libraries/breakpad;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_LINK_WITH_DYNAMIC_LIBRARIES = NO;
GCC_NO_COMMON_BLOCKS = YES;
@ -1785,6 +2056,8 @@
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/OpenGL.framework/Versions/A/Headers,
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/AGL.framework/Headers,
"/usr/local/Qt-5.5.1/mkspecs/macx-clang",
./ThirdParty/breakpad,
./ThirdParty/minizip,
);
INFOPLIST_FILE = Telegram.plist;
INSTALL_DIR = ./../Mac/Release/;
@ -1815,8 +2088,8 @@
"-Wno-unused-function",
"-Wno-switch",
"-Wno-comment",
"-I./../../Libraries/openssl-xcode/include",
"-DCUSTOM_API_ID",
"-I./../../Libraries/openssl-xcode/include",
);
OTHER_CPLUSPLUSFLAGS = (
"-pipe",
@ -1835,8 +2108,8 @@
"-Wno-unused-function",
"-Wno-switch",
"-Wno-comment",
"-I./../../Libraries/openssl-xcode/include",
"-DCUSTOM_API_ID",
"-I./../../Libraries/openssl-xcode/include",
);
OTHER_LDFLAGS = (
"-headerpad_max_install_names",
@ -1846,7 +2119,7 @@
"-L/usr/local/Qt-5.5.1/plugins/platforms",
"-lcups",
"-L/usr/local/Qt-5.5.1/plugins/imageformats",
"-lz",
/usr/local/lib/libz.a,
"-lm",
/usr/local/lib/libopenal.a,
/usr/local/lib/libopus.a,
@ -1859,6 +2132,7 @@
/usr/local/lib/libavutil.a,
/usr/local/lib/libiconv.a,
"../../Libraries/openssl-xcode/libcrypto.a",
"-g",
);
PRODUCT_NAME = Telegram;
QT_LIBRARY_SUFFIX = "";
@ -1886,7 +2160,7 @@
DYLIB_CURRENT_VERSION = 0.9.19;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = "";
FRAMEWORK_SEARCH_PATHS = ./../../Libraries/breakpad;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_LINK_WITH_DYNAMIC_LIBRARIES = NO;
GCC_NO_COMMON_BLOCKS = YES;
@ -1919,6 +2193,8 @@
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/OpenGL.framework/Versions/A/Headers,
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/AGL.framework/Headers,
"/usr/local/Qt-5.5.1/mkspecs/macx-clang",
./ThirdParty/breakpad,
./ThirdParty/minizip,
);
INFOPLIST_FILE = Telegram.plist;
INSTALL_DIR = ./../Mac/Debug/;
@ -1981,7 +2257,7 @@
"-L/usr/local/Qt-5.5.1/plugins/platforms",
"-lcups",
"-L/usr/local/Qt-5.5.1/plugins/imageformats",
"-lz",
/usr/local/lib/libz.a,
"-lm",
/usr/local/lib/libopenal.a,
/usr/local/lib/libopus.a,
@ -1994,6 +2270,7 @@
/usr/local/lib/libavutil.a,
/usr/local/lib/libiconv.a,
"../../Libraries/openssl-xcode/libcrypto.a",
"-g",
);
PRODUCT_NAME = Telegram;
QT_LIBRARY_SUFFIX = _debug;

View file

@ -0,0 +1,47 @@
// 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_MAC_CRASH_GENERATION_CLIENT_INFO_H_
#define CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_
namespace google_breakpad {
class ClientInfo {
public:
explicit ClientInfo(pid_t pid) : pid_(pid) {}
pid_t pid() const { return pid_; }
private:
pid_t pid_;
};
} // namespace google_breakpad
#endif // CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_

View file

@ -0,0 +1,72 @@
// 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.
#include "client/mac/crash_generation/crash_generation_client.h"
#include "client/mac/crash_generation/crash_generation_server.h"
#include "common/mac/MachIPC.h"
namespace google_breakpad {
bool CrashGenerationClient::RequestDumpForException(
int exception_type,
int exception_code,
int exception_subcode,
mach_port_t crashing_thread) {
// The server will send a message to this port indicating that it
// has finished its work.
ReceivePort acknowledge_port;
MachSendMessage message(kDumpRequestMessage);
message.AddDescriptor(mach_task_self()); // this task
message.AddDescriptor(crashing_thread); // crashing thread
message.AddDescriptor(mach_thread_self()); // handler thread
message.AddDescriptor(acknowledge_port.GetPort()); // message receive port
ExceptionInfo info;
info.exception_type = exception_type;
info.exception_code = exception_code;
info.exception_subcode = exception_subcode;
message.SetData(&info, sizeof(info));
const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
kern_return_t result = sender_.SendMessage(message, kSendTimeoutMs);
if (result != KERN_SUCCESS)
return false;
// Give the server slightly longer to reply since it has to
// inspect this task and write the minidump.
const mach_msg_timeout_t kReceiveTimeoutMs = 5 * 1000;
MachReceiveMessage acknowledge_message;
result = acknowledge_port.WaitForMessage(&acknowledge_message,
kReceiveTimeoutMs);
return result == KERN_SUCCESS;
}
} // namespace google_breakpad

View file

@ -0,0 +1,65 @@
// 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 GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#define GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#include "common/mac/MachIPC.h"
namespace google_breakpad {
class CrashGenerationClient {
public:
explicit CrashGenerationClient(const char* mach_port_name)
: sender_(mach_port_name) {
}
// Request the crash server to generate a dump.
//
// Return true if the dump was successful; false otherwise.
bool RequestDumpForException(int exception_type,
int exception_code,
int exception_subcode,
mach_port_t crashing_thread);
bool RequestDump() {
return RequestDumpForException(0, 0, 0, MACH_PORT_NULL);
}
private:
MachPortSender sender_;
// Prevent copy construction and assignment.
CrashGenerationClient(const CrashGenerationClient&);
CrashGenerationClient& operator=(const CrashGenerationClient&);
};
} // namespace google_breakpad
#endif // GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_

View file

@ -0,0 +1,166 @@
// 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.
#include "client/mac/crash_generation/crash_generation_server.h"
#include <pthread.h>
#include "client/mac/crash_generation/client_info.h"
#include "client/mac/handler/minidump_generator.h"
#include "common/mac/scoped_task_suspend-inl.h"
namespace google_breakpad {
CrashGenerationServer::CrashGenerationServer(
const char *mach_port_name,
FilterCallback filter,
void *filter_context,
OnClientDumpRequestCallback dump_callback,
void *dump_context,
OnClientExitingCallback exit_callback,
void *exit_context,
bool generate_dumps,
const std::string &dump_path)
: filter_(filter),
filter_context_(filter_context),
dump_callback_(dump_callback),
dump_context_(dump_context),
exit_callback_(exit_callback),
exit_context_(exit_context),
generate_dumps_(generate_dumps),
dump_dir_(dump_path.empty() ? "/tmp" : dump_path),
started_(false),
receive_port_(mach_port_name),
mach_port_name_(mach_port_name) {
}
CrashGenerationServer::~CrashGenerationServer() {
if (started_)
Stop();
}
bool CrashGenerationServer::Start() {
int thread_create_result = pthread_create(&server_thread_, NULL,
&WaitForMessages, this);
started_ = thread_create_result == 0;
return started_;
}
bool CrashGenerationServer::Stop() {
if (!started_)
return false;
// Send a quit message to the background thread, and then join it.
MachPortSender sender(mach_port_name_.c_str());
MachSendMessage quit_message(kQuitMessage);
const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
kern_return_t result = sender.SendMessage(quit_message, kSendTimeoutMs);
if (result == KERN_SUCCESS) {
int thread_join_result = pthread_join(server_thread_, NULL);
started_ = thread_join_result != 0;
}
return !started_;
}
// static
void *CrashGenerationServer::WaitForMessages(void *server) {
CrashGenerationServer *self =
reinterpret_cast<CrashGenerationServer*>(server);
while (self->WaitForOneMessage()) {}
return NULL;
}
bool CrashGenerationServer::WaitForOneMessage() {
MachReceiveMessage message;
kern_return_t result = receive_port_.WaitForMessage(&message,
MACH_MSG_TIMEOUT_NONE);
if (result == KERN_SUCCESS) {
switch (message.GetMessageID()) {
case kDumpRequestMessage: {
ExceptionInfo &info = (ExceptionInfo &)*message.GetData();
mach_port_t remote_task = message.GetTranslatedPort(0);
mach_port_t crashing_thread = message.GetTranslatedPort(1);
mach_port_t handler_thread = message.GetTranslatedPort(2);
mach_port_t ack_port = message.GetTranslatedPort(3);
pid_t remote_pid = -1;
pid_for_task(remote_task, &remote_pid);
ClientInfo client(remote_pid);
bool result;
std::string dump_path;
if (generate_dumps_ && (!filter_ || filter_(filter_context_))) {
ScopedTaskSuspend suspend(remote_task);
MinidumpGenerator generator(remote_task, handler_thread);
dump_path = generator.UniqueNameInDirectory(dump_dir_, NULL);
if (info.exception_type && info.exception_code) {
generator.SetExceptionInformation(info.exception_type,
info.exception_code,
info.exception_subcode,
crashing_thread);
}
result = generator.Write(dump_path.c_str());
} else {
result = true;
}
if (result && dump_callback_) {
dump_callback_(dump_context_, client, dump_path);
}
// TODO(ted): support a way for the client to send additional data,
// perhaps with a callback so users of the server can read the data
// themselves?
if (ack_port != MACH_PORT_DEAD && ack_port != MACH_PORT_NULL) {
MachPortSender sender(ack_port);
MachSendMessage ack_message(kAcknowledgementMessage);
const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
sender.SendMessage(ack_message, kSendTimeoutMs);
}
if (exit_callback_) {
exit_callback_(exit_context_, client);
}
break;
}
case kQuitMessage:
return false;
}
} else { // result != KERN_SUCCESS
return false;
}
return true;
}
} // namespace google_breakpad

View file

@ -0,0 +1,150 @@
// 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 GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
#define GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
#include <stdint.h>
#include <string>
#include "common/mac/MachIPC.h"
namespace google_breakpad {
class ClientInfo;
// Messages the server can read via its mach port
enum {
kDumpRequestMessage = 1,
kAcknowledgementMessage = 2,
kQuitMessage = 3
};
// Exception details sent by the client when requesting a dump.
struct ExceptionInfo {
int32_t exception_type;
int32_t exception_code;
int32_t exception_subcode;
};
class CrashGenerationServer {
public:
// WARNING: callbacks may be invoked on a different thread
// than that which creates the CrashGenerationServer. They must
// be thread safe.
typedef void (*OnClientDumpRequestCallback)(void *context,
const ClientInfo &client_info,
const std::string &file_path);
typedef void (*OnClientExitingCallback)(void *context,
const ClientInfo &client_info);
// If a FilterCallback returns false, the dump will not be written.
typedef bool (*FilterCallback)(void *context);
// Create an instance with the given parameters.
//
// mach_port_name: Named server port to listen on.
// filter: Callback for a client to cancel writing a dump.
// filter_context: Context for the filter callback.
// dump_callback: Callback for a client crash dump request.
// dump_context: Context for client crash dump request callback.
// exit_callback: Callback for client process exit.
// exit_context: Context for client exit callback.
// generate_dumps: Whether to automatically generate dumps.
// Client code of this class might want to generate dumps explicitly
// in the crash dump request callback. In that case, false can be
// passed for this parameter.
// dump_path: Path for generating dumps; required only if true is
// passed for generateDumps parameter; NULL can be passed otherwise.
CrashGenerationServer(const char *mach_port_name,
FilterCallback filter,
void *filter_context,
OnClientDumpRequestCallback dump_callback,
void *dump_context,
OnClientExitingCallback exit_callback,
void *exit_context,
bool generate_dumps,
const std::string &dump_path);
~CrashGenerationServer();
// Perform initialization steps needed to start listening to clients.
//
// Return true if initialization is successful; false otherwise.
bool Start();
// Stop the server.
bool Stop();
private:
// Return a unique filename at which a minidump can be written.
bool MakeMinidumpFilename(std::string &outFilename);
// Loop reading client messages and responding to them until
// a quit message is received.
static void *WaitForMessages(void *server);
// Wait for a single client message and respond to it. Returns false
// if a quit message was received or if an error occurred.
bool WaitForOneMessage();
FilterCallback filter_;
void *filter_context_;
OnClientDumpRequestCallback dump_callback_;
void *dump_context_;
OnClientExitingCallback exit_callback_;
void *exit_context_;
bool generate_dumps_;
std::string dump_dir_;
bool started_;
// The mach port that receives requests to dump from child processes.
ReceivePort receive_port_;
// The name of the mach port. Stored so the Stop method can message
// the background thread to shut it down.
std::string mach_port_name_;
// The thread that waits on the receive port.
pthread_t server_thread_;
// Disable copy constructor and operator=.
CrashGenerationServer(const CrashGenerationServer&);
CrashGenerationServer& operator=(const CrashGenerationServer&);
};
} // namespace google_breakpad
#endif // GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_

View file

@ -0,0 +1,402 @@
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 file was copied from libc/gen/nlist.c from Darwin's source code
* The version of nlist used as a base is from 10.5.2, libc-498
* http://www.opensource.apple.com/darwinsource/10.5.2/Libc-498/gen/nlist.c
*
* The full tarball is at:
* http://www.opensource.apple.com/darwinsource/tarballs/apsl/Libc-498.tar.gz
*
* I've modified it to be compatible with 64-bit images.
*/
#include "breakpad_nlist_64.h"
#include <CoreFoundation/CoreFoundation.h>
#include <fcntl.h>
#include <mach-o/nlist.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach/mach.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <TargetConditionals.h>
#include <unistd.h>
/* Stuff lifted from <a.out.h> and <sys/exec.h> since they are gone */
/*
* Header prepended to each a.out file.
*/
struct exec {
unsigned short a_machtype; /* machine type */
unsigned short a_magic; /* magic number */
unsigned long a_text; /* size of text segment */
unsigned long a_data; /* size of initialized data */
unsigned long a_bss; /* size of uninitialized data */
unsigned long a_syms; /* size of symbol table */
unsigned long a_entry; /* entry point */
unsigned long a_trsize; /* size of text relocation */
unsigned long a_drsize; /* size of data relocation */
};
#define OMAGIC 0407 /* old impure format */
#define NMAGIC 0410 /* read-only text */
#define ZMAGIC 0413 /* demand load format */
#define N_BADMAG(x) \
(((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC)
#define N_TXTOFF(x) \
((x).a_magic==ZMAGIC ? 0 : sizeof (struct exec))
#define N_SYMOFF(x) \
(N_TXTOFF(x) + (x).a_text+(x).a_data + (x).a_trsize+(x).a_drsize)
// Traits structs for specializing function templates to handle
// 32-bit/64-bit Mach-O files.
template<typename T>
struct MachBits {};
typedef struct nlist nlist32;
typedef struct nlist_64 nlist64;
template<>
struct MachBits<nlist32> {
typedef mach_header mach_header_type;
typedef uint32_t word_type;
static const uint32_t magic = MH_MAGIC;
};
template<>
struct MachBits<nlist64> {
typedef mach_header_64 mach_header_type;
typedef uint64_t word_type;
static const uint32_t magic = MH_MAGIC_64;
};
template<typename nlist_type>
int
__breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
cpu_type_t cpu_type);
/*
* nlist - retreive attributes from name list (string table version)
*/
template <typename nlist_type>
int breakpad_nlist_common(const char *name,
nlist_type *list,
const char **symbolNames,
cpu_type_t cpu_type) {
int fd = open(name, O_RDONLY, 0);
if (fd < 0)
return -1;
int n = __breakpad_fdnlist(fd, list, symbolNames, cpu_type);
close(fd);
return n;
}
int breakpad_nlist(const char *name,
struct nlist *list,
const char **symbolNames,
cpu_type_t cpu_type) {
return breakpad_nlist_common(name, list, symbolNames, cpu_type);
}
int breakpad_nlist(const char *name,
struct nlist_64 *list,
const char **symbolNames,
cpu_type_t cpu_type) {
return breakpad_nlist_common(name, list, symbolNames, cpu_type);
}
/* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */
template<typename nlist_type>
int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
cpu_type_t cpu_type) {
typedef typename MachBits<nlist_type>::mach_header_type mach_header_type;
typedef typename MachBits<nlist_type>::word_type word_type;
const uint32_t magic = MachBits<nlist_type>::magic;
int maxlen = 500;
int nreq = 0;
for (nlist_type* q = list;
symbolNames[q-list] && symbolNames[q-list][0];
q++, nreq++) {
q->n_type = 0;
q->n_value = 0;
q->n_desc = 0;
q->n_sect = 0;
q->n_un.n_strx = 0;
}
struct exec buf;
if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) ||
(N_BADMAG(buf) && *((uint32_t *)&buf) != magic &&
CFSwapInt32BigToHost(*((uint32_t *)&buf)) != FAT_MAGIC &&
/* The following is the big-endian ppc64 check */
(*((uint32_t*)&buf)) != FAT_MAGIC)) {
return -1;
}
/* Deal with fat file if necessary */
unsigned arch_offset = 0;
if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC ||
/* The following is the big-endian ppc64 check */
*((unsigned int *)&buf) == FAT_MAGIC) {
/* Read in the fat header */
struct fat_header fh;
if (lseek(fd, 0, SEEK_SET) == -1) {
return -1;
}
if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) {
return -1;
}
/* Convert fat_narchs to host byte order */
fh.nfat_arch = CFSwapInt32BigToHost(fh.nfat_arch);
/* Read in the fat archs */
struct fat_arch *fat_archs =
(struct fat_arch *)malloc(fh.nfat_arch * sizeof(struct fat_arch));
if (fat_archs == NULL) {
return -1;
}
if (read(fd, (char *)fat_archs,
sizeof(struct fat_arch) * fh.nfat_arch) !=
(ssize_t)(sizeof(struct fat_arch) * fh.nfat_arch)) {
free(fat_archs);
return -1;
}
/*
* Convert archs to host byte ordering (a constraint of
* cpusubtype_getbestarch()
*/
for (unsigned i = 0; i < fh.nfat_arch; i++) {
fat_archs[i].cputype =
CFSwapInt32BigToHost(fat_archs[i].cputype);
fat_archs[i].cpusubtype =
CFSwapInt32BigToHost(fat_archs[i].cpusubtype);
fat_archs[i].offset =
CFSwapInt32BigToHost(fat_archs[i].offset);
fat_archs[i].size =
CFSwapInt32BigToHost(fat_archs[i].size);
fat_archs[i].align =
CFSwapInt32BigToHost(fat_archs[i].align);
}
struct fat_arch *fap = NULL;
for (unsigned i = 0; i < fh.nfat_arch; i++) {
if (fat_archs[i].cputype == cpu_type) {
fap = &fat_archs[i];
break;
}
}
if (!fap) {
free(fat_archs);
return -1;
}
arch_offset = fap->offset;
free(fat_archs);
/* Read in the beginning of the architecture-specific file */
if (lseek(fd, arch_offset, SEEK_SET) == -1) {
return -1;
}
if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) {
return -1;
}
}
off_t sa; /* symbol address */
off_t ss; /* start of strings */
register_t n;
if (*((unsigned int *)&buf) == magic) {
if (lseek(fd, arch_offset, SEEK_SET) == -1) {
return -1;
}
mach_header_type mh;
if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) {
return -1;
}
struct load_command *load_commands =
(struct load_command *)malloc(mh.sizeofcmds);
if (load_commands == NULL) {
return -1;
}
if (read(fd, (char *)load_commands, mh.sizeofcmds) !=
(ssize_t)mh.sizeofcmds) {
free(load_commands);
return -1;
}
struct symtab_command *stp = NULL;
struct load_command *lcp = load_commands;
// iterate through all load commands, looking for
// LC_SYMTAB load command
for (uint32_t i = 0; i < mh.ncmds; i++) {
if (lcp->cmdsize % sizeof(word_type) != 0 ||
lcp->cmdsize <= 0 ||
(char *)lcp + lcp->cmdsize >
(char *)load_commands + mh.sizeofcmds) {
free(load_commands);
return -1;
}
if (lcp->cmd == LC_SYMTAB) {
if (lcp->cmdsize !=
sizeof(struct symtab_command)) {
free(load_commands);
return -1;
}
stp = (struct symtab_command *)lcp;
break;
}
lcp = (struct load_command *)
((char *)lcp + lcp->cmdsize);
}
if (stp == NULL) {
free(load_commands);
return -1;
}
// sa points to the beginning of the symbol table
sa = stp->symoff + arch_offset;
// ss points to the beginning of the string table
ss = stp->stroff + arch_offset;
// n is the number of bytes in the symbol table
// each symbol table entry is an nlist structure
n = stp->nsyms * sizeof(nlist_type);
free(load_commands);
} else {
sa = N_SYMOFF(buf) + arch_offset;
ss = sa + buf.a_syms + arch_offset;
n = buf.a_syms;
}
if (lseek(fd, sa, SEEK_SET) == -1) {
return -1;
}
// the algorithm here is to read the nlist entries in m-sized
// chunks into q. q is then iterated over. for each entry in q,
// use the string table index(q->n_un.n_strx) to read the symbol
// name, then scan the nlist entries passed in by the user(via p),
// and look for a match
while (n) {
nlist_type space[BUFSIZ/sizeof (nlist_type)];
register_t m = sizeof (space);
if (n < m)
m = n;
if (read(fd, (char *)space, m) != m)
break;
n -= m;
off_t savpos = lseek(fd, 0, SEEK_CUR);
if (savpos == -1) {
return -1;
}
for (nlist_type* q = space; (m -= sizeof(nlist_type)) >= 0; q++) {
char nambuf[BUFSIZ];
if (q->n_un.n_strx == 0 || q->n_type & N_STAB)
continue;
// seek to the location in the binary where the symbol
// name is stored & read it into memory
if (lseek(fd, ss+q->n_un.n_strx, SEEK_SET) == -1) {
return -1;
}
if (read(fd, nambuf, maxlen+1) == -1) {
return -1;
}
const char *s2 = nambuf;
for (nlist_type *p = list;
symbolNames[p-list] && symbolNames[p-list][0];
p++) {
// get the symbol name the user has passed in that
// corresponds to the nlist entry that we're looking at
const char *s1 = symbolNames[p - list];
while (*s1) {
if (*s1++ != *s2++)
goto cont;
}
if (*s2)
goto cont;
p->n_value = q->n_value;
p->n_type = q->n_type;
p->n_desc = q->n_desc;
p->n_sect = q->n_sect;
p->n_un.n_strx = q->n_un.n_strx;
if (--nreq == 0)
return nreq;
break;
cont: ;
}
}
if (lseek(fd, savpos, SEEK_SET) == -1) {
return -1;
}
}
return nreq;
}

View file

@ -0,0 +1,47 @@
// Copyright (c) 2008, 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.
// breakpad_nlist.h
//
// This file is meant to provide a header for clients of the modified
// nlist function implemented to work on 64-bit.
#ifndef CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__
#include <mach/machine.h>
int breakpad_nlist(const char *name,
struct nlist *list,
const char **symbolNames,
cpu_type_t cpu_type);
int breakpad_nlist(const char *name,
struct nlist_64 *list,
const char **symbolNames,
cpu_type_t cpu_type);
#endif /* CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ */

View file

@ -0,0 +1,573 @@
// Copyright (c) 2007, 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/mac/handler/dynamic_images.h"
extern "C" { // needed to compile on Leopard
#include <mach-o/nlist.h>
#include <stdlib.h>
#include <stdio.h>
}
#include <assert.h>
#include <AvailabilityMacros.h>
#include <dlfcn.h>
#include <mach/task_info.h>
#include <sys/sysctl.h>
#include <TargetConditionals.h>
#include <unistd.h>
#include <algorithm>
#include <string>
#include <vector>
#include "breakpad_nlist_64.h"
#if !TARGET_OS_IPHONE
#include <CoreServices/CoreServices.h>
#ifndef MAC_OS_X_VERSION_10_6
#define MAC_OS_X_VERSION_10_6 1060
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
// Fallback declarations for TASK_DYLD_INFO and friends, introduced in
// <mach/task_info.h> in the Mac OS X 10.6 SDK.
#define TASK_DYLD_INFO 17
struct task_dyld_info {
mach_vm_address_t all_image_info_addr;
mach_vm_size_t all_image_info_size;
};
typedef struct task_dyld_info task_dyld_info_data_t;
typedef struct task_dyld_info *task_dyld_info_t;
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
#endif
#endif // !TARGET_OS_IPHONE
namespace google_breakpad {
using std::string;
using std::vector;
//==============================================================================
// Returns the size of the memory region containing |address| and the
// number of bytes from |address| to the end of the region.
// We potentially, will extend the size of the original
// region by the size of the following region if it's contiguous with the
// first in order to handle cases when we're reading strings and they
// straddle two vm regions.
//
static mach_vm_size_t GetMemoryRegionSize(task_port_t target_task,
const uint64_t address,
mach_vm_size_t *size_to_end) {
mach_vm_address_t region_base = (mach_vm_address_t)address;
mach_vm_size_t region_size;
natural_t nesting_level = 0;
vm_region_submap_info_64 submap_info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
// Get information about the vm region containing |address|
vm_region_recurse_info_t region_info;
region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info);
kern_return_t result =
mach_vm_region_recurse(target_task,
&region_base,
&region_size,
&nesting_level,
region_info,
&info_count);
if (result == KERN_SUCCESS) {
// Get distance from |address| to the end of this region
*size_to_end = region_base + region_size -(mach_vm_address_t)address;
// If we want to handle strings as long as 4096 characters we may need
// to check if there's a vm region immediately following the first one.
// If so, we need to extend |*size_to_end| to go all the way to the end
// of the second region.
if (*size_to_end < 4096) {
// Second region starts where the first one ends
mach_vm_address_t region_base2 =
(mach_vm_address_t)(region_base + region_size);
mach_vm_size_t region_size2;
// Get information about the following vm region
result =
mach_vm_region_recurse(target_task,
&region_base2,
&region_size2,
&nesting_level,
region_info,
&info_count);
// Extend region_size to go all the way to the end of the 2nd region
if (result == KERN_SUCCESS
&& region_base2 == region_base + region_size) {
region_size += region_size2;
}
}
*size_to_end = region_base + region_size -(mach_vm_address_t)address;
} else {
region_size = 0;
*size_to_end = 0;
}
return region_size;
}
#define kMaxStringLength 8192
//==============================================================================
// Reads a NULL-terminated string from another task.
//
// Warning! This will not read any strings longer than kMaxStringLength-1
//
static string ReadTaskString(task_port_t target_task,
const uint64_t address) {
// The problem is we don't know how much to read until we know how long
// the string is. And we don't know how long the string is, until we've read
// the memory! So, we'll try to read kMaxStringLength bytes
// (or as many bytes as we can until we reach the end of the vm region).
mach_vm_size_t size_to_end;
GetMemoryRegionSize(target_task, address, &size_to_end);
if (size_to_end > 0) {
mach_vm_size_t size_to_read =
size_to_end > kMaxStringLength ? kMaxStringLength : size_to_end;
vector<uint8_t> bytes;
if (ReadTaskMemory(target_task, address, (size_t)size_to_read, bytes) !=
KERN_SUCCESS)
return string();
return string(reinterpret_cast<const char*>(&bytes[0]));
}
return string();
}
//==============================================================================
// Reads an address range from another task. The bytes read will be returned
// in bytes, which will be resized as necessary.
kern_return_t ReadTaskMemory(task_port_t target_task,
const uint64_t address,
size_t length,
vector<uint8_t> &bytes) {
int systemPageSize = getpagesize();
// use the negative of the page size for the mask to find the page address
mach_vm_address_t page_address = address & (-systemPageSize);
mach_vm_address_t last_page_address =
(address + length + (systemPageSize - 1)) & (-systemPageSize);
mach_vm_size_t page_size = last_page_address - page_address;
uint8_t* local_start;
uint32_t local_length;
kern_return_t r = mach_vm_read(target_task,
page_address,
page_size,
reinterpret_cast<vm_offset_t*>(&local_start),
&local_length);
if (r != KERN_SUCCESS)
return r;
bytes.resize(length);
memcpy(&bytes[0],
&local_start[(mach_vm_address_t)address - page_address],
length);
mach_vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length);
return KERN_SUCCESS;
}
#pragma mark -
//==============================================================================
// Traits structs for specializing function templates to handle
// 32-bit/64-bit Mach-O files.
struct MachO32 {
typedef mach_header mach_header_type;
typedef segment_command mach_segment_command_type;
typedef dyld_image_info32 dyld_image_info;
typedef dyld_all_image_infos32 dyld_all_image_infos;
typedef struct nlist nlist_type;
static const uint32_t magic = MH_MAGIC;
static const uint32_t segment_load_command = LC_SEGMENT;
};
struct MachO64 {
typedef mach_header_64 mach_header_type;
typedef segment_command_64 mach_segment_command_type;
typedef dyld_image_info64 dyld_image_info;
typedef dyld_all_image_infos64 dyld_all_image_infos;
typedef struct nlist_64 nlist_type;
static const uint32_t magic = MH_MAGIC_64;
static const uint32_t segment_load_command = LC_SEGMENT_64;
};
template<typename MachBits>
bool FindTextSection(DynamicImage& image) {
typedef typename MachBits::mach_header_type mach_header_type;
typedef typename MachBits::mach_segment_command_type
mach_segment_command_type;
const mach_header_type* header =
reinterpret_cast<const mach_header_type*>(&image.header_[0]);
if(header->magic != MachBits::magic) {
return false;
}
const struct load_command *cmd =
reinterpret_cast<const struct load_command *>(header + 1);
bool found_text_section = false;
bool found_dylib_id_command = false;
for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) {
if (!found_text_section) {
if (cmd->cmd == MachBits::segment_load_command) {
const mach_segment_command_type *seg =
reinterpret_cast<const mach_segment_command_type *>(cmd);
if (!strcmp(seg->segname, "__TEXT")) {
image.vmaddr_ = static_cast<mach_vm_address_t>(seg->vmaddr);
image.vmsize_ = static_cast<mach_vm_size_t>(seg->vmsize);
image.slide_ = 0;
if (seg->fileoff == 0 && seg->filesize != 0) {
image.slide_ =
(uintptr_t)image.GetLoadAddress() - (uintptr_t)seg->vmaddr;
}
found_text_section = true;
}
}
}
if (!found_dylib_id_command) {
if (cmd->cmd == LC_ID_DYLIB) {
const struct dylib_command *dc =
reinterpret_cast<const struct dylib_command *>(cmd);
image.version_ = dc->dylib.current_version;
found_dylib_id_command = true;
}
}
if (found_dylib_id_command && found_text_section) {
return true;
}
cmd = reinterpret_cast<const struct load_command *>
(reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
}
return false;
}
//==============================================================================
// Initializes vmaddr_, vmsize_, and slide_
void DynamicImage::CalculateMemoryAndVersionInfo() {
// unless we can process the header, ensure that calls to
// IsValid() will return false
vmaddr_ = 0;
vmsize_ = 0;
slide_ = 0;
version_ = 0;
// The function template above does all the real work.
if (Is64Bit())
FindTextSection<MachO64>(*this);
else
FindTextSection<MachO32>(*this);
}
//==============================================================================
// The helper function template abstracts the 32/64-bit differences.
template<typename MachBits>
uint32_t GetFileTypeFromHeader(DynamicImage& image) {
typedef typename MachBits::mach_header_type mach_header_type;
const mach_header_type* header =
reinterpret_cast<const mach_header_type*>(&image.header_[0]);
return header->filetype;
}
uint32_t DynamicImage::GetFileType() {
if (Is64Bit())
return GetFileTypeFromHeader<MachO64>(*this);
return GetFileTypeFromHeader<MachO32>(*this);
}
#pragma mark -
//==============================================================================
// Loads information about dynamically loaded code in the given task.
DynamicImages::DynamicImages(mach_port_t task)
: task_(task),
cpu_type_(DetermineTaskCPUType(task)),
image_list_() {
ReadImageInfoForTask();
}
template<typename MachBits>
static uint64_t LookupSymbol(const char* symbol_name,
const char* filename,
cpu_type_t cpu_type) {
typedef typename MachBits::nlist_type nlist_type;
nlist_type symbol_info[8] = {};
const char *symbolNames[2] = { symbol_name, "\0" };
nlist_type &list = symbol_info[0];
int invalidEntriesCount = breakpad_nlist(filename,
&list,
symbolNames,
cpu_type);
if(invalidEntriesCount != 0) {
return 0;
}
assert(list.n_value);
return list.n_value;
}
#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
static bool HasTaskDyldInfo() {
return true;
}
#else
static SInt32 GetOSVersionInternal() {
SInt32 os_version = 0;
Gestalt(gestaltSystemVersion, &os_version);
return os_version;
}
static SInt32 GetOSVersion() {
static SInt32 os_version = GetOSVersionInternal();
return os_version;
}
static bool HasTaskDyldInfo() {
return GetOSVersion() >= 0x1060;
}
#endif // TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= 10_6
uint64_t DynamicImages::GetDyldAllImageInfosPointer() {
if (HasTaskDyldInfo()) {
task_dyld_info_data_t task_dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(task_, TASK_DYLD_INFO, (task_info_t)&task_dyld_info,
&count) != KERN_SUCCESS) {
return 0;
}
return (uint64_t)task_dyld_info.all_image_info_addr;
} else {
const char *imageSymbolName = "_dyld_all_image_infos";
const char *dyldPath = "/usr/lib/dyld";
if (Is64Bit())
return LookupSymbol<MachO64>(imageSymbolName, dyldPath, cpu_type_);
return LookupSymbol<MachO32>(imageSymbolName, dyldPath, cpu_type_);
}
}
//==============================================================================
// This code was written using dyld_debug.c (from Darwin) as a guide.
template<typename MachBits>
void ReadImageInfo(DynamicImages& images,
uint64_t image_list_address) {
typedef typename MachBits::dyld_image_info dyld_image_info;
typedef typename MachBits::dyld_all_image_infos dyld_all_image_infos;
typedef typename MachBits::mach_header_type mach_header_type;
// Read the structure inside of dyld that contains information about
// loaded images. We're reading from the desired task's address space.
// Here we make the assumption that dyld loaded at the same address in
// the crashed process vs. this one. This is an assumption made in
// "dyld_debug.c" and is said to be nearly always valid.
vector<uint8_t> dyld_all_info_bytes;
if (ReadTaskMemory(images.task_,
image_list_address,
sizeof(dyld_all_image_infos),
dyld_all_info_bytes) != KERN_SUCCESS)
return;
dyld_all_image_infos *dyldInfo =
reinterpret_cast<dyld_all_image_infos*>(&dyld_all_info_bytes[0]);
// number of loaded images
int count = dyldInfo->infoArrayCount;
// Read an array of dyld_image_info structures each containing
// information about a loaded image.
vector<uint8_t> dyld_info_array_bytes;
if (ReadTaskMemory(images.task_,
dyldInfo->infoArray,
count * sizeof(dyld_image_info),
dyld_info_array_bytes) != KERN_SUCCESS)
return;
dyld_image_info *infoArray =
reinterpret_cast<dyld_image_info*>(&dyld_info_array_bytes[0]);
images.image_list_.reserve(count);
for (int i = 0; i < count; ++i) {
dyld_image_info &info = infoArray[i];
// First read just the mach_header from the image in the task.
vector<uint8_t> mach_header_bytes;
if (ReadTaskMemory(images.task_,
info.load_address_,
sizeof(mach_header_type),
mach_header_bytes) != KERN_SUCCESS)
continue; // bail on this dynamic image
mach_header_type *header =
reinterpret_cast<mach_header_type*>(&mach_header_bytes[0]);
// Now determine the total amount necessary to read the header
// plus all of the load commands.
size_t header_size =
sizeof(mach_header_type) + header->sizeofcmds;
if (ReadTaskMemory(images.task_,
info.load_address_,
header_size,
mach_header_bytes) != KERN_SUCCESS)
continue;
// Read the file name from the task's memory space.
string file_path;
if (info.file_path_) {
// Although we're reading kMaxStringLength bytes, it's copied in the
// the DynamicImage constructor below with the correct string length,
// so it's not really wasting memory.
file_path = ReadTaskString(images.task_, info.file_path_);
}
// Create an object representing this image and add it to our list.
DynamicImage *new_image;
new_image = new DynamicImage(&mach_header_bytes[0],
header_size,
info.load_address_,
file_path,
static_cast<uintptr_t>(info.file_mod_date_),
images.task_,
images.cpu_type_);
if (new_image->IsValid()) {
images.image_list_.push_back(DynamicImageRef(new_image));
} else {
delete new_image;
}
}
// sorts based on loading address
sort(images.image_list_.begin(), images.image_list_.end());
// remove duplicates - this happens in certain strange cases
// You can see it in DashboardClient when Google Gadgets plugin
// is installed. Apple's crash reporter log and gdb "info shared"
// both show the same library multiple times at the same address
vector<DynamicImageRef>::iterator it = unique(images.image_list_.begin(),
images.image_list_.end());
images.image_list_.erase(it, images.image_list_.end());
}
void DynamicImages::ReadImageInfoForTask() {
uint64_t imageList = GetDyldAllImageInfosPointer();
if (imageList) {
if (Is64Bit())
ReadImageInfo<MachO64>(*this, imageList);
else
ReadImageInfo<MachO32>(*this, imageList);
}
}
//==============================================================================
DynamicImage *DynamicImages::GetExecutableImage() {
int executable_index = GetExecutableImageIndex();
if (executable_index >= 0) {
return GetImage(executable_index);
}
return NULL;
}
//==============================================================================
// returns -1 if failure to find executable
int DynamicImages::GetExecutableImageIndex() {
int image_count = GetImageCount();
for (int i = 0; i < image_count; ++i) {
DynamicImage *image = GetImage(i);
if (image->GetFileType() == MH_EXECUTE) {
return i;
}
}
return -1;
}
//==============================================================================
// static
cpu_type_t DynamicImages::DetermineTaskCPUType(task_t task) {
if (task == mach_task_self())
return GetNativeCPUType();
int mib[CTL_MAXNAME];
size_t mibLen = CTL_MAXNAME;
int err = sysctlnametomib("sysctl.proc_cputype", mib, &mibLen);
if (err == 0) {
assert(mibLen < CTL_MAXNAME);
pid_for_task(task, &mib[mibLen]);
mibLen += 1;
cpu_type_t cpu_type;
size_t cpuTypeSize = sizeof(cpu_type);
sysctl(mib, static_cast<u_int>(mibLen), &cpu_type, &cpuTypeSize, 0, 0);
return cpu_type;
}
return GetNativeCPUType();
}
} // namespace google_breakpad

View file

@ -0,0 +1,319 @@
// Copyright (c) 2007, 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.
// dynamic_images.h
//
// Implements most of the function of the dyld API, but allowing an
// arbitrary task to be introspected, unlike the dyld API which
// only allows operation on the current task. The current implementation
// is limited to use by 32-bit tasks.
#ifndef CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
#define CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
#include <mach/mach.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <sys/types.h>
#include <string>
#include <vector>
#include "mach_vm_compat.h"
namespace google_breakpad {
using std::string;
using std::vector;
//==============================================================================
// The memory layout of this struct matches the dyld_image_info struct
// defined in "dyld_gdb.h" in the darwin source.
typedef struct dyld_image_info32 {
uint32_t load_address_; // struct mach_header*
uint32_t file_path_; // char*
uint32_t file_mod_date_;
} dyld_image_info32;
typedef struct dyld_image_info64 {
uint64_t load_address_; // struct mach_header*
uint64_t file_path_; // char*
uint64_t file_mod_date_;
} dyld_image_info64;
//==============================================================================
// This is as defined in "dyld_gdb.h" in the darwin source.
// _dyld_all_image_infos (in dyld) is a structure of this type
// which will be used to determine which dynamic code has been loaded.
typedef struct dyld_all_image_infos32 {
uint32_t version; // == 1 in Mac OS X 10.4
uint32_t infoArrayCount;
uint32_t infoArray; // const struct dyld_image_info*
uint32_t notification;
bool processDetachedFromSharedRegion;
} dyld_all_image_infos32;
typedef struct dyld_all_image_infos64 {
uint32_t version; // == 1 in Mac OS X 10.4
uint32_t infoArrayCount;
uint64_t infoArray; // const struct dyld_image_info*
uint64_t notification;
bool processDetachedFromSharedRegion;
} dyld_all_image_infos64;
// some typedefs to isolate 64/32 bit differences
#ifdef __LP64__
typedef mach_header_64 breakpad_mach_header;
typedef segment_command_64 breakpad_mach_segment_command;
#else
typedef mach_header breakpad_mach_header;
typedef segment_command breakpad_mach_segment_command;
#endif
// Helper functions to deal with 32-bit/64-bit Mach-O differences.
class DynamicImage;
template<typename MachBits>
bool FindTextSection(DynamicImage& image);
template<typename MachBits>
uint32_t GetFileTypeFromHeader(DynamicImage& image);
//==============================================================================
// Represents a single dynamically loaded mach-o image
class DynamicImage {
public:
DynamicImage(uint8_t *header, // data is copied
size_t header_size, // includes load commands
uint64_t load_address,
string file_path,
uintptr_t image_mod_date,
mach_port_t task,
cpu_type_t cpu_type)
: header_(header, header + header_size),
header_size_(header_size),
load_address_(load_address),
vmaddr_(0),
vmsize_(0),
slide_(0),
version_(0),
file_path_(file_path),
file_mod_date_(image_mod_date),
task_(task),
cpu_type_(cpu_type) {
CalculateMemoryAndVersionInfo();
}
// Size of mach_header plus load commands
size_t GetHeaderSize() const {return header_.size();}
// Full path to mach-o binary
string GetFilePath() {return file_path_;}
uint64_t GetModDate() const {return file_mod_date_;}
// Actual address where the image was loaded
uint64_t GetLoadAddress() const {return load_address_;}
// Address where the image should be loaded
mach_vm_address_t GetVMAddr() const {return vmaddr_;}
// Difference between GetLoadAddress() and GetVMAddr()
ptrdiff_t GetVMAddrSlide() const {return slide_;}
// Size of the image
mach_vm_size_t GetVMSize() const {return vmsize_;}
// Task owning this loaded image
mach_port_t GetTask() {return task_;}
// CPU type of the task
cpu_type_t GetCPUType() {return cpu_type_;}
// filetype from the Mach-O header.
uint32_t GetFileType();
// Return true if the task is a 64-bit architecture.
bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; }
uint32_t GetVersion() {return version_;}
// For sorting
bool operator<(const DynamicImage &inInfo) {
return GetLoadAddress() < inInfo.GetLoadAddress();
}
// Sanity checking
bool IsValid() {return GetVMSize() != 0;}
private:
DynamicImage(const DynamicImage &);
DynamicImage &operator=(const DynamicImage &);
friend class DynamicImages;
template<typename MachBits>
friend bool FindTextSection(DynamicImage& image);
template<typename MachBits>
friend uint32_t GetFileTypeFromHeader(DynamicImage& image);
// Initializes vmaddr_, vmsize_, and slide_
void CalculateMemoryAndVersionInfo();
const vector<uint8_t> header_; // our local copy of the header
size_t header_size_; // mach_header plus load commands
uint64_t load_address_; // base address image is mapped into
mach_vm_address_t vmaddr_;
mach_vm_size_t vmsize_;
ptrdiff_t slide_;
uint32_t version_; // Dylib version
string file_path_; // path dyld used to load the image
uintptr_t file_mod_date_; // time_t of image file
mach_port_t task_;
cpu_type_t cpu_type_; // CPU type of task_
};
//==============================================================================
// DynamicImageRef is just a simple wrapper for a pointer to
// DynamicImage. The reason we use it instead of a simple typedef is so
// that we can use stl::sort() on a vector of DynamicImageRefs
// and simple class pointers can't implement operator<().
//
class DynamicImageRef {
public:
explicit DynamicImageRef(DynamicImage *inP) : p(inP) {}
// The copy constructor is required by STL
DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {}
bool operator<(const DynamicImageRef &inRef) const {
return (*const_cast<DynamicImageRef*>(this)->p)
< (*const_cast<DynamicImageRef&>(inRef).p);
}
bool operator==(const DynamicImageRef &inInfo) const {
return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() ==
(*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress();
}
// Be just like DynamicImage*
DynamicImage *operator->() {return p;}
operator DynamicImage*() {return p;}
private:
DynamicImage *p;
};
// Helper function to deal with 32-bit/64-bit Mach-O differences.
class DynamicImages;
template<typename MachBits>
void ReadImageInfo(DynamicImages& images, uint64_t image_list_address);
//==============================================================================
// An object of type DynamicImages may be created to allow introspection of
// an arbitrary task's dynamically loaded mach-o binaries. This makes the
// assumption that the current task has send rights to the target task.
class DynamicImages {
public:
explicit DynamicImages(mach_port_t task);
~DynamicImages() {
for (int i = 0; i < GetImageCount(); ++i) {
delete image_list_[i];
}
}
// Returns the number of dynamically loaded mach-o images.
int GetImageCount() const {return static_cast<int>(image_list_.size());}
// Returns an individual image.
DynamicImage *GetImage(int i) {
if (i < (int)image_list_.size()) {
return image_list_[i];
}
return NULL;
}
// Returns the image corresponding to the main executable.
DynamicImage *GetExecutableImage();
int GetExecutableImageIndex();
// Returns the task which we're looking at.
mach_port_t GetTask() const {return task_;}
// CPU type of the task
cpu_type_t GetCPUType() {return cpu_type_;}
// Return true if the task is a 64-bit architecture.
bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; }
// Determine the CPU type of the task being dumped.
static cpu_type_t DetermineTaskCPUType(task_t task);
// Get the native CPU type of this task.
static cpu_type_t GetNativeCPUType() {
#if defined(__i386__)
return CPU_TYPE_I386;
#elif defined(__x86_64__)
return CPU_TYPE_X86_64;
#elif defined(__ppc__)
return CPU_TYPE_POWERPC;
#elif defined(__ppc64__)
return CPU_TYPE_POWERPC64;
#elif defined(__arm__)
return CPU_TYPE_ARM;
#elif defined(__aarch64__)
return CPU_TYPE_ARM64;
#else
#error "GetNativeCPUType not implemented for this architecture"
#endif
}
private:
template<typename MachBits>
friend void ReadImageInfo(DynamicImages& images, uint64_t image_list_address);
bool IsOurTask() {return task_ == mach_task_self();}
// Initialization
void ReadImageInfoForTask();
uint64_t GetDyldAllImageInfosPointer();
mach_port_t task_;
cpu_type_t cpu_type_; // CPU type of task_
vector<DynamicImageRef> image_list_;
};
// Fill bytes with the contents of memory at a particular
// location in another task.
kern_return_t ReadTaskMemory(task_port_t target_task,
const uint64_t address,
size_t length,
vector<uint8_t> &bytes);
} // namespace google_breakpad
#endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__

View file

@ -0,0 +1,48 @@
// 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.
#ifndef CLIENT_MAC_GENERATOR_MACH_VM_COMPAT_H_
#define CLIENT_MAC_GENERATOR_MACH_VM_COMPAT_H_
#include <TargetConditionals.h>
// On iOS 5 and higher, mach/mach_vm.h is not supported. Use the corresponding
// vm_map functions instead.
#if TARGET_OS_IPHONE
#include <mach/vm_map.h>
#define mach_vm_address_t vm_address_t
#define mach_vm_deallocate vm_deallocate
#define mach_vm_read vm_read
#define mach_vm_region_recurse vm_region_recurse_64
#define mach_vm_size_t vm_size_t
#else
#include <mach/mach_vm.h>
#endif // TARGET_OS_IPHONE
#endif // CLIENT_MAC_GENERATOR_MACH_VM_COMPAT_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
// 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.
// minidump_generator.h: Create a minidump of the current MacOS process.
#ifndef CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
#define CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
#include <mach/mach.h>
#include <TargetConditionals.h>
#include <string>
#include "client/mac/handler/ucontext_compat.h"
#include "client/minidump_file_writer.h"
#include "common/memory.h"
#include "common/mac/macho_utilities.h"
#include "google_breakpad/common/minidump_format.h"
#include "dynamic_images.h"
#include "mach_vm_compat.h"
#if !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
#define HAS_PPC_SUPPORT
#endif
#if defined(__arm__)
#define HAS_ARM_SUPPORT
#elif defined(__aarch64__)
#define HAS_ARM64_SUPPORT
#elif defined(__i386__) || defined(__x86_64__)
#define HAS_X86_SUPPORT
#endif
namespace google_breakpad {
using std::string;
// Use the REGISTER_FROM_THREADSTATE to access a register name from the
// breakpad_thread_state_t structure.
#if __DARWIN_UNIX03 || TARGET_CPU_X86_64 || TARGET_CPU_PPC64 || TARGET_CPU_ARM
// In The 10.5 SDK Headers Apple prepended __ to the variable names in the
// i386_thread_state_t structure. There's no good way to tell what version of
// the SDK we're compiling against so we just toggle on the same preprocessor
// symbol Apple's headers use.
#define REGISTER_FROM_THREADSTATE(a, b) ((a)->__ ## b)
#else
#define REGISTER_FROM_THREADSTATE(a, b) (a->b)
#endif
// Creates a minidump file of the current process. If there is exception data,
// use SetExceptionInformation() to add this to the minidump. The minidump
// file is generated by the Write() function.
// Usage:
// MinidumpGenerator minidump();
// minidump.Write("/tmp/minidump");
//
class MinidumpGenerator {
public:
MinidumpGenerator();
MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread);
virtual ~MinidumpGenerator();
// Return <dir>/<unique_name>.dmp
// Sets |unique_name| (if requested) to the unique name for the minidump
static string UniqueNameInDirectory(const string &dir, string *unique_name);
// Write out the minidump into |path|
// All of the components of |path| must exist and be writable
// Return true if successful, false otherwise
bool Write(const char *path);
// Specify some exception information, if applicable
void SetExceptionInformation(int type, int code, int subcode,
mach_port_t thread_name) {
exception_type_ = type;
exception_code_ = code;
exception_subcode_ = subcode;
exception_thread_ = thread_name;
}
// Specify the task context. If |task_context| is not NULL, it will be used
// to retrieve the context of the current thread, instead of using
// |thread_get_state|.
void SetTaskContext(breakpad_ucontext_t *task_context);
// Gather system information. This should be call at least once before using
// the MinidumpGenerator class.
static void GatherSystemInformation();
protected:
// Overridable Stream writers
virtual bool WriteExceptionStream(MDRawDirectory *exception_stream);
// Overridable Helper
virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread);
private:
typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *);
// Stream writers
bool WriteThreadListStream(MDRawDirectory *thread_list_stream);
bool WriteMemoryListStream(MDRawDirectory *memory_list_stream);
bool WriteSystemInfoStream(MDRawDirectory *system_info_stream);
bool WriteModuleListStream(MDRawDirectory *module_list_stream);
bool WriteMiscInfoStream(MDRawDirectory *misc_info_stream);
bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream);
// Helpers
uint64_t CurrentPCForStack(breakpad_thread_state_data_t state);
bool GetThreadState(thread_act_t target_thread, thread_state_t state,
mach_msg_type_number_t *count);
bool WriteStackFromStartAddress(mach_vm_address_t start_addr,
MDMemoryDescriptor *stack_location);
bool WriteStack(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContext(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
bool WriteCVRecord(MDRawModule *module, int cpu_type,
const char *module_path, bool in_memory);
bool WriteModuleStream(unsigned int index, MDRawModule *module);
size_t CalculateStackSize(mach_vm_address_t start_addr);
int FindExecutableModule();
// Per-CPU implementations of these methods
#ifdef HAS_ARM_SUPPORT
bool WriteStackARM(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextARM(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
uint64_t CurrentPCForStackARM(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_ARM64_SUPPORT
bool WriteStackARM64(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextARM64(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_PPC_SUPPORT
bool WriteStackPPC(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextPPC(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
uint64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state);
bool WriteStackPPC64(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextPPC64(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
uint64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_X86_SUPPORT
bool WriteStackX86(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextX86(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
uint64_t CurrentPCForStackX86(breakpad_thread_state_data_t state);
bool WriteStackX86_64(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextX86_64(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
uint64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);
#endif
// disallow copy ctor and operator=
explicit MinidumpGenerator(const MinidumpGenerator &);
void operator=(const MinidumpGenerator &);
protected:
// Use this writer to put the data to disk
MinidumpFileWriter writer_;
private:
// Exception information
int exception_type_;
int exception_code_;
int exception_subcode_;
mach_port_t exception_thread_;
mach_port_t crashing_task_;
mach_port_t handler_thread_;
// CPU type of the task being dumped.
cpu_type_t cpu_type_;
// System information
static char build_string_[16];
static int os_major_version_;
static int os_minor_version_;
static int os_build_number_;
// Context of the task to dump.
breakpad_ucontext_t *task_context_;
// Information about dynamically loaded code
DynamicImages *dynamic_images_;
// PageAllocator makes it possible to allocate memory
// directly from the system, even while handling an exception.
mutable PageAllocator allocator_;
protected:
// Blocks of memory written to the dump. These are all currently
// written while writing the thread list stream, but saved here
// so a memory list stream can be written afterwards.
wasteful_vector<MDMemoryDescriptor> memory_blocks_;
};
} // namespace google_breakpad
#endif // CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__

View file

@ -0,0 +1,47 @@
// Copyright 2013 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_MAC_HANDLER_UCONTEXT_COMPAT_H_
#define CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_
#include <sys/ucontext.h>
// The purpose of this file is to work around the fact that ucontext_t's
// uc_mcontext member is an mcontext_t rather than an mcontext64_t on ARM64.
#if defined(__aarch64__)
// <sys/ucontext.h> doesn't include the below file.
#include <sys/_types/_ucontext64.h>
typedef ucontext64_t breakpad_ucontext_t;
#define breakpad_uc_mcontext uc_mcontext64
#else
typedef ucontext_t breakpad_ucontext_t;
#define breakpad_uc_mcontext uc_mcontext
#endif // defined(__aarch64__)
#endif // CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_

View file

@ -0,0 +1,97 @@
// 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.
// minidump_file_writer-inl.h: Minidump file writer implementation.
//
// See minidump_file_writer.h for documentation.
#ifndef CLIENT_MINIDUMP_FILE_WRITER_INL_H__
#define CLIENT_MINIDUMP_FILE_WRITER_INL_H__
#include <assert.h>
#include "client/minidump_file_writer.h"
#include "google_breakpad/common/minidump_size.h"
namespace google_breakpad {
template<typename MDType>
inline bool TypedMDRVA<MDType>::Allocate() {
allocation_state_ = SINGLE_OBJECT;
return UntypedMDRVA::Allocate(minidump_size<MDType>::size());
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::Allocate(size_t additional) {
allocation_state_ = SINGLE_OBJECT;
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() + additional);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::AllocateArray(size_t count) {
assert(count);
allocation_state_ = ARRAY;
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() * count);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::AllocateObjectAndArray(size_t count,
size_t length) {
assert(count && length);
allocation_state_ = SINGLE_OBJECT_WITH_ARRAY;
return UntypedMDRVA::Allocate(minidump_size<MDType>::size() + count * length);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType *item) {
assert(allocation_state_ == ARRAY);
return writer_->Copy(
static_cast<MDRVA>(position_ + index * minidump_size<MDType>::size()),
item, minidump_size<MDType>::size());
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::CopyIndexAfterObject(unsigned int index,
const void *src,
size_t length) {
assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY);
return writer_->Copy(
static_cast<MDRVA>(position_ + minidump_size<MDType>::size()
+ index * length),
src, length);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::Flush() {
return writer_->Copy(position_, &data_, minidump_size<MDType>::size());
}
} // namespace google_breakpad
#endif // CLIENT_MINIDUMP_FILE_WRITER_INL_H__

View file

@ -0,0 +1,350 @@
// 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.
// minidump_file_writer.cc: Minidump file writer implementation.
//
// See minidump_file_writer.h for documentation.
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "client/minidump_file_writer-inl.h"
#include "common/linux/linux_libc_support.h"
#include "common/string_conversion.h"
#if defined(__linux__) && __linux__
#include "third_party/lss/linux_syscall_support.h"
#endif
#if defined(__ANDROID__)
#include <errno.h>
namespace {
bool g_need_ftruncate_workaround = false;
bool g_checked_need_ftruncate_workaround = false;
void CheckNeedsFTruncateWorkAround(int file) {
if (g_checked_need_ftruncate_workaround) {
return;
}
g_checked_need_ftruncate_workaround = true;
// Attempt an idempotent truncate that chops off nothing and see if we
// run into any sort of errors.
off_t offset = sys_lseek(file, 0, SEEK_END);
if (offset == -1) {
// lseek failed. Don't apply work around. It's unlikely that we can write
// to a minidump with either method.
return;
}
int result = ftruncate(file, offset);
if (result == -1 && errno == EACCES) {
// It very likely that we are running into the kernel bug in M devices.
// We are going to deploy the workaround for writing minidump files
// without uses of ftruncate(). This workaround should be fine even
// for kernels without the bug.
// See http://crbug.com/542840 for more details.
g_need_ftruncate_workaround = true;
}
}
bool NeedsFTruncateWorkAround() {
return g_need_ftruncate_workaround;
}
} // namespace
#endif // defined(__ANDROID__)
namespace google_breakpad {
const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1);
MinidumpFileWriter::MinidumpFileWriter()
: file_(-1),
close_file_when_destroyed_(true),
position_(0),
size_(0) {
}
MinidumpFileWriter::~MinidumpFileWriter() {
if (close_file_when_destroyed_)
Close();
}
bool MinidumpFileWriter::Open(const char *path) {
assert(file_ == -1);
#if defined(__linux__) && __linux__
file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
#else
file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
#endif
return file_ != -1;
}
void MinidumpFileWriter::SetFile(const int file) {
assert(file_ == -1);
file_ = file;
close_file_when_destroyed_ = false;
#if defined(__ANDROID__)
CheckNeedsFTruncateWorkAround(file);
#endif
}
bool MinidumpFileWriter::Close() {
bool result = true;
if (file_ != -1) {
#if defined(__ANDROID__)
if (!NeedsFTruncateWorkAround() && ftruncate(file_, position_)) {
return false;
}
#else
if (ftruncate(file_, position_)) {
return false;
}
#endif
#if defined(__linux__) && __linux__
result = (sys_close(file_) == 0);
#else
result = (close(file_) == 0);
#endif
file_ = -1;
}
return result;
}
bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
unsigned int length,
TypedMDRVA<MDString> *mdstring) {
bool result = true;
if (sizeof(wchar_t) == sizeof(uint16_t)) {
// Shortcut if wchar_t is the same size as MDString's buffer
result = mdstring->Copy(str, mdstring->get()->length);
} else {
uint16_t out[2];
int out_idx = 0;
// Copy the string character by character
while (length && result) {
UTF32ToUTF16Char(*str, out);
if (!out[0])
return false;
// Process one character at a time
--length;
++str;
// Append the one or two UTF-16 characters. The first one will be non-
// zero, but the second one may be zero, depending on the conversion from
// UTF-32.
int out_count = out[1] ? 2 : 1;
size_t out_size = sizeof(uint16_t) * out_count;
result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
out_idx += out_count;
}
}
return result;
}
bool MinidumpFileWriter::CopyStringToMDString(const char *str,
unsigned int length,
TypedMDRVA<MDString> *mdstring) {
bool result = true;
uint16_t out[2];
int out_idx = 0;
// Copy the string character by character
while (length && result) {
int conversion_count = UTF8ToUTF16Char(str, length, out);
if (!conversion_count)
return false;
// Move the pointer along based on the nubmer of converted characters
length -= conversion_count;
str += conversion_count;
// Append the one or two UTF-16 characters
int out_count = out[1] ? 2 : 1;
size_t out_size = sizeof(uint16_t) * out_count;
result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
out_idx += out_count;
}
return result;
}
template <typename CharType>
bool MinidumpFileWriter::WriteStringCore(const CharType *str,
unsigned int length,
MDLocationDescriptor *location) {
assert(str);
assert(location);
// Calculate the mdstring length by either limiting to |length| as passed in
// or by finding the location of the NULL character.
unsigned int mdstring_length = 0;
if (!length)
length = INT_MAX;
for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length)
;
// Allocate the string buffer
TypedMDRVA<MDString> mdstring(this);
if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(uint16_t)))
return false;
// Set length excluding the NULL and copy the string
mdstring.get()->length =
static_cast<uint32_t>(mdstring_length * sizeof(uint16_t));
bool result = CopyStringToMDString(str, mdstring_length, &mdstring);
// NULL terminate
if (result) {
uint16_t ch = 0;
result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch));
if (result)
*location = mdstring.location();
}
return result;
}
bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length,
MDLocationDescriptor *location) {
return WriteStringCore(str, length, location);
}
bool MinidumpFileWriter::WriteString(const char *str, unsigned int length,
MDLocationDescriptor *location) {
return WriteStringCore(str, length, location);
}
bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
MDMemoryDescriptor *output) {
assert(src);
assert(output);
UntypedMDRVA mem(this);
if (!mem.Allocate(size))
return false;
if (!mem.Copy(src, mem.size()))
return false;
output->start_of_memory_range = reinterpret_cast<uint64_t>(src);
output->memory = mem.location();
return true;
}
MDRVA MinidumpFileWriter::Allocate(size_t size) {
assert(size);
assert(file_ != -1);
#if defined(__ANDROID__)
if (NeedsFTruncateWorkAround()) {
// If ftruncate() is not available. We simply increase the size beyond the
// current file size. sys_write() will expand the file when data is written
// to it. Because we did not over allocate to fit memory pages, we also
// do not need to ftruncate() the file once we are done.
size_ += size;
// We don't need to seek since the file is unchanged.
MDRVA current_position = position_;
position_ += static_cast<MDRVA>(size);
return current_position;
}
#endif
size_t aligned_size = (size + 7) & ~7; // 64-bit alignment
if (position_ + aligned_size > size_) {
size_t growth = aligned_size;
size_t minimal_growth = getpagesize();
// Ensure that the file grows by at least the size of a memory page
if (growth < minimal_growth)
growth = minimal_growth;
size_t new_size = size_ + growth;
if (ftruncate(file_, new_size) != 0)
return kInvalidMDRVA;
size_ = new_size;
}
MDRVA current_position = position_;
position_ += static_cast<MDRVA>(aligned_size);
return current_position;
}
bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) {
assert(src);
assert(size);
assert(file_ != -1);
// Ensure that the data will fit in the allocated space
if (static_cast<size_t>(size + position) > size_)
return false;
// Seek and write the data
#if defined(__linux__) && __linux__
if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (sys_write(file_, src, size) == size) {
return true;
}
}
#else
if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (write(file_, src, size) == size) {
return true;
}
}
#endif
return false;
}
bool UntypedMDRVA::Allocate(size_t size) {
assert(size_ == 0);
size_ = size;
position_ = writer_->Allocate(size_);
return position_ != MinidumpFileWriter::kInvalidMDRVA;
}
bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) {
assert(src);
assert(size);
assert(pos + size <= position_ + size_);
return writer_->Copy(pos, src, size);
}
} // namespace google_breakpad

View file

@ -0,0 +1,272 @@
// 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.
// minidump_file_writer.h: Implements file-based minidump generation. It's
// intended to be used with the Google Breakpad open source crash handling
// project.
#ifndef CLIENT_MINIDUMP_FILE_WRITER_H__
#define CLIENT_MINIDUMP_FILE_WRITER_H__
#include <string>
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
class UntypedMDRVA;
template<typename MDType> class TypedMDRVA;
// The user of this class can Open() a file and add minidump streams, data, and
// strings using the definitions in minidump_format.h. Since this class is
// expected to be used in a situation where the current process may be
// damaged, it will not allocate heap memory.
// Sample usage:
// MinidumpFileWriter writer;
// writer.Open("/tmp/minidump.dmp");
// TypedMDRVA<MDRawHeader> header(&writer_);
// header.Allocate();
// header->get()->signature = MD_HEADER_SIGNATURE;
// :
// writer.Close();
//
// An alternative is to use SetFile and provide a file descriptor:
// MinidumpFileWriter writer;
// writer.SetFile(minidump_fd);
// TypedMDRVA<MDRawHeader> header(&writer_);
// header.Allocate();
// header->get()->signature = MD_HEADER_SIGNATURE;
// :
// writer.Close();
class MinidumpFileWriter {
public:
// Invalid MDRVA (Minidump Relative Virtual Address)
// returned on failed allocation
static const MDRVA kInvalidMDRVA;
MinidumpFileWriter();
~MinidumpFileWriter();
// Open |path| as the destination of the minidump data. If |path| already
// exists, then Open() will fail.
// Return true on success, or false on failure.
bool Open(const char *path);
// Sets the file descriptor |file| as the destination of the minidump data.
// Can be used as an alternative to Open() when a file descriptor is
// available.
// Note that |fd| is not closed when the instance of MinidumpFileWriter is
// destroyed.
void SetFile(const int file);
// Close the current file (that was either created when Open was called, or
// specified with SetFile).
// Return true on success, or false on failure.
bool Close();
// Copy the contents of |str| to a MDString and write it to the file.
// |str| is expected to be either UTF-16 or UTF-32 depending on the size
// of wchar_t.
// Maximum |length| of characters to copy from |str|, or specify 0 to use the
// entire NULL terminated string. Copying will stop at the first NULL.
// |location| the allocated location
// Return true on success, or false on failure
bool WriteString(const wchar_t *str, unsigned int length,
MDLocationDescriptor *location);
// Same as above, except with |str| as a UTF-8 string
bool WriteString(const char *str, unsigned int length,
MDLocationDescriptor *location);
// Write |size| bytes starting at |src| into the current position.
// Return true on success and set |output| to position, or false on failure
bool WriteMemory(const void *src, size_t size, MDMemoryDescriptor *output);
// Copies |size| bytes from |src| to |position|
// Return true on success, or false on failure
bool Copy(MDRVA position, const void *src, ssize_t size);
// Return the current position for writing to the minidump
inline MDRVA position() const { return position_; }
private:
friend class UntypedMDRVA;
// Allocates an area of |size| bytes.
// Returns the position of the allocation, or kInvalidMDRVA if it was
// unable to allocate the bytes.
MDRVA Allocate(size_t size);
// The file descriptor for the output file.
int file_;
// Whether |file_| should be closed when the instance is destroyed.
bool close_file_when_destroyed_;
// Current position in buffer
MDRVA position_;
// Current allocated size
size_t size_;
// Copy |length| characters from |str| to |mdstring|. These are distinct
// because the underlying MDString is a UTF-16 based string. The wchar_t
// variant may need to create a MDString that has more characters than the
// source |str|, whereas the UTF-8 variant may coalesce characters to form
// a single UTF-16 character.
bool CopyStringToMDString(const wchar_t *str, unsigned int length,
TypedMDRVA<MDString> *mdstring);
bool CopyStringToMDString(const char *str, unsigned int length,
TypedMDRVA<MDString> *mdstring);
// The common templated code for writing a string
template <typename CharType>
bool WriteStringCore(const CharType *str, unsigned int length,
MDLocationDescriptor *location);
};
// Represents an untyped allocated chunk
class UntypedMDRVA {
public:
explicit UntypedMDRVA(MinidumpFileWriter *writer)
: writer_(writer),
position_(writer->position()),
size_(0) {}
// Allocates |size| bytes. Must not call more than once.
// Return true on success, or false on failure
bool Allocate(size_t size);
// Returns the current position or kInvalidMDRVA if allocation failed
inline MDRVA position() const { return position_; }
// Number of bytes allocated
inline size_t size() const { return size_; }
// Return size and position
inline MDLocationDescriptor location() const {
MDLocationDescriptor location = { static_cast<uint32_t>(size_),
position_ };
return location;
}
// Copy |size| bytes starting at |src| into the minidump at |position|
// Return true on success, or false on failure
bool Copy(MDRVA position, const void *src, size_t size);
// Copy |size| bytes from |src| to the current position
inline bool Copy(const void *src, size_t size) {
return Copy(position_, src, size);
}
protected:
// Writer we associate with
MinidumpFileWriter *writer_;
// Position of the start of the data
MDRVA position_;
// Allocated size
size_t size_;
};
// Represents a Minidump object chunk. Additional memory can be allocated at
// the end of the object as a:
// - single allocation
// - Array of MDType objects
// - A MDType object followed by an array
template<typename MDType>
class TypedMDRVA : public UntypedMDRVA {
public:
// Constructs an unallocated MDRVA
explicit TypedMDRVA(MinidumpFileWriter *writer)
: UntypedMDRVA(writer),
data_(),
allocation_state_(UNALLOCATED) {}
inline ~TypedMDRVA() {
// Ensure that the data_ object is written out
if (allocation_state_ != ARRAY)
Flush();
}
// Address of object data_ of MDType. This is not declared const as the
// typical usage will be to access the underlying |data_| object as to
// alter its contents.
MDType *get() { return &data_; }
// Allocates minidump_size<MDType>::size() bytes.
// Must not call more than once.
// Return true on success, or false on failure
bool Allocate();
// Allocates minidump_size<MDType>::size() + |additional| bytes.
// Must not call more than once.
// Return true on success, or false on failure
bool Allocate(size_t additional);
// Allocate an array of |count| elements of MDType.
// Must not call more than once.
// Return true on success, or false on failure
bool AllocateArray(size_t count);
// Allocate an array of |count| elements of |size| after object of MDType
// Must not call more than once.
// Return true on success, or false on failure
bool AllocateObjectAndArray(size_t count, size_t size);
// Copy |item| to |index|
// Must have been allocated using AllocateArray().
// Return true on success, or false on failure
bool CopyIndex(unsigned int index, MDType *item);
// Copy |size| bytes starting at |str| to |index|
// Must have been allocated using AllocateObjectAndArray().
// Return true on success, or false on failure
bool CopyIndexAfterObject(unsigned int index, const void *src, size_t size);
// Write data_
bool Flush();
private:
enum AllocationState {
UNALLOCATED = 0,
SINGLE_OBJECT,
ARRAY,
SINGLE_OBJECT_WITH_ARRAY
};
MDType data_;
AllocationState allocation_state_;
};
} // namespace google_breakpad
#endif // CLIENT_MINIDUMP_FILE_WRITER_H__

View file

@ -0,0 +1,554 @@
/*
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
* Distributed under the Terms of Use in
* http://www.unicode.org/copyright.html.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of the Unicode data files and any associated documentation
* (the "Data Files") or Unicode software and any associated documentation
* (the "Software") to deal in the Data Files or Software
* without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, and/or sell copies of
* the Data Files or Software, and to permit persons to whom the Data Files
* or Software are furnished to do so, provided that
* (a) this copyright and permission notice appear with all copies
* of the Data Files or Software,
* (b) this copyright and permission notice appear in associated
* documentation, and
* (c) there is clear notice in each modified Data File or in the Software
* as well as in the documentation associated with the Data File(s) or
* Software that the data or software has been modified.
*
* THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
*
* Except as contained in this notice, the name of a copyright holder
* shall not be used in advertising or otherwise to promote the sale,
* use or other dealings in these Data Files or Software without prior
* written authorization of the copyright holder.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Sept 2001: fixed const & error conditions per
mods suggested by S. Parent & A. Lillich.
June 2002: Tim Dodd added detection and handling of incomplete
source sequences, enhanced error detection, added casts
to eliminate compiler warnings.
July 2003: slight mods to back out aggressive FFFE detection.
Jan 2004: updated switches in from-UTF8 conversions.
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
See the header file "ConvertUTF.h" for complete documentation.
------------------------------------------------------------------------ */
#include "convert_UTF.h"
#ifdef CVTUTF_DEBUG
#include <stdio.h>
#endif
static const int halfShift = 10; /* used for shifting by 10 bits */
static const UTF32 halfBase = 0x0010000UL;
static const UTF32 halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_START (UTF32)0xD800
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
#define UNI_SUR_LOW_START (UTF32)0xDC00
#define UNI_SUR_LOW_END (UTF32)0xDFFF
#ifndef false
#define false 0
#endif
#ifndef true
#define true 1
#endif
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
if (target >= targetEnd) {
result = targetExhausted; break;
}
ch = *source++;
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_LEGAL_UTF32) {
if (flags == strictConversion) {
result = sourceIllegal;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
--source; /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF32* target = *targetStart;
UTF32 ch, ch2;
while (source < sourceEnd) {
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
if (target >= targetEnd) {
source = oldSource; /* Back up source pointer! */
result = targetExhausted; break;
}
*target++ = ch;
}
*sourceStart = source;
*targetStart = target;
#ifdef CVTUTF_DEBUG
if (result == sourceIllegal) {
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
fflush(stderr);
}
#endif
return result;
}
/* --------------------------------------------------------------------- */
/*
* Index into the table below with the first byte of a UTF-8 sequence to
* get the number of trailing bytes that are supposed to follow it.
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
* left as-is for anyone who may want to do such conversion, which was
* allowed in earlier algorithms.
*/
static const char trailingBytesForUTF8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};
/*
* Magic values subtracted from a buffer value during UTF8 conversion.
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
* into the first byte, depending on how many bytes follow. There are
* as many entries in this table as there are UTF-8 sequence types.
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
* for *legal* UTF-8 will be 4 or fewer bytes total.
*/
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* --------------------------------------------------------------------- */
/* The interface converts a whole buffer to avoid function-call overhead.
* Constants have been gathered. Loops & conditionals have been removed as
* much as possible for efficiency, in favor of drop-through switches.
* (See "Note A" at the bottom of the file for equivalent code.)
* If your compiler supports it, the "isLegalUTF8" call can be turned
* into an inline function.
*/
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
UTF32 ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/* Figure out how many bytes the result will require */
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
}
target += bytesToWrite;
if (target > targetEnd) {
source = oldSource; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
* This must be called with the length pre-determined by the first byte.
* If not calling this from ConvertUTF8to*, then the length can be set by:
* length = trailingBytesForUTF8[*source]+1;
* and the sequence is illegal right away if there aren't that many bytes
* available.
* If presented with a length > 4, this returns false. The Unicode
* definition of UTF-8 goes up to 4-byte sequences.
*/
static Boolean isLegalUTF8(const UTF8 *source, int length) {
UTF8 a;
const UTF8 *srcptr = source+length;
switch (length) {
default: return false;
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
switch (*source) {
/* no fall-through in this inner switch */
case 0xE0: if (a < 0xA0) return false; break;
case 0xED: if (a > 0x9F) return false; break;
case 0xF0: if (a < 0x90) return false; break;
case 0xF4: if (a > 0x8F) return false; break;
default: if (a < 0x80) return false;
}
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
}
if (*source > 0xF4) return false;
return true;
}
/* --------------------------------------------------------------------- */
/*
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
int length = trailingBytesForUTF8[*source]+1;
if (source+length > sourceEnd) {
return false;
}
return isLegalUTF8(source, length);
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_UTF16) {
if (flags == strictConversion) {
result = sourceIllegal;
source -= (extraBytesToRead+1); /* return to the start */
break; /* Bail out; shouldn't continue */
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
ch = *source++;
if (flags == strictConversion ) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/*
* Figure out how many bytes the result will require. Turn any
* illegally large UTF32 things (> Plane 17) into replacement chars.
*/
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
result = sourceIllegal;
}
target += bytesToWrite;
if (target > targetEnd) {
--source; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF32* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6;
case 4: ch += *source++; ch <<= 6;
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up the source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_LEGAL_UTF32) {
/*
* UTF-16 surrogate values are illegal in UTF-32, and anything
* over Plane 17 (> 0x10FFFF) is illegal.
*/
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = ch;
}
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
result = sourceIllegal;
*target++ = UNI_REPLACEMENT_CHAR;
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* ---------------------------------------------------------------------
Note A.
The fall-through switches in UTF-8 reading code save a
temp variable, some decrements & conditionals. The switches
are equivalent to the following loop:
{
int tmpBytesToRead = extraBytesToRead+1;
do {
ch += *source++;
--tmpBytesToRead;
if (tmpBytesToRead) ch <<= 6;
} while (tmpBytesToRead > 0);
}
In UTF-8 writing code, the switches on "bytesToWrite" are
similarly unrolled loops.
--------------------------------------------------------------------- */

View file

@ -0,0 +1,164 @@
/*
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
* Distributed under the Terms of Use in
* http://www.unicode.org/copyright.html.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of the Unicode data files and any associated documentation
* (the "Data Files") or Unicode software and any associated documentation
* (the "Software") to deal in the Data Files or Software
* without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, and/or sell copies of
* the Data Files or Software, and to permit persons to whom the Data Files
* or Software are furnished to do so, provided that
* (a) this copyright and permission notice appear with all copies
* of the Data Files or Software,
* (b) this copyright and permission notice appear in associated
* documentation, and
* (c) there is clear notice in each modified Data File or in the Software
* as well as in the documentation associated with the Data File(s) or
* Software that the data or software has been modified.
*
* THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
*
* Except as contained in this notice, the name of a copyright holder
* shall not be used in advertising or otherwise to promote the sale,
* use or other dealings in these Data Files or Software without prior
* written authorization of the copyright holder.
*/
#ifndef COMMON_CONVERT_UTF_H_
#define COMMON_CONVERT_UTF_H_
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Header file.
Several funtions are included here, forming a complete set of
conversions between the three formats. UTF-7 is not included
here, but is handled in a separate source file.
Each of these routines takes pointers to input buffers and output
buffers. The input buffers are const.
Each routine converts the text between *sourceStart and sourceEnd,
putting the result into the buffer between *targetStart and
targetEnd. Note: the end pointers are *after* the last item: e.g.
*(sourceEnd - 1) is the last item.
The return result indicates whether the conversion was successful,
and if not, whether the problem was in the source or target buffers.
(Only the first encountered problem is indicated.)
After the conversion, *sourceStart and *targetStart are both
updated to point to the end of last text successfully converted in
the respective buffers.
Input parameters:
sourceStart - pointer to a pointer to the source buffer.
The contents of this are modified on return so that
it points at the next thing to be converted.
targetStart - similarly, pointer to pointer to the target buffer.
sourceEnd, targetEnd - respectively pointers to the ends of the
two buffers, for overflow checking only.
These conversion functions take a ConversionFlags argument. When this
flag is set to strict, both irregular sequences and isolated surrogates
will cause an error. When the flag is set to lenient, both irregular
sequences and isolated surrogates are converted.
Whether the flag is strict or lenient, all illegal sequences will cause
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
must check for illegal sequences.
When the flag is set to lenient, characters over 0x10FFFF are converted
to the replacement character; otherwise (when the flag is set to strict)
they constitute an error.
Output parameters:
The value "sourceIllegal" is returned from some routines if the input
sequence is malformed. When "sourceIllegal" is returned, the source
value will point to the illegal value that caused the problem. E.g.,
in UTF-8 when a sequence is malformed, it points to the start of the
malformed sequence.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Fixes & updates, Sept 2001.
------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
16 bits, so wchar_t is no less portable than unsigned short!
All should be unsigned values to avoid sign extension during
bit mask & shift operations.
------------------------------------------------------------------------ */
typedef unsigned long UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
typedef unsigned char Boolean; /* 0 or 1 */
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
#define UNI_MAX_BMP (UTF32)0x0000FFFF
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
typedef enum {
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum {
strictConversion = 0,
lenientConversion
} ConversionFlags;
/* This is for C++ and does no harm in C */
#ifdef __cplusplus
extern "C" {
#endif
ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
#ifdef __cplusplus
}
#endif
/* --------------------------------------------------------------------- */
#endif // COMMON_CONVERT_UTF_H_

View file

@ -0,0 +1,96 @@
// 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.
// This header provides replacements for libc functions that we need. We if
// call the libc functions directly we risk crashing in the dynamic linker as
// it tries to resolve uncached PLT entries.
#ifndef CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
#define CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
#include <stdint.h>
#include <limits.h>
#include <sys/types.h>
extern "C" {
extern size_t my_strlen(const char* s);
extern int my_strcmp(const char* a, const char* b);
extern int my_strncmp(const char* a, const char* b, size_t len);
// Parse a non-negative integer.
// result: (output) the resulting non-negative integer
// s: a NUL terminated string
// Return true iff successful.
extern bool my_strtoui(int* result, const char* s);
// Return the length of the given unsigned integer when expressed in base 10.
extern unsigned my_uint_len(uintmax_t i);
// Convert an unsigned integer to a string
// output: (output) the resulting string is written here. This buffer must be
// large enough to hold the resulting string. Call |my_uint_len| to get the
// required length.
// i: the unsigned integer to serialise.
// i_len: the length of the integer in base 10 (see |my_uint_len|).
extern void my_uitos(char* output, uintmax_t i, unsigned i_len);
extern const char* my_strchr(const char* haystack, char needle);
extern const char* my_strrchr(const char* haystack, char needle);
// Read a hex value
// result: (output) the resulting value
// s: a string
// Returns a pointer to the first invalid charactor.
extern const char* my_read_hex_ptr(uintptr_t* result, const char* s);
extern const char* my_read_decimal_ptr(uintptr_t* result, const char* s);
extern void my_memset(void* ip, char c, size_t len);
extern void* my_memchr(const void* src, int c, size_t len);
// The following are considered safe to use in a compromised environment.
// Besides, this gives the compiler an opportunity to optimize their calls.
#define my_memcpy memcpy
#define my_memmove memmove
#define my_memcmp memcmp
extern size_t my_strlcpy(char* s1, const char* s2, size_t len);
extern size_t my_strlcat(char* s1, const char* s2, size_t len);
extern int my_isspace(int ch);
} // extern "C"
#endif // CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_

View file

@ -0,0 +1,301 @@
// Copyright (c) 2007, 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.
//
// MachIPC.h
//
// Some helpful wrappers for using Mach IPC calls
#ifndef MACH_IPC_H__
#define MACH_IPC_H__
#import <mach/mach.h>
#import <mach/message.h>
#import <servers/bootstrap.h>
#import <sys/types.h>
#import <CoreServices/CoreServices.h>
//==============================================================================
// DISCUSSION:
//
// The three main classes of interest are
//
// MachMessage: a wrapper for a mach message of the following form
// mach_msg_header_t
// mach_msg_body_t
// optional descriptors
// optional extra message data
//
// MachReceiveMessage and MachSendMessage subclass MachMessage
// and are used instead of MachMessage which is an abstract base class
//
// ReceivePort:
// Represents a mach port for which we have receive rights
//
// MachPortSender:
// Represents a mach port for which we have send rights
//
// Here's an example to receive a message on a server port:
//
// // This creates our named server port
// ReceivePort receivePort("com.Google.MyService");
//
// MachReceiveMessage message;
// kern_return_t result = receivePort.WaitForMessage(&message, 0);
//
// if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
// mach_port_t task = message.GetTranslatedPort(0);
// mach_port_t thread = message.GetTranslatedPort(1);
//
// char *messageString = message.GetData();
//
// printf("message string = %s\n", messageString);
// }
//
// Here is an example of using these classes to send a message to this port:
//
// // send to already named port
// MachPortSender sender("com.Google.MyService");
// MachSendMessage message(57); // our message ID is 57
//
// // add some ports to be translated for us
// message.AddDescriptor(mach_task_self()); // our task
// message.AddDescriptor(mach_thread_self()); // this thread
//
// char messageString[] = "Hello server!\n";
// message.SetData(messageString, strlen(messageString)+1);
//
// kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms
//
namespace google_breakpad {
#define PRINT_MACH_RESULT(result_, message_) \
printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
//==============================================================================
// A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
// with convenient constructors and accessors
class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
public:
// General-purpose constructor
MachMsgPortDescriptor(mach_port_t in_name,
mach_msg_type_name_t in_disposition) {
name = in_name;
pad1 = 0;
pad2 = 0;
disposition = in_disposition;
type = MACH_MSG_PORT_DESCRIPTOR;
}
// For passing send rights to a port
MachMsgPortDescriptor(mach_port_t in_name) {
name = in_name;
pad1 = 0;
pad2 = 0;
disposition = MACH_MSG_TYPE_COPY_SEND;
type = MACH_MSG_PORT_DESCRIPTOR;
}
// Copy constructor
MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
name = desc.name;
pad1 = desc.pad1;
pad2 = desc.pad2;
disposition = desc.disposition;
type = desc.type;
}
mach_port_t GetMachPort() const {
return name;
}
mach_msg_type_name_t GetDisposition() const {
return disposition;
}
// For convenience
operator mach_port_t() const {
return GetMachPort();
}
};
//==============================================================================
// MachMessage: a wrapper for a mach message
// (mach_msg_header_t, mach_msg_body_t, extra data)
//
// This considerably simplifies the construction of a message for sending
// and the getting at relevant data and descriptors for the receiver.
//
// Currently the combined size of the descriptors plus data must be
// less than 1024. But as a benefit no memory allocation is necessary.
//
// TODO: could consider adding malloc() support for very large messages
//
// A MachMessage object is used by ReceivePort::WaitForMessage
// and MachPortSender::SendMessage
//
class MachMessage {
public:
// The receiver of the message can retrieve the raw data this way
uint8_t *GetData() {
return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
}
uint32_t GetDataLength() {
return EndianU32_LtoN(GetDataPacket()->data_length);
}
// The message ID may be used as a code identifying the type of message
void SetMessageID(int32_t message_id) {
GetDataPacket()->id = EndianU32_NtoL(message_id);
}
int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
// Adds a descriptor (typically a mach port) to be translated
// returns true if successful, otherwise not enough space
bool AddDescriptor(const MachMsgPortDescriptor &desc);
int GetDescriptorCount() const { return body.msgh_descriptor_count; }
MachMsgPortDescriptor *GetDescriptor(int n);
// Convenience method which gets the mach port described by the descriptor
mach_port_t GetTranslatedPort(int n);
// A simple message is one with no descriptors
bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
// Sets raw data for the message (returns false if not enough space)
bool SetData(void *data, int32_t data_length);
protected:
// Consider this an abstract base class - must create an actual instance
// of MachReceiveMessage or MachSendMessage
MachMessage() {
memset(this, 0, sizeof(MachMessage));
}
friend class ReceivePort;
friend class MachPortSender;
// Represents raw data in our message
struct MessageDataPacket {
int32_t id; // little-endian
int32_t data_length; // little-endian
uint8_t data[1]; // actual size limited by sizeof(MachMessage)
};
MessageDataPacket* GetDataPacket();
void SetDescriptorCount(int n);
void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
// Returns total message size setting msgh_size in the header to this value
mach_msg_size_t CalculateSize();
mach_msg_header_t head;
mach_msg_body_t body;
uint8_t padding[1024]; // descriptors and data may be embedded here
};
//==============================================================================
// MachReceiveMessage and MachSendMessage are useful to separate the idea
// of a mach message being sent and being received, and adds increased type
// safety:
// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
// MachPortSender::SendMessage() only accepts a MachSendMessage
//==============================================================================
class MachReceiveMessage : public MachMessage {
public:
MachReceiveMessage() : MachMessage() {};
};
//==============================================================================
class MachSendMessage : public MachMessage {
public:
MachSendMessage(int32_t message_id);
};
//==============================================================================
// Represents a mach port for which we have receive rights
class ReceivePort {
public:
// Creates a new mach port for receiving messages and registers a name for it
explicit ReceivePort(const char *receive_port_name);
// Given an already existing mach port, use it. We take ownership of the
// port and deallocate it in our destructor.
explicit ReceivePort(mach_port_t receive_port);
// Create a new mach port for receiving messages
ReceivePort();
~ReceivePort();
// Waits on the mach port until message received or timeout
kern_return_t WaitForMessage(MachReceiveMessage *out_message,
mach_msg_timeout_t timeout);
// The underlying mach port that we wrap
mach_port_t GetPort() const { return port_; }
private:
ReceivePort(const ReceivePort&); // disable copy c-tor
mach_port_t port_;
kern_return_t init_result_;
};
//==============================================================================
// Represents a mach port for which we have send rights
class MachPortSender {
public:
// get a port with send rights corresponding to a named registered service
explicit MachPortSender(const char *receive_port_name);
// Given an already existing mach port, use it.
explicit MachPortSender(mach_port_t send_port);
kern_return_t SendMessage(MachSendMessage &message,
mach_msg_timeout_t timeout);
private:
MachPortSender(const MachPortSender&); // disable copy c-tor
mach_port_t send_port_;
kern_return_t init_result_;
};
} // namespace google_breakpad
#endif // MACH_IPC_H__

View file

@ -0,0 +1,306 @@
// Copyright (c) 2007, 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.
//
// MachIPC.mm
// Wrapper for mach IPC calls
#import <stdio.h>
#import "MachIPC.h"
#include "common/mac/bootstrap_compat.h"
namespace google_breakpad {
//==============================================================================
MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
// head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
head.msgh_local_port = MACH_PORT_NULL;
head.msgh_reserved = 0;
head.msgh_id = 0;
SetDescriptorCount(0); // start out with no descriptors
SetMessageID(message_id);
SetData(NULL, 0); // client may add data later
}
//==============================================================================
// returns true if successful
bool MachMessage::SetData(void *data,
int32_t data_length) {
// first check to make sure we have enough space
size_t size = CalculateSize();
size_t new_size = size + data_length;
if (new_size > sizeof(MachMessage)) {
return false; // not enough space
}
GetDataPacket()->data_length = EndianU32_NtoL(data_length);
if (data) memcpy(GetDataPacket()->data, data, data_length);
CalculateSize();
return true;
}
//==============================================================================
// calculates and returns the total size of the message
// Currently, the entire message MUST fit inside of the MachMessage
// messsage size <= sizeof(MachMessage)
mach_msg_size_t MachMessage::CalculateSize() {
size_t size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
// add space for MessageDataPacket
int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
size += 2*sizeof(int32_t) + alignedDataLength;
// add space for descriptors
size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
head.msgh_size = static_cast<mach_msg_size_t>(size);
return head.msgh_size;
}
//==============================================================================
MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
MessageDataPacket *packet =
reinterpret_cast<MessageDataPacket*>(padding + desc_size);
return packet;
}
//==============================================================================
void MachMessage::SetDescriptor(int n,
const MachMsgPortDescriptor &desc) {
MachMsgPortDescriptor *desc_array =
reinterpret_cast<MachMsgPortDescriptor*>(padding);
desc_array[n] = desc;
}
//==============================================================================
// returns true if successful otherwise there was not enough space
bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
// first check to make sure we have enough space
int size = CalculateSize();
size_t new_size = size + sizeof(MachMsgPortDescriptor);
if (new_size > sizeof(MachMessage)) {
return false; // not enough space
}
// unfortunately, we need to move the data to allow space for the
// new descriptor
u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
SetDescriptor(GetDescriptorCount(), desc);
SetDescriptorCount(GetDescriptorCount() + 1);
CalculateSize();
return true;
}
//==============================================================================
void MachMessage::SetDescriptorCount(int n) {
body.msgh_descriptor_count = n;
if (n > 0) {
head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
} else {
head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
}
}
//==============================================================================
MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
if (n < GetDescriptorCount()) {
MachMsgPortDescriptor *desc =
reinterpret_cast<MachMsgPortDescriptor*>(padding);
return desc + n;
}
return nil;
}
//==============================================================================
mach_port_t MachMessage::GetTranslatedPort(int n) {
if (n < GetDescriptorCount()) {
return GetDescriptor(n)->GetMachPort();
}
return MACH_PORT_NULL;
}
#pragma mark -
//==============================================================================
// create a new mach port for receiving messages and register a name for it
ReceivePort::ReceivePort(const char *receive_port_name) {
mach_port_t current_task = mach_task_self();
init_result_ = mach_port_allocate(current_task,
MACH_PORT_RIGHT_RECEIVE,
&port_);
if (init_result_ != KERN_SUCCESS)
return;
init_result_ = mach_port_insert_right(current_task,
port_,
port_,
MACH_MSG_TYPE_MAKE_SEND);
if (init_result_ != KERN_SUCCESS)
return;
mach_port_t task_bootstrap_port = 0;
init_result_ = task_get_bootstrap_port(current_task, &task_bootstrap_port);
if (init_result_ != KERN_SUCCESS)
return;
init_result_ = breakpad::BootstrapRegister(
bootstrap_port,
const_cast<char*>(receive_port_name),
port_);
}
//==============================================================================
// create a new mach port for receiving messages
ReceivePort::ReceivePort() {
mach_port_t current_task = mach_task_self();
init_result_ = mach_port_allocate(current_task,
MACH_PORT_RIGHT_RECEIVE,
&port_);
if (init_result_ != KERN_SUCCESS)
return;
init_result_ = mach_port_insert_right(current_task,
port_,
port_,
MACH_MSG_TYPE_MAKE_SEND);
}
//==============================================================================
// Given an already existing mach port, use it. We take ownership of the
// port and deallocate it in our destructor.
ReceivePort::ReceivePort(mach_port_t receive_port)
: port_(receive_port),
init_result_(KERN_SUCCESS) {
}
//==============================================================================
ReceivePort::~ReceivePort() {
if (init_result_ == KERN_SUCCESS)
mach_port_deallocate(mach_task_self(), port_);
}
//==============================================================================
kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
mach_msg_timeout_t timeout) {
if (!out_message) {
return KERN_INVALID_ARGUMENT;
}
// return any error condition encountered in constructor
if (init_result_ != KERN_SUCCESS)
return init_result_;
out_message->head.msgh_bits = 0;
out_message->head.msgh_local_port = port_;
out_message->head.msgh_remote_port = MACH_PORT_NULL;
out_message->head.msgh_reserved = 0;
out_message->head.msgh_id = 0;
mach_msg_option_t options = MACH_RCV_MSG;
if (timeout != MACH_MSG_TIMEOUT_NONE)
options |= MACH_RCV_TIMEOUT;
kern_return_t result = mach_msg(&out_message->head,
options,
0,
sizeof(MachMessage),
port_,
timeout, // timeout in ms
MACH_PORT_NULL);
return result;
}
#pragma mark -
//==============================================================================
// get a port with send rights corresponding to a named registered service
MachPortSender::MachPortSender(const char *receive_port_name) {
mach_port_t task_bootstrap_port = 0;
init_result_ = task_get_bootstrap_port(mach_task_self(),
&task_bootstrap_port);
if (init_result_ != KERN_SUCCESS)
return;
init_result_ = bootstrap_look_up(task_bootstrap_port,
const_cast<char*>(receive_port_name),
&send_port_);
}
//==============================================================================
MachPortSender::MachPortSender(mach_port_t send_port)
: send_port_(send_port),
init_result_(KERN_SUCCESS) {
}
//==============================================================================
kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
mach_msg_timeout_t timeout) {
if (message.head.msgh_size == 0) {
return KERN_INVALID_VALUE; // just for safety -- never should occur
};
if (init_result_ != KERN_SUCCESS)
return init_result_;
message.head.msgh_remote_port = send_port_;
kern_return_t result = mach_msg(&message.head,
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
message.head.msgh_size,
0,
MACH_PORT_NULL,
timeout, // timeout in ms
MACH_PORT_NULL);
return result;
}
} // namespace google_breakpad

View file

@ -0,0 +1,42 @@
// 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 "common/mac/bootstrap_compat.h"
namespace breakpad {
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
kern_return_t BootstrapRegister(mach_port_t bp,
name_t service_name,
mach_port_t sp) {
return bootstrap_register(bp, service_name, sp);
}
#pragma GCC diagnostic warning "-Wdeprecated-declarations"
} // namesapce breakpad

View file

@ -0,0 +1,54 @@
// 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 COMMON_MAC_BOOTSTRAP_COMPAT_H_
#define COMMON_MAC_BOOTSTRAP_COMPAT_H_
#include <servers/bootstrap.h>
namespace breakpad {
// Wrapper for bootstrap_register to avoid deprecation warnings.
//
// In 10.6, it's possible to call bootstrap_check_in as the one-stop-shop for
// handling what bootstrap_register is used for. In 10.5, bootstrap_check_in
// can't check in a service whose name has not yet been registered, despite
// bootstrap_register being marked as deprecated in that OS release. Breakpad
// needs to register new service names, and in 10.5, calling
// bootstrap_register is the only way to achieve that. Attempts to call
// bootstrap_check_in for a new service name on 10.5 will result in
// BOOTSTRAP_UNKNOWN_SERVICE being returned rather than registration of the
// new service name.
kern_return_t BootstrapRegister(mach_port_t bp,
name_t service_name,
mach_port_t sp);
} // namespace breakpad
#endif // COMMON_MAC_BOOTSTRAP_COMPAT_H_

View file

@ -0,0 +1,73 @@
// -*- mode: c++ -*-
// 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.
// Original author: Jim Blandy <jim@mozilla.com> <jimb@red-bean.com>
// byteswap.h: Overloaded functions for conveniently byteswapping values.
#ifndef COMMON_MAC_BYTESWAP_H_
#define COMMON_MAC_BYTESWAP_H_
#ifdef __APPLE__
#include <libkern/OSByteOrder.h>
static inline uint16_t ByteSwap(uint16_t v) { return OSSwapInt16(v); }
static inline uint32_t ByteSwap(uint32_t v) { return OSSwapInt32(v); }
static inline uint64_t ByteSwap(uint64_t v) { return OSSwapInt64(v); }
static inline int16_t ByteSwap(int16_t v) { return OSSwapInt16(v); }
static inline int32_t ByteSwap(int32_t v) { return OSSwapInt32(v); }
static inline int64_t ByteSwap(int64_t v) { return OSSwapInt64(v); }
#elif defined(__linux__)
// For NXByteOrder
#include <architecture/byte_order.h>
#include <stdint.h>
#include <endian.h>
#include_next <byteswap.h>
static inline uint16_t ByteSwap(uint16_t v) { return bswap_16(v); }
static inline uint32_t ByteSwap(uint32_t v) { return bswap_32(v); }
static inline uint64_t ByteSwap(uint64_t v) { return bswap_64(v); }
static inline int16_t ByteSwap(int16_t v) { return bswap_16(v); }
static inline int32_t ByteSwap(int32_t v) { return bswap_32(v); }
static inline int64_t ByteSwap(int64_t v) { return bswap_64(v); }
static inline NXByteOrder NXHostByteOrder() {
#ifdef __LITTLE_ENDIAN
return NX_LittleEndian;
#else
return NX_BigEndian;
#endif
}
#endif // __APPLE__
#endif // COMMON_MAC_BYTESWAP_H_

View file

@ -0,0 +1,106 @@
// 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.
// file_id.cc: Return a unique identifier for a file
//
// See file_id.h for documentation
//
// Author: Dan Waylonis
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "common/mac/file_id.h"
#include "common/mac/macho_id.h"
using MacFileUtilities::MachoID;
namespace google_breakpad {
FileID::FileID(const char *path) {
snprintf(path_, sizeof(path_), "%s", path);
}
bool FileID::FileIdentifier(unsigned char identifier[16]) {
int fd = open(path_, O_RDONLY);
if (fd == -1)
return false;
MD5Context md5;
MD5Init(&md5);
// Read 4k x 2 bytes at a time. This is faster than just 4k bytes, but
// doesn't seem to be an unreasonable size for the stack.
unsigned char buffer[4096 * 2];
size_t buffer_size = sizeof(buffer);
while ((buffer_size = read(fd, buffer, buffer_size) > 0)) {
MD5Update(&md5, buffer, static_cast<unsigned>(buffer_size));
}
close(fd);
MD5Final(identifier, &md5);
return true;
}
bool FileID::MachoIdentifier(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]) {
MachoID macho(path_);
if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier))
return true;
return macho.MD5(cpu_type, cpu_subtype, identifier);
}
// static
void FileID::ConvertIdentifierToString(const unsigned char identifier[16],
char *buffer, int buffer_length) {
int buffer_idx = 0;
for (int idx = 0; (buffer_idx < buffer_length) && (idx < 16); ++idx) {
int hi = (identifier[idx] >> 4) & 0x0F;
int lo = (identifier[idx]) & 0x0F;
if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
buffer[buffer_idx++] = '-';
buffer[buffer_idx++] =
static_cast<char>((hi >= 10) ? ('A' + hi - 10) : ('0' + hi));
buffer[buffer_idx++] =
static_cast<char>((lo >= 10) ? ('A' + lo - 10) : ('0' + lo));
}
// NULL terminate
buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
}
} // namespace google_breakpad

View file

@ -0,0 +1,81 @@
// 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.
// file_id.h: Return a unique identifier for a file
//
// Author: Dan Waylonis
#ifndef COMMON_MAC_FILE_ID_H__
#define COMMON_MAC_FILE_ID_H__
#include <limits.h>
#include <mach/machine.h>
namespace google_breakpad {
class FileID {
public:
FileID(const char *path);
~FileID() {};
// Load the identifier for the file path specified in the constructor into
// |identifier|. Return false if the identifier could not be created for the
// file.
// The current implementation will return the MD5 hash of the file's bytes.
bool FileIdentifier(unsigned char identifier[16]);
// Treat the file as a mach-o file that will contain one or more archicture.
// Accepted values for |cpu_type| and |cpu_subtype| (e.g., CPU_TYPE_X86 or
// CPU_TYPE_POWERPC) are listed in /usr/include/mach/machine.h.
// If |cpu_type| is 0, then the native cpu type is used. If |cpu_subtype| is
// CPU_SUBTYPE_MULTIPLE, the match is only done on |cpu_type|.
// Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype|
// is not present in the file.
// Return the unique identifier in |identifier|.
// The current implementation will look for the (in order of priority):
// LC_UUID, LC_ID_DYLIB, or MD5 hash of the given |cpu_type|.
bool MachoIdentifier(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
// Convert the |identifier| data to a NULL terminated string. The string will
// be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE).
// The |buffer| should be at least 37 bytes long to receive all of the data
// and termination. Shorter buffers will contain truncated data.
static void ConvertIdentifierToString(const unsigned char identifier[16],
char *buffer, int buffer_length);
private:
// Storage for the path specified
char path_[PATH_MAX];
};
} // namespace google_breakpad
#endif // COMMON_MAC_FILE_ID_H__

View file

@ -0,0 +1,369 @@
// 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.
// macho_id.cc: Functions to gather identifying information from a macho file
//
// See macho_id.h for documentation
//
// Author: Dan Waylonis
#include <fcntl.h>
#include <mach-o/loader.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "common/mac/macho_id.h"
#include "common/mac/macho_walker.h"
#include "common/mac/macho_utilities.h"
namespace MacFileUtilities {
using google_breakpad::MD5Init;
using google_breakpad::MD5Update;
using google_breakpad::MD5Final;
MachoID::MachoID(const char *path)
: memory_(0),
memory_size_(0),
crc_(0),
md5_context_(),
update_function_(NULL) {
snprintf(path_, sizeof(path_), "%s", path);
}
MachoID::MachoID(const char *path, void *memory, size_t size)
: memory_(memory),
memory_size_(size),
crc_(0),
md5_context_(),
update_function_(NULL) {
snprintf(path_, sizeof(path_), "%s", path);
}
MachoID::~MachoID() {
}
// The CRC info is from http://en.wikipedia.org/wiki/Adler-32
// With optimizations from http://www.zlib.net/
// The largest prime smaller than 65536
#define MOD_ADLER 65521
// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1
#define MAX_BLOCK 5552
void MachoID::UpdateCRC(unsigned char *bytes, size_t size) {
// Unrolled loops for summing
#define DO1(buf,i) {sum1 += (buf)[i]; sum2 += sum1;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
// Split up the crc
uint32_t sum1 = crc_ & 0xFFFF;
uint32_t sum2 = (crc_ >> 16) & 0xFFFF;
// Do large blocks
while (size >= MAX_BLOCK) {
size -= MAX_BLOCK;
int block_count = MAX_BLOCK / 16;
do {
DO16(bytes);
bytes += 16;
} while (--block_count);
sum1 %= MOD_ADLER;
sum2 %= MOD_ADLER;
}
// Do remaining bytes
if (size) {
while (size >= 16) {
size -= 16;
DO16(bytes);
bytes += 16;
}
while (size--) {
sum1 += *bytes++;
sum2 += sum1;
}
sum1 %= MOD_ADLER;
sum2 %= MOD_ADLER;
crc_ = (sum2 << 16) | sum1;
}
}
void MachoID::UpdateMD5(unsigned char *bytes, size_t size) {
MD5Update(&md5_context_, bytes, static_cast<unsigned>(size));
}
void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
if (!update_function_ || !size)
return;
// Read up to 4k bytes at a time
unsigned char buffer[4096];
size_t buffer_size;
off_t file_offset = offset;
while (size > 0) {
if (size > sizeof(buffer)) {
buffer_size = sizeof(buffer);
size -= buffer_size;
} else {
buffer_size = size;
size = 0;
}
if (!walker->ReadBytes(buffer, buffer_size, file_offset))
return;
(this->*update_function_)(buffer, buffer_size);
file_offset += buffer_size;
}
}
bool MachoID::UUIDCommand(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char bytes[16]) {
struct breakpad_uuid_command uuid_cmd;
uuid_cmd.cmd = 0;
if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd))
return false;
// If we found the command, we'll have initialized the uuid_command
// structure
if (uuid_cmd.cmd == LC_UUID) {
memcpy(bytes, uuid_cmd.uuid, sizeof(uuid_cmd.uuid));
return true;
}
return false;
}
bool MachoID::IDCommand(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]) {
struct dylib_command dylib_cmd;
dylib_cmd.cmd = 0;
if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd))
return false;
// If we found the command, we'll have initialized the dylib_command
// structure
if (dylib_cmd.cmd == LC_ID_DYLIB) {
// Take the hashed filename, version, and compatability version bytes
// to form the first 12 bytes, pad the rest with zeros
// create a crude hash of the filename to generate the first 4 bytes
identifier[0] = 0;
identifier[1] = 0;
identifier[2] = 0;
identifier[3] = 0;
for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) {
identifier[j%4] += path_[i];
}
identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF;
identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF;
identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF;
identifier[7] = dylib_cmd.dylib.current_version & 0xFF;
identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF;
identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF;
identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF;
identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF;
identifier[12] = (cpu_type >> 24) & 0xFF;
identifier[13] = (cpu_type >> 16) & 0xFF;
identifier[14] = (cpu_type >> 8) & 0xFF;
identifier[15] = cpu_type & 0xFF;
return true;
}
return false;
}
uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
update_function_ = &MachoID::UpdateCRC;
crc_ = 0;
if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
return 0;
return crc_;
}
bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) {
update_function_ = &MachoID::UpdateMD5;
MD5Init(&md5_context_);
if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
return false;
MD5Final(identifier, &md5_context_);
return true;
}
bool MachoID::WalkHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
MachoWalker::LoadCommandCallback callback,
void *context) {
if (memory_) {
MachoWalker walker(memory_, memory_size_, callback, context);
return walker.WalkHeader(cpu_type, cpu_subtype);
} else {
MachoWalker walker(path_, callback, context);
return walker.WalkHeader(cpu_type, cpu_subtype);
}
}
// static
bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
bool swap, void *context) {
MachoID *macho_id = (MachoID *)context;
if (cmd->cmd == LC_SEGMENT) {
struct segment_command seg;
if (!walker->ReadBytes(&seg, sizeof(seg), offset))
return false;
if (swap)
breakpad_swap_segment_command(&seg);
struct mach_header_64 header;
off_t header_offset;
if (!walker->CurrentHeader(&header, &header_offset))
return false;
// Process segments that have sections:
// (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
offset += sizeof(struct segment_command);
struct section sec;
for (unsigned long i = 0; i < seg.nsects; ++i) {
if (!walker->ReadBytes(&sec, sizeof(sec), offset))
return false;
if (swap)
breakpad_swap_section(&sec, 1);
// sections of type S_ZEROFILL are "virtual" and contain no data
// in the file itself
if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0)
macho_id->Update(walker, header_offset + sec.offset, sec.size);
offset += sizeof(struct section);
}
} else if (cmd->cmd == LC_SEGMENT_64) {
struct segment_command_64 seg64;
if (!walker->ReadBytes(&seg64, sizeof(seg64), offset))
return false;
if (swap)
breakpad_swap_segment_command_64(&seg64);
struct mach_header_64 header;
off_t header_offset;
if (!walker->CurrentHeader(&header, &header_offset))
return false;
// Process segments that have sections:
// (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
offset += sizeof(struct segment_command_64);
struct section_64 sec64;
for (unsigned long i = 0; i < seg64.nsects; ++i) {
if (!walker->ReadBytes(&sec64, sizeof(sec64), offset))
return false;
if (swap)
breakpad_swap_section_64(&sec64, 1);
// sections of type S_ZEROFILL are "virtual" and contain no data
// in the file itself
if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0)
macho_id->Update(walker,
header_offset + sec64.offset,
(size_t)sec64.size);
offset += sizeof(struct section_64);
}
}
// Continue processing
return true;
}
// static
bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
bool swap, void *context) {
if (cmd->cmd == LC_UUID) {
struct breakpad_uuid_command *uuid_cmd =
(struct breakpad_uuid_command *)context;
if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command),
offset))
return false;
if (swap)
breakpad_swap_uuid_command(uuid_cmd);
return false;
}
// Continue processing
return true;
}
// static
bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
bool swap, void *context) {
if (cmd->cmd == LC_ID_DYLIB) {
struct dylib_command *dylib_cmd = (struct dylib_command *)context;
if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset))
return false;
if (swap)
breakpad_swap_dylib_command(dylib_cmd);
return false;
}
// Continue processing
return true;
}
} // namespace MacFileUtilities

View file

@ -0,0 +1,131 @@
// 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.
// macho_id.h: Functions to gather identifying information from a macho file
//
// Author: Dan Waylonis
#ifndef COMMON_MAC_MACHO_ID_H__
#define COMMON_MAC_MACHO_ID_H__
#include <limits.h>
#include <mach/machine.h>
#include <mach-o/loader.h>
#include "common/mac/macho_walker.h"
#include "common/md5.h"
namespace MacFileUtilities {
class MachoID {
public:
MachoID(const char *path);
MachoID(const char *path, void *memory, size_t size);
~MachoID();
// For the given |cpu_type| and |cpu_subtype|, return a UUID from the LC_UUID
// command.
// Return false if there isn't a LC_UUID command.
bool UUIDCommand(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
// For the given |cpu_type| and |cpu_subtype|, return a UUID from the
// LC_ID_DYLIB command.
// Return false if there isn't a LC_ID_DYLIB command.
bool IDCommand(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
// For the given |cpu_type| and |cpu_subtype|, return the Adler32 CRC for the
// mach-o data segment(s).
// Return 0 on error (e.g., if the file is not a mach-o file)
uint32_t Adler32(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype);
// For the given |cpu_type|, and |cpu_subtype| return the MD5 for the mach-o
// data segment(s).
// Return true on success, false otherwise
bool MD5(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
private:
// Signature of class member function to be called with data read from file
typedef void (MachoID::*UpdateFunction)(unsigned char *bytes, size_t size);
// Update the CRC value by examining |size| |bytes| and applying the algorithm
// to each byte.
void UpdateCRC(unsigned char *bytes, size_t size);
// Update the MD5 value by examining |size| |bytes| and applying the algorithm
// to each byte.
void UpdateMD5(unsigned char *bytes, size_t size);
// Bottleneck for update routines
void Update(MachoWalker *walker, off_t offset, size_t size);
// Factory for the MachoWalker
bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype,
MachoWalker::LoadCommandCallback callback, void *context);
// The callback from the MachoWalker for CRC and MD5
static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
bool swap, void *context);
// The callback from the MachoWalker for LC_UUID
static bool UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
bool swap, void *context);
// The callback from the MachoWalker for LC_ID_DYLIB
static bool IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
bool swap, void *context);
// File path
char path_[PATH_MAX];
// Memory region to read from
void *memory_;
// Size of the memory region
size_t memory_size_;
// The current crc value
uint32_t crc_;
// The MD5 context
google_breakpad::MD5Context md5_context_;
// The current update to call from the Update callback
UpdateFunction update_function_;
};
} // namespace MacFileUtilities
#endif // COMMON_MAC_MACHO_ID_H__

View file

@ -0,0 +1,155 @@
// 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.
// macho_utilties.cc: Utilities for dealing with mach-o files
//
// Author: Dave Camp
#include "common/mac/byteswap.h"
#include "common/mac/macho_utilities.h"
#include <mach-o/fat.h>
#include <mach-o/loader.h>
void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc) {
uc->cmd = ByteSwap(uc->cmd);
uc->cmdsize = ByteSwap(uc->cmdsize);
}
void breakpad_swap_load_command(struct load_command *lc) {
lc->cmd = ByteSwap(lc->cmd);
lc->cmdsize = ByteSwap(lc->cmdsize);
}
void breakpad_swap_dylib_command(struct dylib_command *dc) {
dc->cmd = ByteSwap(dc->cmd);
dc->cmdsize = ByteSwap(dc->cmdsize);
dc->dylib.name.offset = ByteSwap(dc->dylib.name.offset);
dc->dylib.timestamp = ByteSwap(dc->dylib.timestamp);
dc->dylib.current_version = ByteSwap(dc->dylib.current_version);
dc->dylib.compatibility_version = ByteSwap(dc->dylib.compatibility_version);
}
void breakpad_swap_segment_command(struct segment_command *sc) {
sc->cmd = ByteSwap(sc->cmd);
sc->cmdsize = ByteSwap(sc->cmdsize);
sc->vmaddr = ByteSwap(sc->vmaddr);
sc->vmsize = ByteSwap(sc->vmsize);
sc->fileoff = ByteSwap(sc->fileoff);
sc->filesize = ByteSwap(sc->filesize);
sc->maxprot = ByteSwap(sc->maxprot);
sc->initprot = ByteSwap(sc->initprot);
sc->nsects = ByteSwap(sc->nsects);
sc->flags = ByteSwap(sc->flags);
}
void breakpad_swap_segment_command_64(struct segment_command_64 *sg) {
sg->cmd = ByteSwap(sg->cmd);
sg->cmdsize = ByteSwap(sg->cmdsize);
sg->vmaddr = ByteSwap(sg->vmaddr);
sg->vmsize = ByteSwap(sg->vmsize);
sg->fileoff = ByteSwap(sg->fileoff);
sg->filesize = ByteSwap(sg->filesize);
sg->maxprot = ByteSwap(sg->maxprot);
sg->initprot = ByteSwap(sg->initprot);
sg->nsects = ByteSwap(sg->nsects);
sg->flags = ByteSwap(sg->flags);
}
void breakpad_swap_fat_header(struct fat_header *fh) {
fh->magic = ByteSwap(fh->magic);
fh->nfat_arch = ByteSwap(fh->nfat_arch);
}
void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs) {
for (uint32_t i = 0; i < narchs; ++i) {
fa[i].cputype = ByteSwap(fa[i].cputype);
fa[i].cpusubtype = ByteSwap(fa[i].cpusubtype);
fa[i].offset = ByteSwap(fa[i].offset);
fa[i].size = ByteSwap(fa[i].size);
fa[i].align = ByteSwap(fa[i].align);
}
}
void breakpad_swap_mach_header(struct mach_header *mh) {
mh->magic = ByteSwap(mh->magic);
mh->cputype = ByteSwap(mh->cputype);
mh->cpusubtype = ByteSwap(mh->cpusubtype);
mh->filetype = ByteSwap(mh->filetype);
mh->ncmds = ByteSwap(mh->ncmds);
mh->sizeofcmds = ByteSwap(mh->sizeofcmds);
mh->flags = ByteSwap(mh->flags);
}
void breakpad_swap_mach_header_64(struct mach_header_64 *mh) {
mh->magic = ByteSwap(mh->magic);
mh->cputype = ByteSwap(mh->cputype);
mh->cpusubtype = ByteSwap(mh->cpusubtype);
mh->filetype = ByteSwap(mh->filetype);
mh->ncmds = ByteSwap(mh->ncmds);
mh->sizeofcmds = ByteSwap(mh->sizeofcmds);
mh->flags = ByteSwap(mh->flags);
mh->reserved = ByteSwap(mh->reserved);
}
void breakpad_swap_section(struct section *s,
uint32_t nsects) {
for (uint32_t i = 0; i < nsects; i++) {
s[i].addr = ByteSwap(s[i].addr);
s[i].size = ByteSwap(s[i].size);
s[i].offset = ByteSwap(s[i].offset);
s[i].align = ByteSwap(s[i].align);
s[i].reloff = ByteSwap(s[i].reloff);
s[i].nreloc = ByteSwap(s[i].nreloc);
s[i].flags = ByteSwap(s[i].flags);
s[i].reserved1 = ByteSwap(s[i].reserved1);
s[i].reserved2 = ByteSwap(s[i].reserved2);
}
}
void breakpad_swap_section_64(struct section_64 *s,
uint32_t nsects) {
for (uint32_t i = 0; i < nsects; i++) {
s[i].addr = ByteSwap(s[i].addr);
s[i].size = ByteSwap(s[i].size);
s[i].offset = ByteSwap(s[i].offset);
s[i].align = ByteSwap(s[i].align);
s[i].reloff = ByteSwap(s[i].reloff);
s[i].nreloc = ByteSwap(s[i].nreloc);
s[i].flags = ByteSwap(s[i].flags);
s[i].reserved1 = ByteSwap(s[i].reserved1);
s[i].reserved2 = ByteSwap(s[i].reserved2);
}
}

View file

@ -0,0 +1,95 @@
// 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.
// macho_utilities.h: Utilities for dealing with mach-o files
//
// Author: Dave Camp
#ifndef COMMON_MAC_MACHO_UTILITIES_H__
#define COMMON_MAC_MACHO_UTILITIES_H__
#include <mach-o/loader.h>
#include <mach/thread_status.h>
/* Some #defines and structs that aren't defined in older SDKs */
#ifndef CPU_ARCH_ABI64
# define CPU_ARCH_ABI64 0x01000000
#endif
#ifndef CPU_TYPE_X86
# define CPU_TYPE_X86 CPU_TYPE_I386
#endif
#ifndef CPU_TYPE_POWERPC64
# define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
#endif
#ifndef LC_UUID
# define LC_UUID 0x1b /* the uuid */
#endif
// The uuid_command struct/swap routines were added during the 10.4 series.
// Their presence isn't guaranteed.
struct breakpad_uuid_command {
uint32_t cmd; /* LC_UUID */
uint32_t cmdsize; /* sizeof(struct uuid_command) */
uint8_t uuid[16]; /* the 128-bit uuid */
};
void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc);
void breakpad_swap_load_command(struct load_command *lc);
void breakpad_swap_dylib_command(struct dylib_command *dc);
// Older SDKs defines thread_state_data_t as an int[] instead
// of the natural_t[] it should be.
typedef natural_t breakpad_thread_state_data_t[THREAD_STATE_MAX];
void breakpad_swap_segment_command(struct segment_command *sc);
// The 64-bit swap routines were added during the 10.4 series, their
// presence isn't guaranteed.
void breakpad_swap_segment_command_64(struct segment_command_64 *sg);
void breakpad_swap_fat_header(struct fat_header *fh);
void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs);
void breakpad_swap_mach_header(struct mach_header *mh);
void breakpad_swap_mach_header_64(struct mach_header_64 *mh);
void breakpad_swap_section(struct section *s,
uint32_t nsects);
void breakpad_swap_section_64(struct section_64 *s,
uint32_t nsects);
#endif

View file

@ -0,0 +1,268 @@
// 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.
// macho_walker.cc: Iterate over the load commands in a mach-o file
//
// See macho_walker.h for documentation
//
// Author: Dan Waylonis
#include <assert.h>
#include <fcntl.h>
#include <mach-o/arch.h>
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include <string.h>
#include <unistd.h>
#include "common/mac/byteswap.h"
#include "common/mac/macho_walker.h"
#include "common/mac/macho_utilities.h"
namespace MacFileUtilities {
MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
void *context)
: file_(-1),
memory_(NULL),
memory_size_(0),
callback_(callback),
callback_context_(context),
current_header_(NULL),
current_header_size_(0),
current_header_offset_(0) {
file_ = open(path, O_RDONLY);
}
MachoWalker::MachoWalker(void *memory, size_t size,
LoadCommandCallback callback, void *context)
: file_(-1),
memory_(memory),
memory_size_(size),
callback_(callback),
callback_context_(context),
current_header_(NULL),
current_header_size_(0),
current_header_offset_(0) {
}
MachoWalker::~MachoWalker() {
if (file_ != -1)
close(file_);
}
bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
cpu_type_t valid_cpu_type = cpu_type;
cpu_subtype_t valid_cpu_subtype = cpu_subtype;
// if |cpu_type| is 0, use the native cpu type.
if (cpu_type == 0) {
const NXArchInfo *arch = NXGetLocalArchInfo();
assert(arch);
valid_cpu_type = arch->cputype;
valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE;
}
off_t offset;
if (FindHeader(valid_cpu_type, valid_cpu_subtype, offset)) {
if (cpu_type & CPU_ARCH_ABI64)
return WalkHeader64AtOffset(offset);
return WalkHeaderAtOffset(offset);
}
return false;
}
bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
if (memory_) {
if (offset < 0)
return false;
bool result = true;
if (offset + size > memory_size_) {
if (static_cast<size_t>(offset) >= memory_size_)
return false;
size = memory_size_ - static_cast<size_t>(offset);
result = false;
}
memcpy(buffer, static_cast<char *>(memory_) + offset, size);
return result;
} else {
return pread(file_, buffer, size, offset) == (ssize_t)size;
}
}
bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
if (current_header_) {
memcpy(header, current_header_, sizeof(mach_header_64));
*offset = current_header_offset_;
return true;
}
return false;
}
bool MachoWalker::FindHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
off_t &offset) {
// Read the magic bytes that's common amongst all mach-o files
uint32_t magic;
if (!ReadBytes(&magic, sizeof(magic), 0))
return false;
offset = sizeof(magic);
// Figure out what type of file we've got
bool is_fat = false;
if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
is_fat = true;
}
else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 &&
magic != MH_CIGAM_64) {
return false;
}
if (!is_fat) {
// If we don't have a fat header, check if the cpu type matches the single
// header
struct mach_header header;
if (!ReadBytes(&header, sizeof(header), 0))
return false;
if (magic == MH_CIGAM || magic == MH_CIGAM_64)
breakpad_swap_mach_header(&header);
if (cpu_type != header.cputype ||
(cpu_subtype != CPU_SUBTYPE_MULTIPLE &&
cpu_subtype != header.cpusubtype)) {
return false;
}
offset = 0;
return true;
} else {
// Read the fat header and find an appropriate architecture
offset = 0;
struct fat_header fat;
if (!ReadBytes(&fat, sizeof(fat), offset))
return false;
if (NXHostByteOrder() != NX_BigEndian)
breakpad_swap_fat_header(&fat);
offset += sizeof(fat);
// Search each architecture for the desired one
struct fat_arch arch;
for (uint32_t i = 0; i < fat.nfat_arch; ++i) {
if (!ReadBytes(&arch, sizeof(arch), offset))
return false;
if (NXHostByteOrder() != NX_BigEndian)
breakpad_swap_fat_arch(&arch, 1);
if (arch.cputype == cpu_type &&
(cpu_subtype == CPU_SUBTYPE_MULTIPLE ||
arch.cpusubtype == cpu_subtype)) {
offset = arch.offset;
return true;
}
offset += sizeof(arch);
}
}
return false;
}
bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
struct mach_header header;
if (!ReadBytes(&header, sizeof(header), offset))
return false;
bool swap = (header.magic == MH_CIGAM);
if (swap)
breakpad_swap_mach_header(&header);
// Copy the data into the mach_header_64 structure. Since the 32-bit and
// 64-bit only differ in the last field (reserved), this is safe to do.
struct mach_header_64 header64;
memcpy((void *)&header64, (const void *)&header, sizeof(header));
header64.reserved = 0;
current_header_ = &header64;
current_header_size_ = sizeof(header); // 32-bit, not 64-bit
current_header_offset_ = offset;
offset += current_header_size_;
bool result = WalkHeaderCore(offset, header.ncmds, swap);
current_header_ = NULL;
current_header_size_ = 0;
current_header_offset_ = 0;
return result;
}
bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
struct mach_header_64 header;
if (!ReadBytes(&header, sizeof(header), offset))
return false;
bool swap = (header.magic == MH_CIGAM_64);
if (swap)
breakpad_swap_mach_header_64(&header);
current_header_ = &header;
current_header_size_ = sizeof(header);
current_header_offset_ = offset;
offset += current_header_size_;
bool result = WalkHeaderCore(offset, header.ncmds, swap);
current_header_ = NULL;
current_header_size_ = 0;
current_header_offset_ = 0;
return result;
}
bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands,
bool swap) {
for (uint32_t i = 0; i < number_of_commands; ++i) {
struct load_command cmd;
if (!ReadBytes(&cmd, sizeof(cmd), offset))
return false;
if (swap)
breakpad_swap_load_command(&cmd);
// Call the user callback
if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_))
break;
offset += cmd.cmdsize;
}
return true;
}
} // namespace MacFileUtilities

View file

@ -0,0 +1,119 @@
// 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.
// macho_walker.h: Iterate over the load commands in a mach-o file
//
// Author: Dan Waylonis
#ifndef COMMON_MAC_MACHO_WALKER_H__
#define COMMON_MAC_MACHO_WALKER_H__
#include <mach/machine.h>
#include <mach-o/loader.h>
#include <sys/types.h>
namespace MacFileUtilities {
class MachoWalker {
public:
// A callback function executed when a new load command is read. If no
// further processing of load commands is desired, return false. Otherwise,
// return true.
// |cmd| is the current command, and |offset| is the location relative to the
// beginning of the file (not header) where the command was read. If |swap|
// is set, then any command data (other than the returned load_command) should
// be swapped when read
typedef bool (*LoadCommandCallback)(MachoWalker *walker, load_command *cmd,
off_t offset, bool swap, void *context);
MachoWalker(const char *path, LoadCommandCallback callback, void *context);
MachoWalker(void *memory, size_t size, LoadCommandCallback callback,
void *context);
~MachoWalker();
// Begin walking the header for |cpu_type| and |cpu_subtype|. If |cpu_type|
// is 0, then the native cpu type is used. Otherwise, accepted values are
// listed in /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or
// CPU_TYPE_POWERPC). If |cpu_subtype| is CPU_SUBTYPE_MULTIPLE, the match is
// only done on |cpu_type|.
// Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype|
// is not present in the file.
bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
// Read |size| bytes from the opened file at |offset| into |buffer|
bool ReadBytes(void *buffer, size_t size, off_t offset);
// Return the current header and header offset
bool CurrentHeader(struct mach_header_64 *header, off_t *offset);
private:
// Locate (if any) the header offset for |cpu_type| and return in |offset|.
// Return true if found, false otherwise.
bool FindHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
off_t &offset);
// Process an individual header starting at |offset| from the start of the
// file. Return true if successful, false otherwise.
bool WalkHeaderAtOffset(off_t offset);
bool WalkHeader64AtOffset(off_t offset);
// Bottleneck for walking the load commands
bool WalkHeaderCore(off_t offset, uint32_t number_of_commands, bool swap);
// File descriptor to the opened file
int file_;
// Memory location to read from.
void *memory_;
// Size of the memory segment we can read from.
size_t memory_size_;
// User specified callback & context
LoadCommandCallback callback_;
void *callback_context_;
// Current header, size, and offset. The mach_header_64 is used for both
// 32-bit and 64-bit headers because they only differ in their last field
// (reserved). By adding the |current_header_size_| and the
// |current_header_offset_|, you can determine the offset in the file just
// after the header.
struct mach_header_64 *current_header_;
unsigned long current_header_size_;
off_t current_header_offset_;
private:
MachoWalker(const MachoWalker &);
MachoWalker &operator=(const MachoWalker &);
};
} // namespace MacFileUtilities
#endif // COMMON_MAC_MACHO_WALKER_H__

View file

@ -0,0 +1,56 @@
// 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.
// Inline implementation of ScopedTaskSuspend, which suspends a Mach
// task for the duration of its scope.
#ifndef GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_
#define GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_
#include <mach/mach.h>
namespace google_breakpad {
class ScopedTaskSuspend {
public:
explicit ScopedTaskSuspend(mach_port_t target) : target_(target) {
task_suspend(target_);
}
~ScopedTaskSuspend() {
task_resume(target_);
}
private:
mach_port_t target_;
};
} // namespace google_breakpad
#endif // GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_

View file

@ -0,0 +1,84 @@
// 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.
#include "common/scoped_ptr.h"
#include "common/mac/string_utilities.h"
namespace MacStringUtils {
using google_breakpad::scoped_array;
std::string ConvertToString(CFStringRef str) {
CFIndex length = CFStringGetLength(str);
std::string result;
if (!length)
return result;
CFIndex maxUTF8Length =
CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
scoped_array<UInt8> buffer(new UInt8[maxUTF8Length + 1]);
CFIndex actualUTF8Length;
CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingUTF8, 0,
false, buffer.get(), maxUTF8Length, &actualUTF8Length);
buffer[actualUTF8Length] = 0;
result.assign((const char *)buffer.get());
return result;
}
unsigned int IntegerValueAtIndex(string &str, unsigned int idx) {
string digits("0123456789"), temp;
size_t start = 0;
size_t end;
size_t found = 0;
unsigned int result = 0;
for (; found <= idx; ++found) {
end = str.find_first_not_of(digits, start);
if (end == string::npos)
end = str.size();
temp = str.substr(start, end - start);
if (found == idx) {
result = atoi(temp.c_str());
}
start = str.find_first_of(digits, end + 1);
if (start == string::npos)
break;
}
return result;
}
} // namespace MacStringUtils

View file

@ -0,0 +1,52 @@
// 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.
// string_utilities.h: Utilities for strings for Mac platform
#ifndef COMMON_MAC_STRING_UTILITIES_H__
#define COMMON_MAC_STRING_UTILITIES_H__
#include <CoreFoundation/CoreFoundation.h>
#include <string>
namespace MacStringUtils {
using std::string;
// Convert a CoreFoundation string into a std::string
string ConvertToString(CFStringRef str);
// Return the idx'th decimal integer in str, separated by non-decimal-digits
// E.g., str = 10.4.8, idx = 1 -> 4
unsigned int IntegerValueAtIndex(string &str, unsigned int idx);
} // namespace MacStringUtils
#endif // COMMON_MAC_STRING_UTILITIES_H__

View file

@ -0,0 +1,251 @@
/*
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include <string.h>
#include "common/md5.h"
namespace google_breakpad {
#ifndef WORDS_BIGENDIAN
#define byteReverse(buf, len) /* Nothing */
#else
/*
* Note: this code is harmless on little-endian machines.
*/
static void byteReverse(unsigned char *buf, unsigned longs)
{
u32 t;
do {
t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(u32 *) buf = t;
buf += 4;
} while (--longs);
}
#endif
static void MD5Transform(u32 buf[4], u32 const in[16]);
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len)
{
u32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((u32 *) ctx->in)[14] = ctx->bits[0];
((u32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (u32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(u32 buf[4], u32 const in[16])
{
u32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
} // namespace google_breakpad

View file

@ -0,0 +1,27 @@
// Copyright 2007 Google Inc. All Rights Reserved.
// Author: liuli@google.com (Liu Li)
#ifndef COMMON_MD5_H__
#define COMMON_MD5_H__
#include <stdint.h>
namespace google_breakpad {
typedef uint32_t u32;
typedef uint8_t u8;
struct MD5Context {
u32 buf[4];
u32 bits[2];
u8 in[64];
};
void MD5Init(struct MD5Context *ctx);
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len);
void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
} // namespace google_breakpad
#endif // COMMON_MD5_H__

View file

@ -0,0 +1,212 @@
// 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 GOOGLE_BREAKPAD_COMMON_MEMORY_H_
#define GOOGLE_BREAKPAD_COMMON_MEMORY_H_
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <memory>
#include <vector>
#if defined(MEMORY_SANITIZER)
#include <sanitizer/msan_interface.h>
#endif
#ifdef __APPLE__
#define sys_mmap mmap
#define sys_mmap2 mmap
#define sys_munmap munmap
#define MAP_ANONYMOUS MAP_ANON
#else
#include "third_party/lss/linux_syscall_support.h"
#endif
namespace google_breakpad {
// This is very simple allocator which fetches pages from the kernel directly.
// Thus, it can be used even when the heap may be corrupted.
//
// There is no free operation. The pages are only freed when the object is
// destroyed.
class PageAllocator {
public:
PageAllocator()
: page_size_(getpagesize()),
last_(NULL),
current_page_(NULL),
page_offset_(0) {
}
~PageAllocator() {
FreeAll();
}
void *Alloc(size_t bytes) {
if (!bytes)
return NULL;
if (current_page_ && page_size_ - page_offset_ >= bytes) {
uint8_t *const ret = current_page_ + page_offset_;
page_offset_ += bytes;
if (page_offset_ == page_size_) {
page_offset_ = 0;
current_page_ = NULL;
}
return ret;
}
const size_t pages =
(bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_;
uint8_t *const ret = GetNPages(pages);
if (!ret)
return NULL;
page_offset_ =
(page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) %
page_size_;
current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL;
return ret + sizeof(PageHeader);
}
// Checks whether the page allocator owns the passed-in pointer.
// This method exists for testing pursposes only.
bool OwnsPointer(const void* p) {
for (PageHeader* header = last_; header; header = header->next) {
const char* current = reinterpret_cast<char*>(header);
if ((p >= current) && (p < current + header->num_pages * page_size_))
return true;
}
return false;
}
private:
uint8_t *GetNPages(size_t num_pages) {
#if defined(__x86_64__) || defined(__aarch64__) || defined(__aarch64__) || \
((defined(__mips__) && _MIPS_SIM == _ABI64))
void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#else
void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#endif
if (a == MAP_FAILED)
return NULL;
#if defined(MEMORY_SANITIZER)
// We need to indicate to MSan that memory allocated through sys_mmap is
// initialized, since linux_syscall_support.h doesn't have MSan hooks.
__msan_unpoison(a, page_size_ * num_pages);
#endif
struct PageHeader *header = reinterpret_cast<PageHeader*>(a);
header->next = last_;
header->num_pages = num_pages;
last_ = header;
return reinterpret_cast<uint8_t*>(a);
}
void FreeAll() {
PageHeader *next;
for (PageHeader *cur = last_; cur; cur = next) {
next = cur->next;
sys_munmap(cur, cur->num_pages * page_size_);
}
}
struct PageHeader {
PageHeader *next; // pointer to the start of the next set of pages.
size_t num_pages; // the number of pages in this set.
};
const size_t page_size_;
PageHeader *last_;
uint8_t *current_page_;
size_t page_offset_;
};
// Wrapper to use with STL containers
template <typename T>
struct PageStdAllocator : public std::allocator<T> {
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::size_type size_type;
explicit PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {}
template <class Other> PageStdAllocator(const PageStdAllocator<Other>& other)
: allocator_(other.allocator_) {}
inline pointer allocate(size_type n, const void* = 0) {
return static_cast<pointer>(allocator_.Alloc(sizeof(T) * n));
}
inline void deallocate(pointer, size_type) {
// The PageAllocator doesn't free.
}
template <typename U> struct rebind {
typedef PageStdAllocator<U> other;
};
private:
// Silly workaround for the gcc from Android's ndk (gcc 4.6), which will
// otherwise complain that `other.allocator_` is private in the constructor
// code.
template<typename Other> friend struct PageStdAllocator;
PageAllocator& allocator_;
};
// A wasteful vector is a std::vector, except that it allocates memory from a
// PageAllocator. It's wasteful because, when resizing, it always allocates a
// whole new array since the PageAllocator doesn't support realloc.
template<class T>
class wasteful_vector : public std::vector<T, PageStdAllocator<T> > {
public:
wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16)
: std::vector<T, PageStdAllocator<T> >(PageStdAllocator<T>(*allocator)) {
std::vector<T, PageStdAllocator<T> >::reserve(size_hint);
}
};
} // namespace google_breakpad
inline void* operator new(size_t nbytes,
google_breakpad::PageAllocator& allocator) {
return allocator.Alloc(nbytes);
}
#endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_

View file

@ -0,0 +1,155 @@
// 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.
#include <string.h>
#include "common/convert_UTF.h"
#include "common/scoped_ptr.h"
#include "common/string_conversion.h"
#include "common/using_std_string.h"
namespace google_breakpad {
using std::vector;
void UTF8ToUTF16(const char *in, vector<uint16_t> *out) {
size_t source_length = strlen(in);
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
const UTF8 *source_end_ptr = source_ptr + source_length;
// Erase the contents and zero fill to the expected size
out->clear();
out->insert(out->begin(), source_length, 0);
uint16_t *target_ptr = &(*out)[0];
uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t);
ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
// Resize to be the size of the # of converted characters + NULL
out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}
int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) {
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
const UTF8 *source_end_ptr = source_ptr + sizeof(char);
uint16_t *target_ptr = out;
uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t);
out[0] = out[1] = 0;
// Process one character at a time
while (1) {
ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
if (result == conversionOK)
return static_cast<int>(source_ptr - reinterpret_cast<const UTF8 *>(in));
// Add another character to the input stream and try again
source_ptr = reinterpret_cast<const UTF8 *>(in);
++source_end_ptr;
if (source_end_ptr > reinterpret_cast<const UTF8 *>(in) + in_length)
break;
}
return 0;
}
void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out) {
size_t source_length = wcslen(in);
const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in);
const UTF32 *source_end_ptr = source_ptr + source_length;
// Erase the contents and zero fill to the expected size
out->clear();
out->insert(out->begin(), source_length, 0);
uint16_t *target_ptr = &(*out)[0];
uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t);
ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
// Resize to be the size of the # of converted characters + NULL
out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}
void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]) {
const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(&in);
const UTF32 *source_end_ptr = source_ptr + 1;
uint16_t *target_ptr = out;
uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t);
out[0] = out[1] = 0;
ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
if (result != conversionOK) {
out[0] = out[1] = 0;
}
}
static inline uint16_t Swap(uint16_t value) {
return (value >> 8) | static_cast<uint16_t>(value << 8);
}
string UTF16ToUTF8(const vector<uint16_t> &in, bool swap) {
const UTF16 *source_ptr = &in[0];
scoped_array<uint16_t> source_buffer;
// If we're to swap, we need to make a local copy and swap each byte pair
if (swap) {
int idx = 0;
source_buffer.reset(new uint16_t[in.size()]);
UTF16 *source_buffer_ptr = source_buffer.get();
for (vector<uint16_t>::const_iterator it = in.begin();
it != in.end(); ++it, ++idx)
source_buffer_ptr[idx] = Swap(*it);
source_ptr = source_buffer.get();
}
// The maximum expansion would be 4x the size of the input string.
const UTF16 *source_end_ptr = source_ptr + in.size();
size_t target_capacity = in.size() * 4;
scoped_array<UTF8> target_buffer(new UTF8[target_capacity]);
UTF8 *target_ptr = target_buffer.get();
UTF8 *target_end_ptr = target_ptr + target_capacity;
ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
if (result == conversionOK) {
const char *targetPtr = reinterpret_cast<const char *>(target_buffer.get());
return targetPtr;
}
return "";
}
} // namespace google_breakpad

View file

@ -0,0 +1,68 @@
// 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.
// string_conversion.h: Conversion between different UTF-8/16/32 encodings.
#ifndef COMMON_STRING_CONVERSION_H__
#define COMMON_STRING_CONVERSION_H__
#include <string>
#include <vector>
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
namespace google_breakpad {
using std::vector;
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
// conversion failed, |out| will be zero length.
void UTF8ToUTF16(const char *in, vector<uint16_t> *out);
// Convert at least one character (up to a maximum of |in_length|) from |in|
// to UTF-16 into |out|. Return the number of characters consumed from |in|.
// Any unused characters in |out| will be initialized to 0. No memory will
// be allocated by this routine.
int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]);
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
// conversion failed, |out| will be zero length.
void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out);
// Convert |in| to UTF-16 into |out|. Any unused characters in |out| will be
// initialized to 0. No memory will be allocated by this routine.
void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]);
// Convert |in| to UTF-8. If |swap| is true, swap bytes before converting.
string UTF16ToUTF8(const vector<uint16_t> &in, bool swap);
} // namespace google_breakpad
#endif // COMMON_STRING_CONVERSION_H__

View file

@ -0,0 +1,65 @@
// -*- mode: C++ -*-
// 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.
// Original author: Ivan Penkov
// using_std_string.h: Allows building this code in environments where
// global string (::string) exists.
//
// The problem:
// -------------
// Let's say you want to build this code in an environment where a global
// string type is defined (i.e. ::string). Now, let's suppose that ::string
// is different that std::string and you'd like to have the option to easily
// choose between the two string types. Ideally you'd like to control which
// string type is chosen by simply #defining an identifier.
//
// The solution:
// -------------
// #define HAS_GLOBAL_STRING somewhere in a global header file and then
// globally replace std::string with string. Then include this header
// file everywhere where string is used. If you want to revert back to
// using std::string, simply remove the #define (HAS_GLOBAL_STRING).
#ifndef THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_
#define THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_
#ifdef HAS_GLOBAL_STRING
typedef ::string google_breakpad_string;
#else
using std::string;
typedef std::string google_breakpad_string;
#endif
// Inicates that type google_breakpad_string is defined
#define HAS_GOOGLE_BREAKPAD_STRING
#endif // THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_

View file

@ -0,0 +1,107 @@
// Copyright (c) 2007, 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. */
// minidump_size.h: Provides a C++ template for programmatic access to
// the sizes of various types defined in minidump_format.h.
//
// Author: Mark Mentovai
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__
#include <sys/types.h>
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
template<typename T>
class minidump_size {
public:
static size_t size() { return sizeof(T); }
};
// Explicit specializations for variable-length types. The size returned
// for these should be the size for an object without its variable-length
// section.
template<>
class minidump_size<MDString> {
public:
static size_t size() { return MDString_minsize; }
};
template<>
class minidump_size<MDRawThreadList> {
public:
static size_t size() { return MDRawThreadList_minsize; }
};
template<>
class minidump_size<MDCVInfoPDB20> {
public:
static size_t size() { return MDCVInfoPDB20_minsize; }
};
template<>
class minidump_size<MDCVInfoPDB70> {
public:
static size_t size() { return MDCVInfoPDB70_minsize; }
};
template<>
class minidump_size<MDImageDebugMisc> {
public:
static size_t size() { return MDImageDebugMisc_minsize; }
};
template<>
class minidump_size<MDRawModuleList> {
public:
static size_t size() { return MDRawModuleList_minsize; }
};
template<>
class minidump_size<MDRawMemoryList> {
public:
static size_t size() { return MDRawMemoryList_minsize; }
};
// Explicit specialization for MDRawModule, for which sizeof may include
// tail-padding on some architectures but not others.
template<>
class minidump_size<MDRawModule> {
public:
static size_t size() { return MD_MODULE_SIZE; }
};
} // namespace google_breakpad
#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__

247
Telegram/ThirdParty/minizip/ioapi.c vendored Normal file
View file

@ -0,0 +1,247 @@
/* ioapi.h -- IO base function header for compress/uncompress .zip
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
*/
#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS)))
#define _CRT_SECURE_NO_WARNINGS
#endif
#if defined(__APPLE__) || defined(IOAPI_NO_64)
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
#define FTELLO_FUNC(stream) ftello(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
#else
#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
#define FTELLO_FUNC(stream) ftello64(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
#endif
#include "ioapi.h"
voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
{
if (pfilefunc->zfile_func64.zopen64_file != NULL)
return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
else
{
return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
}
}
long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
{
if (pfilefunc->zfile_func64.zseek64_file != NULL)
return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
else
{
uLong offsetTruncated = (uLong)offset;
if (offsetTruncated != offset)
return -1;
else
return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
}
}
ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
{
if (pfilefunc->zfile_func64.zseek64_file != NULL)
return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
else
{
uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
if ((tell_uLong) == MAXU32)
return (ZPOS64_T)-1;
else
return tell_uLong;
}
}
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
{
p_filefunc64_32->zfile_func64.zopen64_file = NULL;
p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
p_filefunc64_32->zfile_func64.ztell64_file = NULL;
p_filefunc64_32->zfile_func64.zseek64_file = NULL;
p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
}
static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));
static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));
static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));
static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode)
{
FILE* file = NULL;
const char* mode_fopen = NULL;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
mode_fopen = "rb";
else
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
mode_fopen = "r+b";
else
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
mode_fopen = "wb";
if ((filename!=NULL) && (mode_fopen != NULL))
file = fopen(filename, mode_fopen);
return file;
}
static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode)
{
FILE* file = NULL;
const char* mode_fopen = NULL;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
mode_fopen = "rb";
else
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
mode_fopen = "r+b";
else
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
mode_fopen = "wb";
if ((filename!=NULL) && (mode_fopen != NULL))
file = FOPEN_FUNC((const char*)filename, mode_fopen);
return file;
}
static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
{
uLong ret;
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
return ret;
}
static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size)
{
uLong ret;
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
return ret;
}
static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)
{
long ret;
ret = ftell((FILE *)stream);
return ret;
}
static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
{
ZPOS64_T ret;
ret = FTELLO_FUNC((FILE *)stream);
return ret;
}
static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin)
{
int fseek_origin=0;
long ret;
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR :
fseek_origin = SEEK_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END :
fseek_origin = SEEK_END;
break;
case ZLIB_FILEFUNC_SEEK_SET :
fseek_origin = SEEK_SET;
break;
default: return -1;
}
ret = 0;
if (fseek((FILE *)stream, offset, fseek_origin) != 0)
ret = -1;
return ret;
}
static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
{
int fseek_origin=0;
long ret;
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR :
fseek_origin = SEEK_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END :
fseek_origin = SEEK_END;
break;
case ZLIB_FILEFUNC_SEEK_SET :
fseek_origin = SEEK_SET;
break;
default: return -1;
}
ret = 0;
if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0)
ret = -1;
return ret;
}
static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
{
int ret;
ret = fclose((FILE *)stream);
return ret;
}
static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream)
{
int ret;
ret = ferror((FILE *)stream);
return ret;
}
void fill_fopen_filefunc (pzlib_filefunc_def)
zlib_filefunc_def* pzlib_filefunc_def;
{
pzlib_filefunc_def->zopen_file = fopen_file_func;
pzlib_filefunc_def->zread_file = fread_file_func;
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
pzlib_filefunc_def->ztell_file = ftell_file_func;
pzlib_filefunc_def->zseek_file = fseek_file_func;
pzlib_filefunc_def->zclose_file = fclose_file_func;
pzlib_filefunc_def->zerror_file = ferror_file_func;
pzlib_filefunc_def->opaque = NULL;
}
void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def)
{
pzlib_filefunc_def->zopen64_file = fopen64_file_func;
pzlib_filefunc_def->zread_file = fread_file_func;
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
pzlib_filefunc_def->ztell64_file = ftell64_file_func;
pzlib_filefunc_def->zseek64_file = fseek64_file_func;
pzlib_filefunc_def->zclose_file = fclose_file_func;
pzlib_filefunc_def->zerror_file = ferror_file_func;
pzlib_filefunc_def->opaque = NULL;
}

View file

@ -1411,7 +1411,7 @@ extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned in
if (zi->in_opened_file_inzip == 0)
return ZIP_PARAMERROR;
zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len);
zi->ci.crc32 = crc32(zi->ci.crc32,(const Bytef *)buf,(uInt)len);
#ifdef HAVE_BZIP2
if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw))