Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/desktop/source/app/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 14 kB image not shown  

Quelle  crashreport.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include <desktop/crashreport.hxx>
#include <rtl/bootstrap.hxx>
#include <osl/file.hxx>
#include <comphelper/processfactory.hxx>
#include <ucbhelper/proxydecider.hxx>
#include <unotools/bootstrap.hxx>
#include <o3tl/char16_t2wchar_t.hxx>
#include <desktop/minidump.hxx>
#include <rtl/ustrbuf.hxx>

#include <config_version.h>
#include <config_folders.h>

#include <string>
#include <string_view>
#include <regex>


#if HAVE_FEATURE_BREAKPAD

#include <fstream>
#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
#include <client/linux/handler/exception_handler.h>
#elif defined _WIN32
#if defined __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmicrosoft-enum-value"
#endif
#include <client/windows/handler/exception_handler.h>
#if defined __clang__
#pragma clang diagnostic pop
#endif
#include <locale>
#include <codecvt>
#endif

osl::Mutex CrashReporter::maMutex;
osl::Mutex CrashReporter::maActiveSfxObjectNameMutex;
osl::Mutex CrashReporter::maUnoLogCmdMutex;
std::unique_ptr<google_breakpad::ExceptionHandler> CrashReporter::mpExceptionHandler;
bool CrashReporter::mbInit = false;
CrashReporter::vmaKeyValues CrashReporter::maKeyValues;
CrashReporter::vmaloggedUnoCommands CrashReporter::maloggedUnoCommands;
OUString CrashReporter::msActiveSfxObjectName;


#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void/*context*/, bool succeeded)
{
    CrashReporter::addKeyValue("Active-SfxObject",CrashReporter::getActiveSfxObjectName(),CrashReporter::AddItem);
    CrashReporter::addKeyValue("Last-4-Uno-Commands",CrashReporter::getLoggedUnoCommands(),CrashReporter::AddItem);
    CrashReporter::addKeyValue("DumpFile", OStringToOUString(descriptor.path(), RTL_TEXTENCODING_UTF8), CrashReporter::Write);
    SAL_WARN("desktop""minidump generated: " << descriptor.path());

    return succeeded;
}
#elif defined _WIN32
static bool dumpCallback(const wchar_t* path, const wchar_t* id,
    void/*context*/, EXCEPTION_POINTERS* /*exinfo*/,
    MDRawAssertionInfo* /*assertion*/,
    bool succeeded)
{
    OUString aPath(OUString::Concat(o3tl::toU(path)) + o3tl::toU(id) + ".dmp");
    CrashReporter::addKeyValue("Active-SfxObject",CrashReporter::getActiveSfxObjectName(),CrashReporter::AddItem);
    CrashReporter::addKeyValue("Last-4-Uno-Commands",CrashReporter::getLoggedUnoCommands(),CrashReporter::AddItem);
    CrashReporter::addKeyValue("DumpFile", aPath, CrashReporter::AddItem);
    CrashReporter::addKeyValue("GDIHandles", OUString::number(::GetGuiResources(::GetCurrentProcess(), GR_GDIOBJECTS)), CrashReporter::Write);
    SAL_WARN("desktop""minidump generated: " << aPath);
    return succeeded;
}
#endif


void CrashReporter::writeToFile(std::ios_base::openmode Openmode)
{
#if defined _WIN32
    const std::string iniPath = getIniFileName();
    std::wstring iniPathW;
    const int nChars = MultiByteToWideChar(CP_UTF8, 0, iniPath.c_str(), -1, nullptr, 0);
    auto buf = std::make_unique<wchar_t[]>(nChars);
    if (MultiByteToWideChar(CP_UTF8, 0, iniPath.c_str(), -1, buf.get(), nChars) != 0)
        iniPathW = buf.get();

    std::ofstream ini_file
        = iniPathW.empty() ? std::ofstream(iniPath, Openmode) : std::ofstream(iniPathW, Openmode);
#else
    std::ofstream ini_file(getIniFileName(), Openmode);
#endif

    for (auto& keyValue : maKeyValues)
    {
        ini_file << OUStringToOString(keyValue.first, RTL_TEXTENCODING_UTF8) << "=";
        ini_file << OUStringToOString(keyValue.second, RTL_TEXTENCODING_UTF8) << "\n";
    }

    maKeyValues.clear();
    ini_file.close();
}

