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 const OUStringLiteral protocol =
u"https";
139 static const 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);
202 aUnoCommandBuffer.append(unocommand);
203 aCommandSeperator=
",";
205 return aUnoCommandBuffer.makeStringAndClear();
210OUString getCrashDirectory()
213 rtl::Bootstrap::get(
"CrashDirectory", aCrashURL);
215 osl::FileBase::getFileURLFromSystemPath(aCrashURL, aCrashURL);
217 if (aCrashURL.isEmpty()) {
218 aCrashURL =
"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE(
"bootstrap")
":UserInstallation}/crash/";
219 rtl::Bootstrap::expandMacros(aCrashURL);
222 if (!aCrashURL.endsWith(
"/"))
227 osl::FileBase::getSystemPathFromFileURL(aCrashURL, aCrashPath);
233void CrashReporter::updateMinidumpLocation()
235#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
236 OUString
aURL = getCrashDirectory();
238 google_breakpad::MinidumpDescriptor descriptor(aOStringUrl.getStr());
239 mpExceptionHandler->set_minidump_descriptor(descriptor);
241 OUString
aURL = getCrashDirectory();
242 mpExceptionHandler->set_dump_path(o3tl::toW(
aURL.getStr()));
246bool CrashReporter::crashReportInfoExists()
252bool CrashReporter::readSendConfig(std::string& response)
257void CrashReporter::installExceptionHandler()
261#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
262 google_breakpad::MinidumpDescriptor descriptor(
"/tmp");
263 mpExceptionHandler = std::make_unique<google_breakpad::ExceptionHandler>(descriptor,
nullptr, dumpCallback,
nullptr,
true, -1);
265 mpExceptionHandler = std::make_unique<google_breakpad::ExceptionHandler>(L
".",
nullptr, dumpCallback,
nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL);
269void CrashReporter::removeExceptionHandler()
271 mpExceptionHandler.reset();
276bool CrashReporter::IsDumpEnable()
278 auto const env = std::getenv(
"CRASH_DUMP_ENABLE");
279 if (env !=
nullptr && env[0] !=
'\0') {
284 if (rtl::Bootstrap::get(
"CrashDumpEnable", sToken))
286 return sToken.toBoolean();
292std::string CrashReporter::getIniFileName()
294 OUString url = getCrashDirectory() +
"dump.ini";
296 std::string aRet(aUrl.getStr());
304#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
305void CrashReporter::writeSystemInfo()
308 if( std::ifstream cpuinfo(
"/proc/cpuinfo" ); cpuinfo )
310 bool haveModel =
false;
311 bool haveFlags =
false;
312 std::regex modelRegex(
"^model name[ \t]*:[ \t]*(.*)$" );
313 std::regex flagsRegex(
"^flags[ \t]*:[ \t]*(.*)$" );
314 for( std::string line; std::getline( cpuinfo, line ); )
317 if( !haveModel && std::regex_match( line, match, modelRegex ) &&
match.size() == 2)
322 if( !haveFlags && std::regex_match( line, match, flagsRegex ) &&
match.size() == 2)
327 if( haveModel && haveFlags )
332 if( std::ifstream meminfo(
"/proc/meminfo" ); meminfo )
334 std::regex memTotalRegex(
"^MemTotal[ \t]*:[ \t]*(.*)$" );
335 for( std::string line; std::getline( meminfo, line ); )
338 if( std::regex_match( line, match, memTotalRegex ) &&
match.size() == 2)
347void CrashReporter::writeSystemInfo()
354 __cpuid( cpui, 0x80000000 );
355 unsigned int exIds = cpui[ 0 ];
356 if( exIds >= 0x80000004 )
359 __cpuidex( brand, 0x80000002, 0 );
360 __cpuidex( brand + 4, 0x80000003, 0 );
361 __cpuidex( brand + 8, 0x80000004, 0 );
363 addKeyValue(
"CPUModelName", OUString::fromUtf8(
reinterpret_cast< const char*
>( brand )),
368 unsigned int ecx1 = 0, edx1 = 0, ebx7 = 0, ecx7 = 0, ecx81 = 0, edx81 = 0;
371 __cpuidex( cpui, 0x1, 0 );
377 __cpuidex( cpui, 0x7, 0 );
381 if( exIds >= 0x80000001 )
383 __cpuidex( cpui, 0x80000001, 0 );
393 const FlagItem flagItems[] =
395 { &ecx1, 0,
"sse3" },
396 { &ecx1, 1,
"pclmulqdq" },
397 { &ecx1, 3,
"monitor" },
398 { &ecx1, 9,
"ssse3" },
399 { &ecx1, 12,
"fma" },
400 { &ecx1, 13,
"cpmxch16b" },
401 { &ecx1, 19,
"sse41" },
402 { &ecx1, 20,
"sse42" },
403 { &ecx1, 22,
"movbe" },
404 { &ecx1, 23,
"popcnt" },
405 { &ecx1, 25,
"aes" },
406 { &ecx1, 26,
"xsave" },
407 { &ecx1, 27,
"osxsave" },
408 { &ecx1, 28,
"avx" },
409 { &ecx1, 29,
"f16c" },
410 { &ecx1, 30,
"rdrand" },
413 { &edx1, 11,
"sep" },
414 { &edx1, 15,
"cmov" },
415 { &edx1, 19,
"clfsh" },
416 { &edx1, 23,
"mmx" },
417 { &edx1, 24,
"fxsr" },
418 { &edx1, 25,
"sse" },
419 { &edx1, 26,
"sse2" },
421 { &ebx7, 0,
"fsgsbase" },
422 { &ebx7, 3,
"bmi1" },
424 { &ebx7, 5,
"avx2" },
425 { &ebx7, 8,
"bmi2" },
426 { &ebx7, 9,
"erms" },
427 { &ebx7, 10,
"invpcid" },
428 { &ebx7, 11,
"rtm" },
429 { &ebx7, 16,
"avx512f" },
430 { &ebx7, 18,
"rdseed" },
431 { &ebx7, 19,
"adx" },
432 { &ebx7, 26,
"avx512pf" },
433 { &ebx7, 27,
"avx512er" },
434 { &ebx7, 28,
"avx512cd" },
435 { &ebx7, 29,
"sha" },
436 { &ecx7, 0,
"prefetchwt1" },
437 { &ecx81, 0,
"lahf" },
438 { &ecx81, 5,
"abm" },
439 { &ecx81, 6,
"sse4a" },
440 { &ecx81, 11,
"xop" },
441 { &ecx81, 21,
"tbm" },
442 { &edx81, 11,
"syscall" },
443 { &edx81, 22,
"mmxext" },
444 { &edx81, 27,
"rdtscp" },
445 { &edx81, 30,
"3dnowext" },
446 { &edx81, 31,
"3dnow" }
448 OUStringBuffer flags;
449 for(
const FlagItem& item : flagItems )
451 if( *item.reg & ( 1U << item.bit ))
453 if( !flags.isEmpty())
455 flags.appendAscii( item.name );
458 if( !flags.isEmpty())
462 MEMORYSTATUSEX memoryStatus;
463 memoryStatus.dwLength =
sizeof( memoryStatus );
464 if( GlobalMemoryStatusEx( &memoryStatus ))
466 addKeyValue(
"MemoryTotal", OUString::number(
int( memoryStatus.ullTotalPhys / 1024 ))
471void 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)