11#include <rtl/bootstrap.hxx>
12#include <osl/file.hxx>
18#include <rtl/ustrbuf.hxx>
20#include <config_version.h>
21#include <config_folders.h>
27#if HAVE_FEATURE_BREAKPAD
30#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
31#include <client/linux/handler/exception_handler.h>
34#pragma clang diagnostic push
35#pragma clang diagnostic ignored "-Wmicrosoft-enum-value"
37#include <client/windows/handler/exception_handler.h>
39#pragma clang diagnostic pop
45osl::Mutex CrashReporter::maMutex;
46osl::Mutex CrashReporter::maActiveSfxObjectNameMutex;
47osl::Mutex CrashReporter::maUnoLogCmdMutex;
48std::unique_ptr<google_breakpad::ExceptionHandler> CrashReporter::mpExceptionHandler;
49bool CrashReporter::mbInit =
false;
50CrashReporter::vmaKeyValues CrashReporter::maKeyValues;
51CrashReporter::vmaloggedUnoCommands CrashReporter::maloggedUnoCommands;
52OUString CrashReporter::msActiveSfxObjectName;
55#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
56static bool dumpCallback(
const google_breakpad::MinidumpDescriptor& descriptor,
void* ,
bool succeeded)
61 SAL_WARN(
"desktop",
"minidump generated: " << descriptor.path());
66static bool dumpCallback(
const wchar_t* path,
const wchar_t*
id,
67 void* , EXCEPTION_POINTERS* ,
73#pragma warning (disable: 4996)
75 std::wstring_convert<std::codecvt_utf8<wchar_t>> conv1;
76 std::string aPath = conv1.to_bytes(std::wstring(path)) + conv1.to_bytes(std::wstring(
id)) +
".dmp";
81 SAL_WARN(
"desktop",
"minidump generated: " << aPath);
87void CrashReporter::writeToFile(std::ios_base::openmode Openmode)
90 const std::string iniPath = getIniFileName();
91 std::wstring iniPathW;
92 const int nChars = MultiByteToWideChar(CP_UTF8, 0, iniPath.c_str(), -1,
nullptr, 0);
93 auto buf = std::make_unique<wchar_t[]>(nChars);
94 if (MultiByteToWideChar(CP_UTF8, 0, iniPath.c_str(), -1, buf.get(), nChars) != 0)
97 std::ofstream ini_file
98 = iniPathW.empty() ? std::ofstream(iniPath, Openmode) :
std::ofstream(iniPathW, Openmode);
100 std::ofstream ini_file(getIniFileName(), Openmode);
103 for (
auto& keyValue : maKeyValues)
115 osl::MutexGuard aGuard(maMutex);
120 maKeyValues.push_back(mpair(rKey, rValue));
125 writeToFile(std::ios_base::app);
126 else if (AddKeyHandling ==
Create)
132void CrashReporter::writeCommonInfo()
138 static constexpr OUStringLiteral protocol =
u"https";
139 static constexpr OUStringLiteral url =
u"crashreport.libreoffice.org";
140 const sal_Int32 port = 443;
145 vmaKeyValues atlast = maKeyValues;
155 if (!proxy_server.
aName.isEmpty())
161 maKeyValues.insert(maKeyValues.end(), atlast.begin(), atlast.end());
165 writeToFile(std::ios_base::trunc);
167 updateMinidumpLocation();
172 osl::MutexGuard aGuard(maActiveSfxObjectNameMutex);
173 msActiveSfxObjectName = rActiveSfxObjectName;
178 osl::MutexGuard aGuard(maActiveSfxObjectNameMutex);
179 return msActiveSfxObjectName;
184 osl::MutexGuard aGuard(maUnoLogCmdMutex);
186 if( maloggedUnoCommands.size() == 4 )
187 maloggedUnoCommands.pop_front();
189 maloggedUnoCommands.push_back(rUnoCommand);
194 osl::MutexGuard aGuard(maUnoLogCmdMutex);
196 OUString aCommandSeperator=
"";
197 OUStringBuffer aUnoCommandBuffer;
199 for(
auto& unocommand: maloggedUnoCommands)
201 aUnoCommandBuffer.append(aCommandSeperator + unocommand);
202 aCommandSeperator=
",";
204 return aUnoCommandBuffer.makeStringAndClear();
209OUString getCrashDirectory()
212 rtl::Bootstrap::get(
"CrashDirectory", aCrashURL);
214 osl::FileBase::getFileURLFromSystemPath(aCrashURL, aCrashURL);
216 if (aCrashURL.isEmpty()) {
217 aCrashURL =
"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE(
"bootstrap")
":UserInstallation}/crash/";
218 rtl::Bootstrap::expandMacros(aCrashURL);
221 if (!aCrashURL.endsWith(
"/"))
226 osl::FileBase::getSystemPathFromFileURL(aCrashURL, aCrashPath);
232void CrashReporter::updateMinidumpLocation()
234#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
235 OUString
aURL = getCrashDirectory();
237 google_breakpad::MinidumpDescriptor descriptor(std::string{aOStringUrl});
238 mpExceptionHandler->set_minidump_descriptor(descriptor);
240 OUString
aURL = getCrashDirectory();
241 mpExceptionHandler->set_dump_path(o3tl::toW(
aURL.getStr()));
245bool CrashReporter::crashReportInfoExists()
251bool CrashReporter::readSendConfig(std::string& response)
256void CrashReporter::installExceptionHandler()
260#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
261 google_breakpad::MinidumpDescriptor descriptor(
"/tmp");
262 mpExceptionHandler = std::make_unique<google_breakpad::ExceptionHandler>(descriptor,
nullptr, dumpCallback,
nullptr,
true, -1);
264 mpExceptionHandler = std::make_unique<google_breakpad::ExceptionHandler>(L
".",
nullptr, dumpCallback,
nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL);
268void CrashReporter::removeExceptionHandler()
270 mpExceptionHandler.reset();
275bool CrashReporter::IsDumpEnable()
277 auto const env = std::getenv(
"CRASH_DUMP_ENABLE");
278 if (env !=
nullptr && env[0] !=
'\0') {
283 if (rtl::Bootstrap::get(
"CrashDumpEnable", sToken))
285 return sToken.toBoolean();
291std::string CrashReporter::getIniFileName()
293 OUString url = getCrashDirectory() +
"dump.ini";
295 std::string aRet(aUrl);
303#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
304void CrashReporter::writeSystemInfo()
307 if( std::ifstream cpuinfo(
"/proc/cpuinfo" ); cpuinfo )
309 bool haveModel =
false;
310 bool haveFlags =
false;
311 std::regex modelRegex(
"^model name[ \t]*:[ \t]*(.*)$" );
312 std::regex flagsRegex(
"^flags[ \t]*:[ \t]*(.*)$" );
313 for( std::string line; std::getline( cpuinfo, line ); )
316 if( !haveModel && std::regex_match( line, match, modelRegex ) &&
match.size() == 2)
321 if( !haveFlags && std::regex_match( line, match, flagsRegex ) &&
match.size() == 2)
326 if( haveModel && haveFlags )
331 if( std::ifstream meminfo(
"/proc/meminfo" ); meminfo )
333 std::regex memTotalRegex(
"^MemTotal[ \t]*:[ \t]*(.*)$" );
334 for( std::string line; std::getline( meminfo, line ); )
337 if( std::regex_match( line, match, memTotalRegex ) &&
match.size() == 2)
346void CrashReporter::writeSystemInfo()
353 __cpuid( cpui, 0x80000000 );
354 unsigned int exIds = cpui[ 0 ];
355 if( exIds >= 0x80000004 )
358 __cpuidex( brand, 0x80000002, 0 );
359 __cpuidex( brand + 4, 0x80000003, 0 );
360 __cpuidex( brand + 8, 0x80000004, 0 );
362 addKeyValue(
"CPUModelName", OUString::fromUtf8(
reinterpret_cast< const char*
>( brand )),
367 unsigned int ecx1 = 0, edx1 = 0, ebx7 = 0, ecx7 = 0, ecx81 = 0, edx81 = 0;
370 __cpuidex( cpui, 0x1, 0 );
376 __cpuidex( cpui, 0x7, 0 );
380 if( exIds >= 0x80000001 )
382 __cpuidex( cpui, 0x80000001, 0 );
392 const FlagItem flagItems[] =
394 { &ecx1, 0,
"sse3" },
395 { &ecx1, 1,
"pclmulqdq" },
396 { &ecx1, 3,
"monitor" },
397 { &ecx1, 9,
"ssse3" },
398 { &ecx1, 12,
"fma" },
399 { &ecx1, 13,
"cpmxch16b" },
400 { &ecx1, 19,
"sse41" },
401 { &ecx1, 20,
"sse42" },
402 { &ecx1, 22,
"movbe" },
403 { &ecx1, 23,
"popcnt" },
404 { &ecx1, 25,
"aes" },
405 { &ecx1, 26,
"xsave" },
406 { &ecx1, 27,
"osxsave" },
407 { &ecx1, 28,
"avx" },
408 { &ecx1, 29,
"f16c" },
409 { &ecx1, 30,
"rdrand" },
412 { &edx1, 11,
"sep" },
413 { &edx1, 15,
"cmov" },
414 { &edx1, 19,
"clfsh" },
415 { &edx1, 23,
"mmx" },
416 { &edx1, 24,
"fxsr" },
417 { &edx1, 25,
"sse" },
418 { &edx1, 26,
"sse2" },
420 { &ebx7, 0,
"fsgsbase" },
421 { &ebx7, 3,
"bmi1" },
423 { &ebx7, 5,
"avx2" },
424 { &ebx7, 8,
"bmi2" },
425 { &ebx7, 9,
"erms" },
426 { &ebx7, 10,
"invpcid" },
427 { &ebx7, 11,
"rtm" },
428 { &ebx7, 16,
"avx512f" },
429 { &ebx7, 18,
"rdseed" },
430 { &ebx7, 19,
"adx" },
431 { &ebx7, 26,
"avx512pf" },
432 { &ebx7, 27,
"avx512er" },
433 { &ebx7, 28,
"avx512cd" },
434 { &ebx7, 29,
"sha" },
435 { &ecx7, 0,
"prefetchwt1" },
436 { &ecx81, 0,
"lahf" },
437 { &ecx81, 5,
"abm" },
438 { &ecx81, 6,
"sse4a" },
439 { &ecx81, 11,
"xop" },
440 { &ecx81, 21,
"tbm" },
441 { &edx81, 11,
"syscall" },
442 { &edx81, 22,
"mmxext" },
443 { &edx81, 27,
"rdtscp" },
444 { &edx81, 30,
"3dnowext" },
445 { &edx81, 31,
"3dnow" }
447 OUStringBuffer flags;
448 for(
const FlagItem& item : flagItems )
450 if( *item.reg & ( 1U << item.bit ))
452 if( !flags.isEmpty())
454 flags.appendAscii( item.name );
457 if( !flags.isEmpty())
461 MEMORYSTATUSEX memoryStatus;
462 memoryStatus.dwLength =
sizeof( memoryStatus );
463 if( GlobalMemoryStatusEx( &memoryStatus ))
465 addKeyValue(
"MemoryTotal", OUString::number(
int( memoryStatus.ullTotalPhys / 1024 ))
470void CrashReporter::writeSystemInfo()
static OUString getLoggedUnoCommands()
static void logUnoCommand(SAL_UNUSED_PARAMETER const OUString &)
static void setActiveSfxObjectName(SAL_UNUSED_PARAMETER const OUString &)
static OUString getActiveSfxObjectName()
static void addKeyValue(SAL_UNUSED_PARAMETER const OUString &, SAL_UNUSED_PARAMETER const OUString &, SAL_UNUSED_PARAMETER tAddKeyHandling)
static OUString getBuildIdData(OUString const &_sDefault)
#define SAL_CONFIGFILE(name)
#define SAL_WARN(area, stream)
const css::uno::Reference< css::xml::crypto::XSecurityEnvironment > & env
bool match(const sal_Unicode *pWild, const sal_Unicode *pStr, const sal_Unicode cEscape)
bool readConfig(const std::string &iniPath, std::string *response)
Read+Send, Test and send info from the Dump.ini .
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)