void CrashReporter::addKeyValue(const OUString& rKey, const OUString& rValue, tAddKeyHandling AddKeyHandling)
{
    osl::MutexGuard aGuard(maMutex);

    if (IsDumpEnable())
    {
        if (!rKey.isEmpty())
            maKeyValues.push_back(mpair(rKey, rValue));

        if (AddKeyHandling != AddItem)
        {
            if (mbInit)
                writeToFile(std::ios_base::app);
            else if (AddKeyHandling == Create)
                writeCommonInfo();
        }
    }
}

void CrashReporter::writeCommonInfo()
{
    writeSystemInfo();

    ucbhelper::InternetProxyDecider proxy_decider(::comphelper::getProcessComponentContext());

    static constexpr OUString protocol = u"https"_ustr;
    static constexpr OUString url = u"crashreport.libreoffice.org"_ustr;
    const sal_Int32 port = 443;

    const OUString proxy_server = proxy_decider.getProxy(protocol, url, port);

    // save the new Keys
    vmaKeyValues atlast = maKeyValues;
    // clear the keys, the following Keys should be at the begin
    maKeyValues.clear();

    // limit the amount of code that needs to be executed before the crash reporting
    addKeyValue("ProductName""LibreOffice", AddItem);
    addKeyValue("Version", LIBO_VERSION_DOTTED, AddItem);
    addKeyValue("BuildID", utl::Bootstrap::getBuildIdData(""), AddItem);
    addKeyValue("URL", protocol + "://" + url + "/submit/", AddItem);

    if (!proxy_server.isEmpty())
    {
        addKeyValue("Proxy", proxy_server, AddItem);
    }

    // write the new keys at the end
    maKeyValues.insert(maKeyValues.end(), atlast.begin(), atlast.end());

    mbInit = true;

    writeToFile(std::ios_base::trunc);

    updateMinidumpLocation();
}

void CrashReporter::setActiveSfxObjectName(const OUString& rActiveSfxObjectName)
{
    osl::MutexGuard aGuard(maActiveSfxObjectNameMutex);
    msActiveSfxObjectName = rActiveSfxObjectName;
}

OUString CrashReporter::getActiveSfxObjectName()
{
    osl::MutexGuard aGuard(maActiveSfxObjectNameMutex);
    return msActiveSfxObjectName;
}

void CrashReporter::logUnoCommand(const OUString& rUnoCommand)
{
    osl::MutexGuard aGuard(maUnoLogCmdMutex);

    if( maloggedUnoCommands.size() == 4 )
        maloggedUnoCommands.pop_front();

    maloggedUnoCommands.push_back(rUnoCommand);
}

OUString CrashReporter::getLoggedUnoCommands()
{
    osl::MutexGuard aGuard(maUnoLogCmdMutex);

    std::u16string_view aCommandSeperator=u"";
    OUStringBuffer aUnoCommandBuffer;

    forauto& unocommand: maloggedUnoCommands)
    {
        aUnoCommandBuffer.append(aCommandSeperator + unocommand);
        aCommandSeperator=u",";
    }
    return aUnoCommandBuffer.makeStringAndClear();
}

namespace {

OUString getCrashDirectory()
{
    OUString aCrashURL;
    rtl::Bootstrap::get("CrashDirectory", aCrashURL);
    // Need to convert to URL in case of user-defined path
    osl::FileBase::getFileURLFromSystemPath(aCrashURL, aCrashURL);

    if (aCrashURL.isEmpty()) { // Fall back to user profile
        aCrashURL = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap"":UserInstallation}/crash/";
        rtl::Bootstrap::expandMacros(aCrashURL);
    }

    if (!aCrashURL.endsWith("/"))
        aCrashURL += "/";

    osl::Directory::create(aCrashURL);
    OUString aCrashPath;
    osl::FileBase::getSystemPathFromFileURL(aCrashURL, aCrashPath);
    return aCrashPath;
}

}

void CrashReporter::updateMinidumpLocation()
{
#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
    OUString aURL = getCrashDirectory();
    OString aOStringUrl = OUStringToOString(aURL, RTL_TEXTENCODING_UTF8);
    google_breakpad::MinidumpDescriptor descriptor(std::string{aOStringUrl});
    mpExceptionHandler->set_minidump_descriptor(descriptor);
#elif defined _WIN32
    OUString aURL = getCrashDirectory();
    mpExceptionHandler->set_dump_path(std::wstring(o3tl::toW(aURL)));
#endif
}

