diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp index 121dc35a6..086c7b461 100644 --- a/Telegram/SourceFiles/logs.cpp +++ b/Telegram/SourceFiles/logs.cpp @@ -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]); diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index 58a1c065b..8a97b226e 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -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 +#define __STDC_FORMAT_MACROS // fix breakpad for mac + +#ifdef __cplusplus #include #include @@ -52,12 +54,18 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org extern "C" { +#endif + +#include "zip.h" + #include #include #include #include #include +#ifdef __cplusplus + } #include "types.h" @@ -79,3 +87,5 @@ extern "C" { #include "gui/flatlabel.h" #include "app.h" + +#endif diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index 77158620e..d4ae8fc39 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -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); diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj index 4f7b75747..ea1644d6d 100644 --- a/Telegram/Telegram.xcodeproj/project.pbxproj +++ b/Telegram/Telegram.xcodeproj/project.pbxproj @@ -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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 071AD8DD1C5E912C008C9E90 /* crash_generation_server.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crash_generation_server.cc; sourceTree = ""; }; + 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 = ""; }; + 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 = ""; }; 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 = ""; }; + 071AD8691C5E8504008C9E90 /* ThirdParty */ = { + isa = PBXGroup; + children = ( + 071AD8701C5E8546008C9E90 /* breakpad */, + 071AD86A1C5E8522008C9E90 /* minizip */, + ); + name = ThirdParty; + sourceTree = ""; + }; + 071AD86A1C5E8522008C9E90 /* minizip */ = { + isa = PBXGroup; + children = ( + 071AD86B1C5E8536008C9E90 /* crypt.h */, + 071AD86C1C5E8536008C9E90 /* ioapi.h */, + 071AD8F71C5E99D6008C9E90 /* ioapi.c */, + 071AD86E1C5E8536008C9E90 /* zip.h */, + 071AD8D11C5E8E6D008C9E90 /* zip.c */, + ); + name = minizip; + sourceTree = ""; + }; + 071AD8701C5E8546008C9E90 /* breakpad */ = { + isa = PBXGroup; + children = ( + 071AD8931C5E89BE008C9E90 /* google_breakpad */, + 071AD87E1C5E8792008C9E90 /* common */, + 071AD8711C5E8569008C9E90 /* client */, + ); + name = breakpad; + sourceTree = ""; + }; + 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 = ""; + }; + 071AD8721C5E8575008C9E90 /* mac */ = { + isa = PBXGroup; + children = ( + 071AD8771C5E8672008C9E90 /* crash_generation */, + 071AD8731C5E8579008C9E90 /* handler */, + ); + name = mac; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 071AD8931C5E89BE008C9E90 /* google_breakpad */ = { + isa = PBXGroup; + children = ( + 071AD8941C5E89C4008C9E90 /* common */, + ); + name = google_breakpad; + sourceTree = ""; + }; + 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 = ""; + }; + 071AD8B01C5E8B1B008C9E90 /* linux */ = { + isa = PBXGroup; + children = ( + 071AD8B11C5E8B23008C9E90 /* linux_libc_support.h */, + ); + name = linux; + sourceTree = ""; + }; 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; diff --git a/Telegram/ThirdParty/breakpad/client/mac/crash_generation/client_info.h b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/client_info.h new file mode 100644 index 000000000..a3a95dcac --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/client_info.h @@ -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_ diff --git a/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_client.cc b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_client.cc new file mode 100644 index 000000000..ceeb3b32a --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_client.cc @@ -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 diff --git a/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_client.h b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_client.h new file mode 100644 index 000000000..527f577a5 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_client.h @@ -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_ diff --git a/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_server.cc b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_server.cc new file mode 100644 index 000000000..451e8d9c2 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_server.cc @@ -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 + +#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(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 diff --git a/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_server.h b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_server.h new file mode 100644 index 000000000..85bd5b5e3 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/crash_generation/crash_generation_server.h @@ -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 + +#include + +#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_ diff --git a/Telegram/ThirdParty/breakpad/client/mac/handler/breakpad_nlist_64.cc b/Telegram/ThirdParty/breakpad/client/mac/handler/breakpad_nlist_64.cc new file mode 100644 index 000000000..3492b823d --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/handler/breakpad_nlist_64.cc @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Stuff lifted from and 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 +struct MachBits {}; + +typedef struct nlist nlist32; +typedef struct nlist_64 nlist64; + +template<> +struct MachBits { + typedef mach_header mach_header_type; + typedef uint32_t word_type; + static const uint32_t magic = MH_MAGIC; +}; + +template<> +struct MachBits { + typedef mach_header_64 mach_header_type; + typedef uint64_t word_type; + static const uint32_t magic = MH_MAGIC_64; +}; + +template +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 +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 +int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, + cpu_type_t cpu_type) { + typedef typename MachBits::mach_header_type mach_header_type; + typedef typename MachBits::word_type word_type; + + const uint32_t magic = MachBits::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; +} diff --git a/Telegram/ThirdParty/breakpad/client/mac/handler/breakpad_nlist_64.h b/Telegram/ThirdParty/breakpad/client/mac/handler/breakpad_nlist_64.h new file mode 100644 index 000000000..1d2c63913 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/handler/breakpad_nlist_64.h @@ -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 + +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__ */ diff --git a/Telegram/ThirdParty/breakpad/client/mac/handler/dynamic_images.cc b/Telegram/ThirdParty/breakpad/client/mac/handler/dynamic_images.cc new file mode 100644 index 000000000..cdba6df4a --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/handler/dynamic_images.cc @@ -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 + #include + #include +} + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "breakpad_nlist_64.h" + +#if !TARGET_OS_IPHONE +#include + +#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 +// 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(&submap_info); + + kern_return_t result = + mach_vm_region_recurse(target_task, + ®ion_base, + ®ion_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, + ®ion_base2, + ®ion_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 bytes; + if (ReadTaskMemory(target_task, address, (size_t)size_to_read, bytes) != + KERN_SUCCESS) + return string(); + + return string(reinterpret_cast(&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 &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(&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 +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(&image.header_[0]); + + if(header->magic != MachBits::magic) { + return false; + } + + const struct load_command *cmd = + reinterpret_cast(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(cmd); + + if (!strcmp(seg->segname, "__TEXT")) { + image.vmaddr_ = static_cast(seg->vmaddr); + image.vmsize_ = static_cast(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(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 + (reinterpret_cast(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(*this); + else + FindTextSection(*this); +} + +//============================================================================== +// The helper function template abstracts the 32/64-bit differences. +template +uint32_t GetFileTypeFromHeader(DynamicImage& image) { + typedef typename MachBits::mach_header_type mach_header_type; + + const mach_header_type* header = + reinterpret_cast(&image.header_[0]); + return header->filetype; +} + +uint32_t DynamicImage::GetFileType() { + if (Is64Bit()) + return GetFileTypeFromHeader(*this); + + return GetFileTypeFromHeader(*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 +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(imageSymbolName, dyldPath, cpu_type_); + return LookupSymbol(imageSymbolName, dyldPath, cpu_type_); + } +} + +//============================================================================== +// This code was written using dyld_debug.c (from Darwin) as a guide. + +template +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 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_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 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_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 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_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(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::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(*this, imageList); + else + ReadImageInfo(*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(mibLen), &cpu_type, &cpuTypeSize, 0, 0); + return cpu_type; + } + + return GetNativeCPUType(); +} + +} // namespace google_breakpad diff --git a/Telegram/ThirdParty/breakpad/client/mac/handler/dynamic_images.h b/Telegram/ThirdParty/breakpad/client/mac/handler/dynamic_images.h new file mode 100644 index 000000000..65147900b --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/handler/dynamic_images.h @@ -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 +#include +#include +#include + +#include +#include + +#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 +bool FindTextSection(DynamicImage& image); + +template +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 + friend bool FindTextSection(DynamicImage& image); + template + friend uint32_t GetFileTypeFromHeader(DynamicImage& image); + + // Initializes vmaddr_, vmsize_, and slide_ + void CalculateMemoryAndVersionInfo(); + + const vector 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(this)->p) + < (*const_cast(inRef).p); + } + + bool operator==(const DynamicImageRef &inInfo) const { + return (*const_cast(this)->p).GetLoadAddress() == + (*const_cast(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 +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(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 + 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 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 &bytes); + +} // namespace google_breakpad + +#endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ diff --git a/Telegram/ThirdParty/breakpad/client/mac/handler/mach_vm_compat.h b/Telegram/ThirdParty/breakpad/client/mac/handler/mach_vm_compat.h new file mode 100644 index 000000000..9e9028b92 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/handler/mach_vm_compat.h @@ -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 + +// On iOS 5 and higher, mach/mach_vm.h is not supported. Use the corresponding +// vm_map functions instead. +#if TARGET_OS_IPHONE +#include +#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 +#endif // TARGET_OS_IPHONE + +#endif // CLIENT_MAC_GENERATOR_MACH_VM_COMPAT_H_ diff --git a/Telegram/ThirdParty/breakpad/client/mac/handler/minidump_generator.cc b/Telegram/ThirdParty/breakpad/client/mac/handler/minidump_generator.cc new file mode 100644 index 000000000..7d6e81dbb --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/handler/minidump_generator.cc @@ -0,0 +1,1591 @@ +// 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "client/mac/handler/minidump_generator.h" + +#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) +#include +#endif +#ifdef HAS_PPC_SUPPORT +#include +#endif +#ifdef HAS_X86_SUPPORT +#include +#endif + +#include "client/minidump_file_writer-inl.h" +#include "common/mac/file_id.h" +#include "common/mac/macho_id.h" +#include "common/mac/string_utilities.h" + +using MacStringUtils::ConvertToString; +using MacStringUtils::IntegerValueAtIndex; + +namespace google_breakpad { + +#if defined(__LP64__) && __LP64__ +#define LC_SEGMENT_ARCH LC_SEGMENT_64 +#else +#define LC_SEGMENT_ARCH LC_SEGMENT +#endif + +// constructor when generating from within the crashed process +MinidumpGenerator::MinidumpGenerator() + : writer_(), + exception_type_(0), + exception_code_(0), + exception_subcode_(0), + exception_thread_(0), + crashing_task_(mach_task_self()), + handler_thread_(mach_thread_self()), + cpu_type_(DynamicImages::GetNativeCPUType()), + task_context_(NULL), + dynamic_images_(NULL), + memory_blocks_(&allocator_) { + GatherSystemInformation(); +} + +// constructor when generating from a different process than the +// crashed process +MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, + mach_port_t handler_thread) + : writer_(), + exception_type_(0), + exception_code_(0), + exception_subcode_(0), + exception_thread_(0), + crashing_task_(crashing_task), + handler_thread_(handler_thread), + cpu_type_(DynamicImages::GetNativeCPUType()), + task_context_(NULL), + dynamic_images_(NULL), + memory_blocks_(&allocator_) { + if (crashing_task != mach_task_self()) { + dynamic_images_ = new DynamicImages(crashing_task_); + cpu_type_ = dynamic_images_->GetCPUType(); + } else { + dynamic_images_ = NULL; + cpu_type_ = DynamicImages::GetNativeCPUType(); + } + + GatherSystemInformation(); +} + +MinidumpGenerator::~MinidumpGenerator() { + delete dynamic_images_; +} + +char MinidumpGenerator::build_string_[16]; +int MinidumpGenerator::os_major_version_ = 0; +int MinidumpGenerator::os_minor_version_ = 0; +int MinidumpGenerator::os_build_number_ = 0; + +// static +void MinidumpGenerator::GatherSystemInformation() { + // If this is non-zero, then we've already gathered the information + if (os_major_version_) + return; + + // This code extracts the version and build information from the OS + CFStringRef vers_path = + CFSTR("/System/Library/CoreServices/SystemVersion.plist"); + CFURLRef sys_vers = + CFURLCreateWithFileSystemPath(NULL, + vers_path, + kCFURLPOSIXPathStyle, + false); + CFReadStreamRef read_stream = CFReadStreamCreateWithFile(NULL, sys_vers); + CFRelease(sys_vers); + if (!read_stream) { + return; + } + if (!CFReadStreamOpen(read_stream)) { + CFRelease(read_stream); + return; + } + CFDataRef data = NULL; + CFIndex num_bytes_read = 0; + const UInt8 *data_bytes = + CFReadStreamGetBuffer(read_stream, 0, &num_bytes_read); + if (data_bytes) { + data = CFDataCreate(NULL, data_bytes, num_bytes_read); + } + CFReadStreamClose(read_stream); + CFRelease(read_stream); + if (!data) { + return; + } + CFDictionaryRef list = static_cast + (CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, + NULL)); + CFRelease(data); + if (!list) { + return; + } + CFStringRef build_version = static_cast + (CFDictionaryGetValue(list, CFSTR("ProductBuildVersion"))); + CFStringRef product_version = static_cast + (CFDictionaryGetValue(list, CFSTR("ProductVersion"))); + string build_str = ConvertToString(build_version); + string product_str = ConvertToString(product_version); + + CFRelease(list); + + strlcpy(build_string_, build_str.c_str(), sizeof(build_string_)); + + // Parse the string that looks like "10.4.8" + os_major_version_ = IntegerValueAtIndex(product_str, 0); + os_minor_version_ = IntegerValueAtIndex(product_str, 1); + os_build_number_ = IntegerValueAtIndex(product_str, 2); +} + +void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) { + task_context_ = task_context; +} + +string MinidumpGenerator::UniqueNameInDirectory(const string &dir, + string *unique_name) { + CFUUIDRef uuid = CFUUIDCreate(NULL); + CFStringRef uuid_cfstr = CFUUIDCreateString(NULL, uuid); + CFRelease(uuid); + string file_name(ConvertToString(uuid_cfstr)); + CFRelease(uuid_cfstr); + string path(dir); + + // Ensure that the directory (if non-empty) has a trailing slash so that + // we can append the file name and have a valid pathname. + if (!dir.empty()) { + if (dir.at(dir.size() - 1) != '/') + path.append(1, '/'); + } + + path.append(file_name); + path.append(".dmp"); + + if (unique_name) + *unique_name = file_name; + + return path; +} + +bool MinidumpGenerator::Write(const char *path) { + WriteStreamFN writers[] = { + &MinidumpGenerator::WriteThreadListStream, + &MinidumpGenerator::WriteMemoryListStream, + &MinidumpGenerator::WriteSystemInfoStream, + &MinidumpGenerator::WriteModuleListStream, + &MinidumpGenerator::WriteMiscInfoStream, + &MinidumpGenerator::WriteBreakpadInfoStream, + // Exception stream needs to be the last entry in this array as it may + // be omitted in the case where the minidump is written without an + // exception. + &MinidumpGenerator::WriteExceptionStream, + }; + bool result = false; + + // If opening was successful, create the header, directory, and call each + // writer. The destructor for the TypedMDRVAs will cause the data to be + // flushed. The destructor for the MinidumpFileWriter will close the file. + if (writer_.Open(path)) { + TypedMDRVA header(&writer_); + TypedMDRVA dir(&writer_); + + if (!header.Allocate()) + return false; + + int writer_count = static_cast(sizeof(writers) / sizeof(writers[0])); + + // If we don't have exception information, don't write out the + // exception stream + if (!exception_thread_ && !exception_type_) + --writer_count; + + // Add space for all writers + if (!dir.AllocateArray(writer_count)) + return false; + + MDRawHeader *header_ptr = header.get(); + header_ptr->signature = MD_HEADER_SIGNATURE; + header_ptr->version = MD_HEADER_VERSION; + time(reinterpret_cast(&(header_ptr->time_date_stamp))); + header_ptr->stream_count = writer_count; + header_ptr->stream_directory_rva = dir.position(); + + MDRawDirectory local_dir; + result = true; + for (int i = 0; (result) && (i < writer_count); ++i) { + result = (this->*writers[i])(&local_dir); + + if (result) + dir.CopyIndex(i, &local_dir); + } + } + return result; +} + +size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) { + mach_vm_address_t stack_region_base = start_addr; + mach_vm_size_t stack_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; + + vm_region_recurse_info_t region_info; + region_info = reinterpret_cast(&submap_info); + + if (start_addr == 0) { + return 0; + } + + kern_return_t result = + mach_vm_region_recurse(crashing_task_, &stack_region_base, + &stack_region_size, &nesting_level, + region_info, &info_count); + + if (result != KERN_SUCCESS || start_addr < stack_region_base) { + // Failure or stack corruption, since mach_vm_region had to go + // higher in the process address space to find a valid region. + return 0; + } + + unsigned int tag = submap_info.user_tag; + + // If the user tag is VM_MEMORY_STACK, look for more readable regions with + // the same tag placed immediately above the computed stack region. Under + // some circumstances, the stack for thread 0 winds up broken up into + // multiple distinct abutting regions. This can happen for several reasons, + // including user code that calls setrlimit(RLIMIT_STACK, ...) or changes + // the access on stack pages by calling mprotect. + if (tag == VM_MEMORY_STACK) { + while (true) { + mach_vm_address_t next_region_base = stack_region_base + + stack_region_size; + mach_vm_address_t proposed_next_region_base = next_region_base; + mach_vm_size_t next_region_size; + nesting_level = 0; + info_count = VM_REGION_SUBMAP_INFO_COUNT_64; + result = mach_vm_region_recurse(crashing_task_, &next_region_base, + &next_region_size, &nesting_level, + region_info, &info_count); + if (result != KERN_SUCCESS || + next_region_base != proposed_next_region_base || + submap_info.user_tag != tag || + (submap_info.protection & VM_PROT_READ) == 0) { + break; + } + + stack_region_size += next_region_size; + } + } + + return stack_region_base + stack_region_size - start_addr; +} + +bool MinidumpGenerator::WriteStackFromStartAddress( + mach_vm_address_t start_addr, + MDMemoryDescriptor *stack_location) { + UntypedMDRVA memory(&writer_); + + bool result = false; + size_t size = CalculateStackSize(start_addr); + + if (size == 0) { + // In some situations the stack address for the thread can come back 0. + // In these cases we skip over the threads in question and stuff the + // stack with a clearly borked value. + start_addr = 0xDEADBEEF; + size = 16; + if (!memory.Allocate(size)) + return false; + + unsigned long long dummy_stack[2]; // Fill dummy stack with 16 bytes of + // junk. + dummy_stack[0] = 0xDEADBEEF; + dummy_stack[1] = 0xDEADBEEF; + + result = memory.Copy(dummy_stack, size); + } else { + + if (!memory.Allocate(size)) + return false; + + if (dynamic_images_) { + vector stack_memory; + if (ReadTaskMemory(crashing_task_, + start_addr, + size, + stack_memory) != KERN_SUCCESS) { + return false; + } + + result = memory.Copy(&stack_memory[0], size); + } else { + result = memory.Copy(reinterpret_cast(start_addr), size); + } + } + + stack_location->start_of_memory_range = start_addr; + stack_location->memory = memory.location(); + + return result; +} + +bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + return WriteStackARM(state, stack_location); +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + return WriteStackARM64(state, stack_location); +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + return WriteStackPPC(state, stack_location); + case CPU_TYPE_POWERPC64: + return WriteStackPPC64(state, stack_location); +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + return WriteStackX86(state, stack_location); + case CPU_TYPE_X86_64: + return WriteStackX86_64(state, stack_location); +#endif + default: + return false; + } +} + +bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) { + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + return WriteContextARM(state, register_location); +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + return WriteContextARM64(state, register_location); +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + return WriteContextPPC(state, register_location); + case CPU_TYPE_POWERPC64: + return WriteContextPPC64(state, register_location); +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + return WriteContextX86(state, register_location); + case CPU_TYPE_X86_64: + return WriteContextX86_64(state, register_location); +#endif + default: + return false; + } +} + +uint64_t MinidumpGenerator::CurrentPCForStack( + breakpad_thread_state_data_t state) { + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + return CurrentPCForStackARM(state); +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + return CurrentPCForStackARM64(state); +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + return CurrentPCForStackPPC(state); + case CPU_TYPE_POWERPC64: + return CurrentPCForStackPPC64(state); +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + return CurrentPCForStackX86(state); + case CPU_TYPE_X86_64: + return CurrentPCForStackX86_64(state); +#endif + default: + assert(0 && "Unknown CPU type!"); + return 0; + } +} + +#ifdef HAS_ARM_SUPPORT +bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + arm_thread_state_t *machine_state = + reinterpret_cast(state); + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) { + arm_thread_state_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, pc); +} + +bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) +{ + TypedMDRVA context(&writer_); + arm_thread_state_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextARM *context_ptr = context.get(); + context_ptr->context_flags = MD_CONTEXT_ARM_FULL; + +#define AddGPR(a) context_ptr->iregs[a] = REGISTER_FROM_THREADSTATE(machine_state, r[a]) + + context_ptr->iregs[13] = REGISTER_FROM_THREADSTATE(machine_state, sp); + context_ptr->iregs[14] = REGISTER_FROM_THREADSTATE(machine_state, lr); + context_ptr->iregs[15] = REGISTER_FROM_THREADSTATE(machine_state, pc); + context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr); + + AddGPR(0); + AddGPR(1); + AddGPR(2); + AddGPR(3); + AddGPR(4); + AddGPR(5); + AddGPR(6); + AddGPR(7); + AddGPR(8); + AddGPR(9); + AddGPR(10); + AddGPR(11); + AddGPR(12); +#undef AddGPR + + return true; +} +#endif + +#ifdef HAS_ARM64_SUPPORT +bool MinidumpGenerator::WriteStackARM64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + arm_thread_state64_t *machine_state = + reinterpret_cast(state); + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackARM64(breakpad_thread_state_data_t state) { + arm_thread_state64_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, pc); +} + +bool +MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) +{ + TypedMDRVA context(&writer_); + arm_thread_state64_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextARM64 *context_ptr = context.get(); + context_ptr->context_flags = MD_CONTEXT_ARM64_FULL; + +#define AddGPR(a) context_ptr->iregs[a] = \ + REGISTER_FROM_THREADSTATE(machine_state, x[a]) + + context_ptr->iregs[29] = REGISTER_FROM_THREADSTATE(machine_state, fp); + context_ptr->iregs[30] = REGISTER_FROM_THREADSTATE(machine_state, lr); + context_ptr->iregs[31] = REGISTER_FROM_THREADSTATE(machine_state, sp); + context_ptr->iregs[32] = REGISTER_FROM_THREADSTATE(machine_state, pc); + context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr); + + AddGPR(0); + AddGPR(1); + AddGPR(2); + AddGPR(3); + AddGPR(4); + AddGPR(5); + AddGPR(6); + AddGPR(7); + AddGPR(8); + AddGPR(9); + AddGPR(10); + AddGPR(11); + AddGPR(12); + AddGPR(13); + AddGPR(14); + AddGPR(15); + AddGPR(16); + AddGPR(17); + AddGPR(18); + AddGPR(19); + AddGPR(20); + AddGPR(21); + AddGPR(22); + AddGPR(23); + AddGPR(24); + AddGPR(25); + AddGPR(26); + AddGPR(27); + AddGPR(28); +#undef AddGPR + + return true; +} +#endif + +#ifdef HAS_PCC_SUPPORT +bool MinidumpGenerator::WriteStackPPC(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + ppc_thread_state_t *machine_state = + reinterpret_cast(state); + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + ppc_thread_state64_t *machine_state = + reinterpret_cast(state); + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) { + ppc_thread_state_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, srr0); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) { + ppc_thread_state64_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, srr0); +} + +bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) +{ + TypedMDRVA context(&writer_); + ppc_thread_state_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextPPC *context_ptr = context.get(); + context_ptr->context_flags = MD_CONTEXT_PPC_BASE; + +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, a)) +#define AddGPR(a) context_ptr->gpr[a] = \ + static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, r ## a) + + AddReg(srr0); + AddReg(cr); + AddReg(xer); + AddReg(ctr); + AddReg(lr); + AddReg(vrsave); + + AddGPR(0); + AddGPR(1); + AddGPR(2); + AddGPR(3); + AddGPR(4); + AddGPR(5); + AddGPR(6); + AddGPR(7); + AddGPR(8); + AddGPR(9); + AddGPR(10); + AddGPR(11); + AddGPR(12); + AddGPR(13); + AddGPR(14); + AddGPR(15); + AddGPR(16); + AddGPR(17); + AddGPR(18); + AddGPR(19); + AddGPR(20); + AddGPR(21); + AddGPR(22); + AddGPR(23); + AddGPR(24); + AddGPR(25); + AddGPR(26); + AddGPR(27); + AddGPR(28); + AddGPR(29); + AddGPR(30); + AddGPR(31); + AddReg(mq); +#undef AddReg +#undef AddGPR + + return true; +} + +bool MinidumpGenerator::WriteContextPPC64( + breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) { + TypedMDRVA context(&writer_); + ppc_thread_state64_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextPPC64 *context_ptr = context.get(); + context_ptr->context_flags = MD_CONTEXT_PPC_BASE; + +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, a)) +#define AddGPR(a) context_ptr->gpr[a] = \ + static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, r ## a) + + AddReg(srr0); + AddReg(cr); + AddReg(xer); + AddReg(ctr); + AddReg(lr); + AddReg(vrsave); + + AddGPR(0); + AddGPR(1); + AddGPR(2); + AddGPR(3); + AddGPR(4); + AddGPR(5); + AddGPR(6); + AddGPR(7); + AddGPR(8); + AddGPR(9); + AddGPR(10); + AddGPR(11); + AddGPR(12); + AddGPR(13); + AddGPR(14); + AddGPR(15); + AddGPR(16); + AddGPR(17); + AddGPR(18); + AddGPR(19); + AddGPR(20); + AddGPR(21); + AddGPR(22); + AddGPR(23); + AddGPR(24); + AddGPR(25); + AddGPR(26); + AddGPR(27); + AddGPR(28); + AddGPR(29); + AddGPR(30); + AddGPR(31); +#undef AddReg +#undef AddGPR + + return true; +} + +#endif + +#ifdef HAS_X86_SUPPORT +bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + i386_thread_state_t *machine_state = + reinterpret_cast(state); + + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + x86_thread_state64_t *machine_state = + reinterpret_cast(state); + + mach_vm_address_t start_addr = static_cast( + REGISTER_FROM_THREADSTATE(machine_state, rsp)); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) { + i386_thread_state_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, eip); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) { + x86_thread_state64_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, rip); +} + +bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) +{ + TypedMDRVA context(&writer_); + i386_thread_state_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextX86 *context_ptr = context.get(); + +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, a)) + + context_ptr->context_flags = MD_CONTEXT_X86; + AddReg(eax); + AddReg(ebx); + AddReg(ecx); + AddReg(edx); + AddReg(esi); + AddReg(edi); + AddReg(ebp); + AddReg(esp); + + AddReg(cs); + AddReg(ds); + AddReg(ss); + AddReg(es); + AddReg(fs); + AddReg(gs); + AddReg(eflags); + + AddReg(eip); +#undef AddReg + + return true; +} + +bool MinidumpGenerator::WriteContextX86_64( + breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) { + TypedMDRVA context(&writer_); + x86_thread_state64_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextAMD64 *context_ptr = context.get(); + +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, a)) + + context_ptr->context_flags = MD_CONTEXT_AMD64; + AddReg(rax); + AddReg(rbx); + AddReg(rcx); + AddReg(rdx); + AddReg(rdi); + AddReg(rsi); + AddReg(rbp); + AddReg(rsp); + AddReg(r8); + AddReg(r9); + AddReg(r10); + AddReg(r11); + AddReg(r12); + AddReg(r13); + AddReg(r14); + AddReg(r15); + AddReg(rip); + // according to AMD's software developer guide, bits above 18 are + // not used in the flags register. Since the minidump format + // specifies 32 bits for the flags register, we can truncate safely + // with no loss. + context_ptr->eflags = static_cast(REGISTER_FROM_THREADSTATE(machine_state, rflags)); + AddReg(cs); + AddReg(fs); + AddReg(gs); +#undef AddReg + + return true; +} +#endif + +bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, + thread_state_t state, + mach_msg_type_number_t *count) { + if (task_context_ && target_thread == mach_thread_self()) { + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + size_t final_size = + std::min(static_cast(*count), sizeof(arm_thread_state_t)); + memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); + *count = static_cast(final_size); + return true; +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: { + size_t final_size = + std::min(static_cast(*count), sizeof(arm_thread_state64_t)); + memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); + *count = static_cast(final_size); + return true; + } +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + case CPU_TYPE_X86_64: { + size_t state_size = cpu_type_ == CPU_TYPE_I386 ? + sizeof(i386_thread_state_t) : sizeof(x86_thread_state64_t); + size_t final_size = + std::min(static_cast(*count), state_size); + memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); + *count = static_cast(final_size); + return true; + } +#endif + } + } + + thread_state_flavor_t flavor; + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + flavor = ARM_THREAD_STATE; + break; +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + flavor = ARM_THREAD_STATE64; + break; +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + flavor = PPC_THREAD_STATE; + break; + case CPU_TYPE_POWERPC64: + flavor = PPC_THREAD_STATE64; + break; +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + flavor = i386_THREAD_STATE; + break; + case CPU_TYPE_X86_64: + flavor = x86_THREAD_STATE64; + break; +#endif + default: + return false; + } + return thread_get_state(target_thread, flavor, + state, count) == KERN_SUCCESS; +} + +bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, + MDRawThread *thread) { + breakpad_thread_state_data_t state; + mach_msg_type_number_t state_count + = static_cast(sizeof(state)); + + if (GetThreadState(thread_id, state, &state_count)) { + if (!WriteStack(state, &thread->stack)) + return false; + + memory_blocks_.push_back(thread->stack); + + if (!WriteContext(state, &thread->thread_context)) + return false; + + thread->thread_id = thread_id; + } else { + return false; + } + + return true; +} + +bool MinidumpGenerator::WriteThreadListStream( + MDRawDirectory *thread_list_stream) { + TypedMDRVA list(&writer_); + thread_act_port_array_t threads_for_task; + mach_msg_type_number_t thread_count; + int non_generator_thread_count; + + if (task_threads(crashing_task_, &threads_for_task, &thread_count)) + return false; + + // Don't include the generator thread + if (handler_thread_ != MACH_PORT_NULL) + non_generator_thread_count = thread_count - 1; + else + non_generator_thread_count = thread_count; + if (!list.AllocateObjectAndArray(non_generator_thread_count, + sizeof(MDRawThread))) + return false; + + thread_list_stream->stream_type = MD_THREAD_LIST_STREAM; + thread_list_stream->location = list.location(); + + list.get()->number_of_threads = non_generator_thread_count; + + MDRawThread thread; + int thread_idx = 0; + + for (unsigned int i = 0; i < thread_count; ++i) { + memset(&thread, 0, sizeof(MDRawThread)); + + if (threads_for_task[i] != handler_thread_) { + if (!WriteThreadStream(threads_for_task[i], &thread)) + return false; + + list.CopyIndexAfterObject(thread_idx++, &thread, sizeof(MDRawThread)); + } + } + + return true; +} + +bool MinidumpGenerator::WriteMemoryListStream( + MDRawDirectory *memory_list_stream) { + TypedMDRVA list(&writer_); + + // If the dump has an exception, include some memory around the + // instruction pointer. + const size_t kIPMemorySize = 256; // bytes + bool have_ip_memory = false; + MDMemoryDescriptor ip_memory_d; + if (exception_thread_ && exception_type_) { + breakpad_thread_state_data_t state; + mach_msg_type_number_t stateCount + = static_cast(sizeof(state)); + + if (GetThreadState(exception_thread_, state, &stateCount)) { + uint64_t ip = CurrentPCForStack(state); + // Bound it to the upper and lower bounds of the region + // it's contained within. If it's not in a known memory region, + // don't bother trying to write it. + mach_vm_address_t addr = static_cast(ip); + mach_vm_size_t size; + natural_t nesting_level = 0; + vm_region_submap_info_64 info; + mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; + vm_region_recurse_info_t recurse_info; + recurse_info = reinterpret_cast(&info); + + kern_return_t ret = + mach_vm_region_recurse(crashing_task_, + &addr, + &size, + &nesting_level, + recurse_info, + &info_count); + if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) { + // Try to get 128 bytes before and after the IP, but + // settle for whatever's available. + ip_memory_d.start_of_memory_range = + std::max(uintptr_t(addr), + uintptr_t(ip - (kIPMemorySize / 2))); + uintptr_t end_of_range = + std::min(uintptr_t(ip + (kIPMemorySize / 2)), + uintptr_t(addr + size)); + uintptr_t range_diff = end_of_range - + static_cast(ip_memory_d.start_of_memory_range); + ip_memory_d.memory.data_size = static_cast(range_diff); + have_ip_memory = true; + // This needs to get appended to the list even though + // the memory bytes aren't filled in yet so the entire + // list can be written first. The memory bytes will get filled + // in after the memory list is written. + memory_blocks_.push_back(ip_memory_d); + } + } + } + + // Now fill in the memory list and write it. + size_t memory_count = memory_blocks_.size(); + if (!list.AllocateObjectAndArray(memory_count, + sizeof(MDMemoryDescriptor))) + return false; + + memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM; + memory_list_stream->location = list.location(); + + list.get()->number_of_memory_ranges = static_cast(memory_count); + + unsigned int i; + for (i = 0; i < memory_count; ++i) { + list.CopyIndexAfterObject(i, &memory_blocks_[i], + sizeof(MDMemoryDescriptor)); + } + + if (have_ip_memory) { + // Now read the memory around the instruction pointer. + UntypedMDRVA ip_memory(&writer_); + if (!ip_memory.Allocate(ip_memory_d.memory.data_size)) + return false; + + if (dynamic_images_) { + // Out-of-process. + vector memory; + if (ReadTaskMemory(crashing_task_, + ip_memory_d.start_of_memory_range, + ip_memory_d.memory.data_size, + memory) != KERN_SUCCESS) { + return false; + } + + ip_memory.Copy(&memory[0], ip_memory_d.memory.data_size); + } else { + // In-process, just copy from local memory. + ip_memory.Copy( + reinterpret_cast(ip_memory_d.start_of_memory_range), + ip_memory_d.memory.data_size); + } + + ip_memory_d.memory = ip_memory.location(); + // Write this again now that the data location is filled in. + list.CopyIndexAfterObject(i - 1, &ip_memory_d, + sizeof(MDMemoryDescriptor)); + } + + return true; +} + +bool +MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { + TypedMDRVA exception(&writer_); + + if (!exception.Allocate()) + return false; + + exception_stream->stream_type = MD_EXCEPTION_STREAM; + exception_stream->location = exception.location(); + MDRawExceptionStream *exception_ptr = exception.get(); + exception_ptr->thread_id = exception_thread_; + + // This naming is confusing, but it is the proper translation from + // mach naming to minidump naming. + exception_ptr->exception_record.exception_code = exception_type_; + exception_ptr->exception_record.exception_flags = exception_code_; + + breakpad_thread_state_data_t state; + mach_msg_type_number_t state_count + = static_cast(sizeof(state)); + + if (!GetThreadState(exception_thread_, state, &state_count)) + return false; + + if (!WriteContext(state, &exception_ptr->thread_context)) + return false; + + if (exception_type_ == EXC_BAD_ACCESS) + exception_ptr->exception_record.exception_address = exception_subcode_; + else + exception_ptr->exception_record.exception_address = CurrentPCForStack(state); + + return true; +} + +bool MinidumpGenerator::WriteSystemInfoStream( + MDRawDirectory *system_info_stream) { + TypedMDRVA info(&writer_); + + if (!info.Allocate()) + return false; + + system_info_stream->stream_type = MD_SYSTEM_INFO_STREAM; + system_info_stream->location = info.location(); + + // CPU Information + uint32_t number_of_processors; + size_t len = sizeof(number_of_processors); + sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0); + MDRawSystemInfo *info_ptr = info.get(); + + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM; + break; +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64; + break; +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + case CPU_TYPE_POWERPC64: + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC; + break; +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + case CPU_TYPE_X86_64: + if (cpu_type_ == CPU_TYPE_I386) + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86; + else + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64; +#ifdef __i386__ + // ebx is used for PIC code, so we need + // to preserve it. +#define cpuid(op,eax,ebx,ecx,edx) \ + asm ("pushl %%ebx \n\t" \ + "cpuid \n\t" \ + "movl %%ebx,%1 \n\t" \ + "popl %%ebx" \ + : "=a" (eax), \ + "=g" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "0" (op)) +#elif defined(__x86_64__) + +#define cpuid(op,eax,ebx,ecx,edx) \ + asm ("cpuid \n\t" \ + : "=a" (eax), \ + "=b" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "0" (op)) +#endif + +#if defined(__i386__) || defined(__x86_64__) + int unused, unused2; + // get vendor id + cpuid(0, unused, info_ptr->cpu.x86_cpu_info.vendor_id[0], + info_ptr->cpu.x86_cpu_info.vendor_id[2], + info_ptr->cpu.x86_cpu_info.vendor_id[1]); + // get version and feature info + cpuid(1, info_ptr->cpu.x86_cpu_info.version_information, unused, unused2, + info_ptr->cpu.x86_cpu_info.feature_information); + + // family + info_ptr->processor_level = + (info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8; + // 0xMMSS (Model, Stepping) + info_ptr->processor_revision = static_cast( + (info_ptr->cpu.x86_cpu_info.version_information & 0xF) | + ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4)); + + // decode extended model info + if (info_ptr->processor_level == 0xF || + info_ptr->processor_level == 0x6) { + info_ptr->processor_revision |= + ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0000) >> 4); + } + + // decode extended family info + if (info_ptr->processor_level == 0xF) { + info_ptr->processor_level += + ((info_ptr->cpu.x86_cpu_info.version_information & 0xFF00000) >> 20); + } + +#endif // __i386__ || __x86_64_ + break; +#endif // HAS_X86_SUPPORT + default: + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN; + break; + } + + info_ptr->number_of_processors = static_cast(number_of_processors); +#if TARGET_OS_IPHONE + info_ptr->platform_id = MD_OS_IOS; +#else + info_ptr->platform_id = MD_OS_MAC_OS_X; +#endif // TARGET_OS_IPHONE + + MDLocationDescriptor build_string_loc; + + if (!writer_.WriteString(build_string_, 0, + &build_string_loc)) + return false; + + info_ptr->csd_version_rva = build_string_loc.rva; + info_ptr->major_version = os_major_version_; + info_ptr->minor_version = os_minor_version_; + info_ptr->build_number = os_build_number_; + + return true; +} + +bool MinidumpGenerator::WriteModuleStream(unsigned int index, + MDRawModule *module) { + if (dynamic_images_) { + // we're in a different process than the crashed process + DynamicImage *image = dynamic_images_->GetImage(index); + + if (!image) + return false; + + memset(module, 0, sizeof(MDRawModule)); + + MDLocationDescriptor string_location; + + string name = image->GetFilePath(); + if (!writer_.WriteString(name.c_str(), 0, &string_location)) + return false; + + module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide(); + module->size_of_image = static_cast(image->GetVMSize()); + module->module_name_rva = string_location.rva; + + // We'll skip the executable module, because they don't have + // LC_ID_DYLIB load commands, and the crash processing server gets + // version information from the Plist file, anyway. + if (index != static_cast(FindExecutableModule())) { + module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE; + module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION; + // Convert MAC dylib version format, which is a 32 bit number, to the + // format used by minidump. The mac format is <16 bits>.<8 bits>.<8 bits> + // so it fits nicely into the windows version with some massaging + // The mapping is: + // 1) upper 16 bits of MAC version go to lower 16 bits of product HI + // 2) Next most significant 8 bits go to upper 16 bits of product LO + // 3) Least significant 8 bits go to lower 16 bits of product LO + uint32_t modVersion = image->GetVersion(); + module->version_info.file_version_hi = 0; + module->version_info.file_version_hi = modVersion >> 16; + module->version_info.file_version_lo |= (modVersion & 0xff00) << 8; + module->version_info.file_version_lo |= (modVersion & 0xff); + } + + if (!WriteCVRecord(module, image->GetCPUType(), name.c_str(), false)) { + return false; + } + } else { + // Getting module info in the crashed process + const breakpad_mach_header *header; + header = (breakpad_mach_header*)_dyld_get_image_header(index); + if (!header) + return false; + +#ifdef __LP64__ + assert(header->magic == MH_MAGIC_64); + + if(header->magic != MH_MAGIC_64) + return false; +#else + assert(header->magic == MH_MAGIC); + + if(header->magic != MH_MAGIC) + return false; +#endif + + int cpu_type = header->cputype; + unsigned long slide = _dyld_get_image_vmaddr_slide(index); + const char* name = _dyld_get_image_name(index); + const struct load_command *cmd = + reinterpret_cast(header + 1); + + memset(module, 0, sizeof(MDRawModule)); + + for (unsigned int i = 0; cmd && (i < header->ncmds); i++) { + if (cmd->cmd == LC_SEGMENT_ARCH) { + + const breakpad_mach_segment_command *seg = + reinterpret_cast(cmd); + + if (!strcmp(seg->segname, "__TEXT")) { + MDLocationDescriptor string_location; + + if (!writer_.WriteString(name, 0, &string_location)) + return false; + + module->base_of_image = seg->vmaddr + slide; + module->size_of_image = static_cast(seg->vmsize); + module->module_name_rva = string_location.rva; + + bool in_memory = false; +#if TARGET_OS_IPHONE + in_memory = true; +#endif + if (!WriteCVRecord(module, cpu_type, name, in_memory)) + return false; + + return true; + } + } + + cmd = reinterpret_cast((char *)cmd + cmd->cmdsize); + } + } + + return true; +} + +int MinidumpGenerator::FindExecutableModule() { + if (dynamic_images_) { + int index = dynamic_images_->GetExecutableImageIndex(); + + if (index >= 0) { + return index; + } + } else { + int image_count = _dyld_image_count(); + const struct mach_header *header; + + for (int index = 0; index < image_count; ++index) { + header = _dyld_get_image_header(index); + + if (header->filetype == MH_EXECUTE) + return index; + } + } + + // failed - just use the first image + return 0; +} + +bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, + const char *module_path, bool in_memory) { + TypedMDRVA cv(&writer_); + + // Only return the last path component of the full module path + const char *module_name = strrchr(module_path, '/'); + + // Increment past the slash + if (module_name) + ++module_name; + else + module_name = ""; + + size_t module_name_length = strlen(module_name); + + if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(uint8_t))) + return false; + + if (!cv.CopyIndexAfterObject(0, module_name, module_name_length)) + return false; + + module->cv_record = cv.location(); + MDCVInfoPDB70 *cv_ptr = cv.get(); + cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE; + cv_ptr->age = 0; + + // Get the module identifier + unsigned char identifier[16]; + bool result = false; + if (in_memory) { + MacFileUtilities::MachoID macho(module_path, + reinterpret_cast(module->base_of_image), + static_cast(module->size_of_image)); + result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); + if (!result) + result = macho.MD5(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); + } + + if (!result) { + FileID file_id(module_path); + result = file_id.MachoIdentifier(cpu_type, CPU_SUBTYPE_MULTIPLE, + identifier); + } + + if (result) { + cv_ptr->signature.data1 = + static_cast(identifier[0]) << 24 | + static_cast(identifier[1]) << 16 | + static_cast(identifier[2]) << 8 | + static_cast(identifier[3]); + cv_ptr->signature.data2 = + static_cast(identifier[4] << 8) | identifier[5]; + cv_ptr->signature.data3 = + static_cast(identifier[6] << 8) | identifier[7]; + cv_ptr->signature.data4[0] = identifier[8]; + cv_ptr->signature.data4[1] = identifier[9]; + cv_ptr->signature.data4[2] = identifier[10]; + cv_ptr->signature.data4[3] = identifier[11]; + cv_ptr->signature.data4[4] = identifier[12]; + cv_ptr->signature.data4[5] = identifier[13]; + cv_ptr->signature.data4[6] = identifier[14]; + cv_ptr->signature.data4[7] = identifier[15]; + } + + return true; +} + +bool MinidumpGenerator::WriteModuleListStream( + MDRawDirectory *module_list_stream) { + TypedMDRVA list(&writer_); + + uint32_t image_count = dynamic_images_ ? + dynamic_images_->GetImageCount() : + _dyld_image_count(); + + if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE)) + return false; + + module_list_stream->stream_type = MD_MODULE_LIST_STREAM; + module_list_stream->location = list.location(); + list.get()->number_of_modules = static_cast(image_count); + + // Write out the executable module as the first one + MDRawModule module; + uint32_t executableIndex = FindExecutableModule(); + + if (!WriteModuleStream(static_cast(executableIndex), &module)) { + return false; + } + + list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE); + int destinationIndex = 1; // Write all other modules after this one + + for (uint32_t i = 0; i < image_count; ++i) { + if (i != executableIndex) { + if (!WriteModuleStream(static_cast(i), &module)) { + return false; + } + + list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE); + } + } + + return true; +} + +bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) { + TypedMDRVA info(&writer_); + + if (!info.Allocate()) + return false; + + misc_info_stream->stream_type = MD_MISC_INFO_STREAM; + misc_info_stream->location = info.location(); + + MDRawMiscInfo *info_ptr = info.get(); + info_ptr->size_of_info = static_cast(sizeof(MDRawMiscInfo)); + info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID | + MD_MISCINFO_FLAGS1_PROCESS_TIMES | + MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO; + + // Process ID + info_ptr->process_id = getpid(); + + // Times + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage) != -1) { + // Omit the fractional time since the MDRawMiscInfo only wants seconds + info_ptr->process_user_time = + static_cast(usage.ru_utime.tv_sec); + info_ptr->process_kernel_time = + static_cast(usage.ru_stime.tv_sec); + } + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, + static_cast(info_ptr->process_id) }; + uint mibsize = static_cast(sizeof(mib) / sizeof(mib[0])); + struct kinfo_proc proc; + size_t size = sizeof(proc); + if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) { + info_ptr->process_create_time = + static_cast(proc.kp_proc.p_starttime.tv_sec); + } + + // Speed + uint64_t speed; + const uint64_t kOneMillion = 1000 * 1000; + size = sizeof(speed); + sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0); + info_ptr->processor_max_mhz = static_cast(speed / kOneMillion); + info_ptr->processor_mhz_limit = static_cast(speed / kOneMillion); + size = sizeof(speed); + sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0); + info_ptr->processor_current_mhz = static_cast(speed / kOneMillion); + + return true; +} + +bool MinidumpGenerator::WriteBreakpadInfoStream( + MDRawDirectory *breakpad_info_stream) { + TypedMDRVA info(&writer_); + + if (!info.Allocate()) + return false; + + breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM; + breakpad_info_stream->location = info.location(); + MDRawBreakpadInfo *info_ptr = info.get(); + + if (exception_thread_ && exception_type_) { + info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; + info_ptr->dump_thread_id = handler_thread_; + info_ptr->requesting_thread_id = exception_thread_; + } else { + info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID; + info_ptr->dump_thread_id = handler_thread_; + info_ptr->requesting_thread_id = 0; + } + + return true; +} + +} // namespace google_breakpad diff --git a/Telegram/ThirdParty/breakpad/client/mac/handler/minidump_generator.h b/Telegram/ThirdParty/breakpad/client/mac/handler/minidump_generator.h new file mode 100644 index 000000000..4e4b4a684 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/handler/minidump_generator.h @@ -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 +#include + +#include + +#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 /.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 memory_blocks_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__ diff --git a/Telegram/ThirdParty/breakpad/client/mac/handler/ucontext_compat.h b/Telegram/ThirdParty/breakpad/client/mac/handler/ucontext_compat.h new file mode 100644 index 000000000..1e4b752e5 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/mac/handler/ucontext_compat.h @@ -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 + +// 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__) +// doesn't include the below file. +#include +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_ diff --git a/Telegram/ThirdParty/breakpad/client/minidump_file_writer-inl.h b/Telegram/ThirdParty/breakpad/client/minidump_file_writer-inl.h new file mode 100644 index 000000000..0e12e00b6 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/minidump_file_writer-inl.h @@ -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 + +#include "client/minidump_file_writer.h" +#include "google_breakpad/common/minidump_size.h" + +namespace google_breakpad { + +template +inline bool TypedMDRVA::Allocate() { + allocation_state_ = SINGLE_OBJECT; + return UntypedMDRVA::Allocate(minidump_size::size()); +} + +template +inline bool TypedMDRVA::Allocate(size_t additional) { + allocation_state_ = SINGLE_OBJECT; + return UntypedMDRVA::Allocate(minidump_size::size() + additional); +} + +template +inline bool TypedMDRVA::AllocateArray(size_t count) { + assert(count); + allocation_state_ = ARRAY; + return UntypedMDRVA::Allocate(minidump_size::size() * count); +} + +template +inline bool TypedMDRVA::AllocateObjectAndArray(size_t count, + size_t length) { + assert(count && length); + allocation_state_ = SINGLE_OBJECT_WITH_ARRAY; + return UntypedMDRVA::Allocate(minidump_size::size() + count * length); +} + +template +inline bool TypedMDRVA::CopyIndex(unsigned int index, MDType *item) { + assert(allocation_state_ == ARRAY); + return writer_->Copy( + static_cast(position_ + index * minidump_size::size()), + item, minidump_size::size()); +} + +template +inline bool TypedMDRVA::CopyIndexAfterObject(unsigned int index, + const void *src, + size_t length) { + assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY); + return writer_->Copy( + static_cast(position_ + minidump_size::size() + + index * length), + src, length); +} + +template +inline bool TypedMDRVA::Flush() { + return writer_->Copy(position_, &data_, minidump_size::size()); +} + +} // namespace google_breakpad + +#endif // CLIENT_MINIDUMP_FILE_WRITER_INL_H__ diff --git a/Telegram/ThirdParty/breakpad/client/minidump_file_writer.cc b/Telegram/ThirdParty/breakpad/client/minidump_file_writer.cc new file mode 100644 index 000000000..a1957f324 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/minidump_file_writer.cc @@ -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 +#include +#include +#include +#include + +#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 + +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(-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) { + 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) { + 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 +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(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(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(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(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(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 + position) > size_) + return false; + + // Seek and write the data +#if defined(__linux__) && __linux__ + if (sys_lseek(file_, position, SEEK_SET) == static_cast(position)) { + if (sys_write(file_, src, size) == size) { + return true; + } + } +#else + if (lseek(file_, position, SEEK_SET) == static_cast(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 diff --git a/Telegram/ThirdParty/breakpad/client/minidump_file_writer.h b/Telegram/ThirdParty/breakpad/client/minidump_file_writer.h new file mode 100644 index 000000000..ce32b6d08 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/client/minidump_file_writer.h @@ -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 + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +class UntypedMDRVA; +template 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 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 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); + bool CopyStringToMDString(const char *str, unsigned int length, + TypedMDRVA *mdstring); + + // The common templated code for writing a string + template + 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(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 +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::size() bytes. + // Must not call more than once. + // Return true on success, or false on failure + bool Allocate(); + + // Allocates minidump_size::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__ diff --git a/Telegram/ThirdParty/breakpad/common/convert_UTF.c b/Telegram/ThirdParty/breakpad/common/convert_UTF.c new file mode 100644 index 000000000..12a3c8917 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/convert_UTF.c @@ -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 +#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. + +--------------------------------------------------------------------- */ diff --git a/Telegram/ThirdParty/breakpad/common/convert_UTF.h b/Telegram/ThirdParty/breakpad/common/convert_UTF.h new file mode 100644 index 000000000..644d09950 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/convert_UTF.h @@ -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: , , +or 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_ diff --git a/Telegram/ThirdParty/breakpad/common/linux/linux_libc_support.h b/Telegram/ThirdParty/breakpad/common/linux/linux_libc_support.h new file mode 100644 index 000000000..ec5a8d6b6 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/linux/linux_libc_support.h @@ -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 +#include +#include + +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_ diff --git a/Telegram/ThirdParty/breakpad/common/mac/MachIPC.h b/Telegram/ThirdParty/breakpad/common/mac/MachIPC.h new file mode 100644 index 000000000..8df9165bb --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/MachIPC.h @@ -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 +#import +#import +#import + +#import + +//============================================================================== +// 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__ diff --git a/Telegram/ThirdParty/breakpad/common/mac/MachIPC.mm b/Telegram/ThirdParty/breakpad/common/mac/MachIPC.mm new file mode 100644 index 000000000..dc9773f77 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/MachIPC.mm @@ -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 +#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(size); + + return head.msgh_size; +} + +//============================================================================== +MachMessage::MessageDataPacket *MachMessage::GetDataPacket() { + size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount(); + MessageDataPacket *packet = + reinterpret_cast(padding + desc_size); + + return packet; +} + +//============================================================================== +void MachMessage::SetDescriptor(int n, + const MachMsgPortDescriptor &desc) { + MachMsgPortDescriptor *desc_array = + reinterpret_cast(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(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(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(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(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 diff --git a/Telegram/ThirdParty/breakpad/common/mac/bootstrap_compat.cc b/Telegram/ThirdParty/breakpad/common/mac/bootstrap_compat.cc new file mode 100644 index 000000000..d875d95b5 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/bootstrap_compat.cc @@ -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 diff --git a/Telegram/ThirdParty/breakpad/common/mac/bootstrap_compat.h b/Telegram/ThirdParty/breakpad/common/mac/bootstrap_compat.h new file mode 100644 index 000000000..8ca7357c3 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/bootstrap_compat.h @@ -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 + +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_ diff --git a/Telegram/ThirdParty/breakpad/common/mac/byteswap.h b/Telegram/ThirdParty/breakpad/common/mac/byteswap.h new file mode 100644 index 000000000..b7bbc0b95 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/byteswap.h @@ -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 + +// byteswap.h: Overloaded functions for conveniently byteswapping values. + +#ifndef COMMON_MAC_BYTESWAP_H_ +#define COMMON_MAC_BYTESWAP_H_ + +#ifdef __APPLE__ +#include + +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 +#include +#include +#include_next + +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_ diff --git a/Telegram/ThirdParty/breakpad/common/mac/file_id.cc b/Telegram/ThirdParty/breakpad/common/mac/file_id.cc new file mode 100644 index 000000000..4661d5d62 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/file_id.cc @@ -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 +#include +#include +#include + +#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(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((hi >= 10) ? ('A' + hi - 10) : ('0' + hi)); + buffer[buffer_idx++] = + static_cast((lo >= 10) ? ('A' + lo - 10) : ('0' + lo)); + } + + // NULL terminate + buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0; +} + +} // namespace google_breakpad diff --git a/Telegram/ThirdParty/breakpad/common/mac/file_id.h b/Telegram/ThirdParty/breakpad/common/mac/file_id.h new file mode 100644 index 000000000..1d6dfde1b --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/file_id.h @@ -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 +#include + +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__ diff --git a/Telegram/ThirdParty/breakpad/common/mac/macho_id.cc b/Telegram/ThirdParty/breakpad/common/mac/macho_id.cc new file mode 100644 index 000000000..c396ad888 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/macho_id.cc @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#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(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 diff --git a/Telegram/ThirdParty/breakpad/common/mac/macho_id.h b/Telegram/ThirdParty/breakpad/common/mac/macho_id.h new file mode 100644 index 000000000..103754912 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/macho_id.h @@ -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 +#include +#include + +#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__ diff --git a/Telegram/ThirdParty/breakpad/common/mac/macho_utilities.cc b/Telegram/ThirdParty/breakpad/common/mac/macho_utilities.cc new file mode 100644 index 000000000..f56fe768c --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/macho_utilities.cc @@ -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 +#include + +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); + } +} diff --git a/Telegram/ThirdParty/breakpad/common/mac/macho_utilities.h b/Telegram/ThirdParty/breakpad/common/mac/macho_utilities.h new file mode 100644 index 000000000..00563a77c --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/macho_utilities.h @@ -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 +#include + +/* 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 diff --git a/Telegram/ThirdParty/breakpad/common/mac/macho_walker.cc b/Telegram/ThirdParty/breakpad/common/mac/macho_walker.cc new file mode 100644 index 000000000..1acd86656 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/macho_walker.cc @@ -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 +#include +#include +#include +#include +#include +#include + +#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(offset) >= memory_size_) + return false; + size = memory_size_ - static_cast(offset); + result = false; + } + memcpy(buffer, static_cast(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 diff --git a/Telegram/ThirdParty/breakpad/common/mac/macho_walker.h b/Telegram/ThirdParty/breakpad/common/mac/macho_walker.h new file mode 100644 index 000000000..dd535814a --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/macho_walker.h @@ -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 +#include +#include + +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__ diff --git a/Telegram/ThirdParty/breakpad/common/mac/scoped_task_suspend-inl.h b/Telegram/ThirdParty/breakpad/common/mac/scoped_task_suspend-inl.h new file mode 100644 index 000000000..d6d1bef97 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/scoped_task_suspend-inl.h @@ -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 + +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_ diff --git a/Telegram/ThirdParty/breakpad/common/mac/string_utilities.cc b/Telegram/ThirdParty/breakpad/common/mac/string_utilities.cc new file mode 100644 index 000000000..07c0f4268 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/string_utilities.cc @@ -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 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 diff --git a/Telegram/ThirdParty/breakpad/common/mac/string_utilities.h b/Telegram/ThirdParty/breakpad/common/mac/string_utilities.h new file mode 100644 index 000000000..6d89c834e --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/mac/string_utilities.h @@ -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 + +#include + +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__ diff --git a/Telegram/ThirdParty/breakpad/common/md5.cc b/Telegram/ThirdParty/breakpad/common/md5.cc new file mode 100644 index 000000000..a0d9a1bdd --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/md5.cc @@ -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 + +#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<>(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 + diff --git a/Telegram/ThirdParty/breakpad/common/md5.h b/Telegram/ThirdParty/breakpad/common/md5.h new file mode 100644 index 000000000..2ab0ab95a --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/md5.h @@ -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 + +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__ diff --git a/Telegram/ThirdParty/breakpad/common/memory.h b/Telegram/ThirdParty/breakpad/common/memory.h new file mode 100644 index 000000000..d6aa137d3 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/memory.h @@ -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 +#include +#include +#include + +#include +#include + +#if defined(MEMORY_SANITIZER) +#include +#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(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(a); + header->next = last_; + header->num_pages = num_pages; + last_ = header; + + return reinterpret_cast(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 +struct PageStdAllocator : public std::allocator { + typedef typename std::allocator::pointer pointer; + typedef typename std::allocator::size_type size_type; + + explicit PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {} + template PageStdAllocator(const PageStdAllocator& other) + : allocator_(other.allocator_) {} + + inline pointer allocate(size_type n, const void* = 0) { + return static_cast(allocator_.Alloc(sizeof(T) * n)); + } + + inline void deallocate(pointer, size_type) { + // The PageAllocator doesn't free. + } + + template struct rebind { + typedef PageStdAllocator 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 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 wasteful_vector : public std::vector > { + public: + wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16) + : std::vector >(PageStdAllocator(*allocator)) { + std::vector >::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_ diff --git a/Telegram/ThirdParty/breakpad/common/string_conversion.cc b/Telegram/ThirdParty/breakpad/common/string_conversion.cc new file mode 100644 index 000000000..9c0d623fc --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/string_conversion.cc @@ -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 + +#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 *out) { + size_t source_length = strlen(in); + const UTF8 *source_ptr = reinterpret_cast(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(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(source_ptr - reinterpret_cast(in)); + + // Add another character to the input stream and try again + source_ptr = reinterpret_cast(in); + ++source_end_ptr; + + if (source_end_ptr > reinterpret_cast(in) + in_length) + break; + } + + return 0; +} + +void UTF32ToUTF16(const wchar_t *in, vector *out) { + size_t source_length = wcslen(in); + const UTF32 *source_ptr = reinterpret_cast(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(&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(value << 8); +} + +string UTF16ToUTF8(const vector &in, bool swap) { + const UTF16 *source_ptr = &in[0]; + scoped_array 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::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 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(target_buffer.get()); + return targetPtr; + } + + return ""; +} + +} // namespace google_breakpad diff --git a/Telegram/ThirdParty/breakpad/common/string_conversion.h b/Telegram/ThirdParty/breakpad/common/string_conversion.h new file mode 100644 index 000000000..b9ba96a2e --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/string_conversion.h @@ -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 +#include + +#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 *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 *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 &in, bool swap); + +} // namespace google_breakpad + +#endif // COMMON_STRING_CONVERSION_H__ diff --git a/Telegram/ThirdParty/breakpad/common/using_std_string.h b/Telegram/ThirdParty/breakpad/common/using_std_string.h new file mode 100644 index 000000000..13c1da59c --- /dev/null +++ b/Telegram/ThirdParty/breakpad/common/using_std_string.h @@ -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_ diff --git a/Telegram/ThirdParty/breakpad/google_breakpad/common/minidump_size.h b/Telegram/ThirdParty/breakpad/google_breakpad/common/minidump_size.h new file mode 100644 index 000000000..918544b66 --- /dev/null +++ b/Telegram/ThirdParty/breakpad/google_breakpad/common/minidump_size.h @@ -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 + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +template +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 { + public: + static size_t size() { return MDString_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawThreadList_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDCVInfoPDB20_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDCVInfoPDB70_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDImageDebugMisc_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawModuleList_minsize; } +}; + +template<> +class minidump_size { + 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 { + public: + static size_t size() { return MD_MODULE_SIZE; } +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ diff --git a/Telegram/ThirdParty/minizip/ioapi.c b/Telegram/ThirdParty/minizip/ioapi.c new file mode 100644 index 000000000..7f5c191b2 --- /dev/null +++ b/Telegram/ThirdParty/minizip/ioapi.c @@ -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; +} diff --git a/Telegram/ThirdParty/minizip/zip.c b/Telegram/ThirdParty/minizip/zip.c index ea54853e8..3c1a7bff2 100644 --- a/Telegram/ThirdParty/minizip/zip.c +++ b/Telegram/ThirdParty/minizip/zip.c @@ -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))