bool CrashReporter::crashReportInfoExists()
{
    static const bool InfoExist = crashreport::readConfig(CrashReporter::getIniFileName(), nullptr);
    return InfoExist;
}

bool CrashReporter::readSendConfig(std::string& response)
{
    return crashreport::readConfig(CrashReporter::getIniFileName(), &response);
}

void CrashReporter::installExceptionHandler()
{
    if (!IsDumpEnable())
        return;
#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
    google_breakpad::MinidumpDescriptor descriptor("/tmp");
    mpExceptionHandler = std::make_unique<google_breakpad::ExceptionHandler>(descriptor, nullptr, dumpCallback, nullptr, true, -1);
#elif defined _WIN32
    mpExceptionHandler = std::make_unique<google_breakpad::ExceptionHandler>(L".", nullptr, dumpCallback, nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL);
#endif
}

void CrashReporter::removeExceptionHandler()
{
    mpExceptionHandler.reset();
}



bool CrashReporter::IsDumpEnable()
{
    auto const env = std::getenv("CRASH_DUMP_ENABLE");
    if (env != nullptr && env[0] != '\0') {
        return true;
    }
    // read configuration item 'CrashDumpEnable' -> bool on/off
    OUString sToken;
    if (rtl::Bootstrap::get("CrashDumpEnable", sToken))
    {
        return sToken.toBoolean();
    }
    return true// default, always on
}


std::string CrashReporter::getIniFileName()
{
    OUString url = getCrashDirectory() + "dump.ini";
    OString aUrl = OUStringToOString(url, RTL_TEXTENCODING_UTF8);
    std::string aRet(aUrl);
    return aRet;
}

// Write system-specific information such as the CPU name and features.
// This may allow us to get some statistics for decisions (such as when
// deciding whether SSE2 can be made a hard-requirement for Windows).
// Breakpad provides this information poorly or not at all.
#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
void CrashReporter::writeSystemInfo()
{
    // Get 'model name' and 'flags' from /proc/cpuinfo.
    if( std::ifstream cpuinfo( "/proc/cpuinfo" ); cpuinfo )
    {
        bool haveModel = false;
        bool haveFlags = false;
        std::regex modelRegex( "^model name[ \t]*:[ \t]*(.*)$" );
        std::regex flagsRegex( "^flags[ \t]*:[ \t]*(.*)$" );
        for( std::string line; std::getline( cpuinfo, line ); )
        {
            std::smatch match;
            if( !haveModel && std::regex_match( line, match, modelRegex ) && match.size() == 2)
            {
                addKeyValue("CPUModelName", OUString::fromUtf8( match[ 1 ].str()), AddItem);
                haveModel = true;
            }
            if( !haveFlags && std::regex_match( line, match, flagsRegex ) && match.size() == 2)
            {
                addKeyValue("CPUFlags", OUString::fromUtf8( match[ 1 ].str()), AddItem);
                haveFlags = true;
            }
            if( haveModel && haveFlags )
                break;
        }
    }
    // Get 'MemTotal' from /proc/meminfo.
    if( std::ifstream meminfo( "/proc/meminfo" ); meminfo )
    {
        std::regex memTotalRegex( "^MemTotal[ \t]*:[ \t]*(.*)$" );
        for( std::string line; std::getline( meminfo, line ); )
        {
            std::smatch match;
            if( std::regex_match( line, match, memTotalRegex ) && match.size() == 2)
            {
                addKeyValue("MemoryTotal", OUString::fromUtf8( match[ 1 ].str()), AddItem);
                break;
            }
        }
    }
}
#elif defined _WIN32
void CrashReporter::writeSystemInfo()
{
#if !defined(_ARM64_)
    // Get CPU model name and flags.
    // See https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
    // and https://en.wikipedia.org/wiki/CPUID .
    int cpui[ 4 ];
    __cpuid( cpui, 0x80000000 ); // Get the highest extended ID.
    unsigned int exIds = cpui[ 0 ];
    if( exIds >= 0x80000004 )
    {
        int brand[ 16 ];
        __cpuidex( brand, 0x80000002, 0 );
        __cpuidex( brand + 4, 0x80000003, 0 );
        __cpuidex( brand + 8, 0x80000004, 0 );
        brand[ 12 ] = 0;;
        addKeyValue( "CPUModelName", OUString::fromUtf8( reinterpret_castconst char* >( brand )),
            AddItem );
    }
    __cpuid( cpui, 0 ); // Get the highest ID.
    int ids = cpui[ 0 ];
    unsigned int ecx1 = 0, edx1 = 0, ebx7 = 0, ecx7 = 0, ecx81 = 0, edx81 = 0;
    if( ids >= 0x1 )
    {
        __cpuidex( cpui, 0x1, 0 );
        ecx1 = cpui[ 2 ];
        edx1 = cpui[ 3 ];
    }
    if( ids >= 0x7 )
    {
        __cpuidex( cpui, 0x7, 0 );
        ebx7 = cpui[ 1 ];
        ecx7 = cpui[ 2 ];
    }
    if( exIds >= 0x80000001 )
    {
        __cpuidex( cpui, 0x80000001, 0 );
        ecx81 = cpui[ 2 ];
        edx81 = cpui[ 3 ];
    }
    struct FlagItem
    {
        unsigned int* reg;
        int bit;
        const char* name;
    };
    const FlagItem flagItems[] =
    {
        { &ecx1, 0, "sse3" },
        { &ecx1, 1, "pclmulqdq" },
        { &ecx1, 3, "monitor" },
        { &ecx1, 9, "ssse3" },
        { &ecx1, 12, "fma" },
        { &ecx1, 13, "cpmxch16b" },
        { &ecx1, 19, "sse41" },
        { &ecx1, 20, "sse42" },
        { &ecx1, 22, "movbe" },
        { &ecx1, 23, "popcnt" },
        { &ecx1, 25, "aes" },
        { &ecx1, 26, "xsave" },
        { &ecx1, 27, "osxsave" },
        { &ecx1, 28, "avx" },
        { &ecx1, 29, "f16c" },
        { &ecx1, 30, "rdrand" },
        { &edx1, 5, "msr" },
        { &edx1, 8, "cx8" },
        { &edx1, 11, "sep" },
        { &edx1, 15, "cmov" },
        { &edx1, 19, "clfsh" },
        { &edx1, 23, "mmx" },
        { &edx1, 24, "fxsr" },
        { &edx1, 25, "sse" },
        { &edx1, 26, "sse2" },
        { &edx1, 28, "ht" },
        { &ebx7, 0, "fsgsbase" },
        { &ebx7, 3, "bmi1" },
        { &ebx7, 4, "hle" },
        { &ebx7, 5, "avx2" },
        { &ebx7, 8, "bmi2" },
        { &ebx7, 9, "erms" },
        { &ebx7, 10, "invpcid" },
        { &ebx7, 11, "rtm" },
        { &ebx7, 16, "avx512f" },
        { &ebx7, 18, "rdseed" },
        { &ebx7, 19, "adx" },
        { &ebx7, 26, "avx512pf" },
        { &ebx7, 27, "avx512er" },
        { &ebx7, 28, "avx512cd" },
        { &ebx7, 29, "sha" },
        { &ecx7, 0, "prefetchwt1" },
        { &ecx81, 0, "lahf" },
        { &ecx81, 5, "abm" },
        { &ecx81, 6, "sse4a" },
        { &ecx81, 11, "xop" },
        { &ecx81, 21, "tbm" },
        { &edx81, 11, "syscall" },
        { &edx81, 22, "mmxext" },
        { &edx81, 27, "rdtscp" },
        { &edx81, 30, "3dnowext" },
        { &edx81, 31, "3dnow" }
    };
    OUStringBuffer flags;
    forconst FlagItem& item : flagItems )
    {
        if( *item.reg & ( 1U << item.bit ))
        {
            if( !flags.isEmpty())
                flags.append( " " );
            flags.appendAscii( item.name );
        }
    }
    if( !flags.isEmpty())
        addKeyValue( "CPUFlags", flags.makeStringAndClear(), AddItem );
#endif
    // Get total memory.
    MEMORYSTATUSEX memoryStatus;
    memoryStatus.dwLength = sizeof( memoryStatus );
    if( GlobalMemoryStatusEx( &memoryStatus ))
    {
        addKeyValue( "MemoryTotal", OUString::number( int( memoryStatus.ullTotalPhys / 1024 ))
            + " kB", AddItem );
    }
}
#else
void CrashReporter::writeSystemInfo()
{
}
#endif

#endif //HAVE_FEATURE_BREAKPAD

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=94 H=95 G=94

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.