Changeset - r27432:005dbba2ae93
[Not reviewed]
master
0 5 0
Rubidium - 13 months ago 2023-05-20 17:45:38
rubidium@openttd.org
Codechange: replace seprintf with fmt::format for filling the crash log data
5 files changed with 234 insertions and 315 deletions:
0 comments (0 inline, 0 general)
src/crashlog.cpp
Show inline comments
 
@@ -76,58 +76,54 @@
 

	
 
/* static */ std::string CrashLog::message{ "<none>" };
 

	
 
char *CrashLog::LogCompiler(char *buffer, const char *last) const
 
void CrashLog::LogCompiler(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
			buffer += seprintf(buffer, last, " Compiler: "
 
	fmt::format_to(output_iterator, " Compiler: "
 
#if defined(_MSC_VER)
 
			"MSVC %d", _MSC_VER
 
			"MSVC {}", _MSC_VER
 
#elif defined(__ICC) && defined(__GNUC__)
 
			"ICC %d (GCC %d.%d.%d mode)", __ICC,  __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__
 
			"ICC {} (GCC {}.{}.{} mode)", __ICC,  __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__
 
#elif defined(__ICC)
 
			"ICC %d", __ICC
 
			"ICC {}", __ICC
 
#elif defined(__GNUC__)
 
			"GCC %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__
 
			"GCC {}.{}.{}", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__
 
#elif defined(__WATCOMC__)
 
			"WatcomC %d", __WATCOMC__
 
			"WatcomC {}", __WATCOMC__
 
#else
 
			"<unknown>"
 
#endif
 
			);
 
#if defined(__VERSION__)
 
			return buffer + seprintf(buffer, last,  " \"" __VERSION__ "\"\n\n");
 
	fmt::format_to(output_iterator, " \"" __VERSION__ "\"\n\n");
 
#else
 
			return buffer + seprintf(buffer, last,  "\n\n");
 
	fmt::format_to(output_iterator, "\n\n");
 
#endif
 
}
 

	
 
/* virtual */ char *CrashLog::LogRegisters(char *buffer, const char *last) const
 
/* virtual */ void CrashLog::LogRegisters(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	/* Stub implementation; not all OSes support this. */
 
	return buffer;
 
}
 

	
 
/* virtual */ char *CrashLog::LogModules(char *buffer, const char *last) const
 
/* virtual */ void CrashLog::LogModules(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	/* Stub implementation; not all OSes support this. */
 
	return buffer;
 
}
 

	
 
/**
 
 * Writes OpenTTD's version to the buffer.
 
 * @param buffer The begin where to write at.
 
 * @param last   The last position in the buffer to write to.
 
 * @return the position of the \c '\0' character after the buffer.
 
 * @param output_iterator Iterator to write the output to.
 
 */
 
char *CrashLog::LogOpenTTDVersion(char *buffer, const char *last) const
 
void CrashLog::LogOpenTTDVersion(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	return buffer + seprintf(buffer, last,
 
	fmt::format_to(output_iterator,
 
			"OpenTTD version:\n"
 
			" Version:    %s (%d)\n"
 
			" NewGRF ver: %08x\n"
 
			" Bits:       %d\n"
 
			" Endian:     %s\n"
 
			" Dedicated:  %s\n"
 
			" Build date: %s\n\n",
 
			" Version:    {} ({})\n"
 
			" NewGRF ver: {:08x}\n"
 
			" Bits:       {}\n"
 
			" Endian:     {}\n"
 
			" Dedicated:  {}\n"
 
			" Build date: {}\n\n",
 
			_openttd_revision,
 
			_openttd_revision_modified,
 
			_openttd_newgrf_version,
 
@@ -153,83 +149,77 @@ char *CrashLog::LogOpenTTDVersion(char *
 
/**
 
 * Writes the (important) configuration settings to the buffer.
 
 * E.g. graphics set, sound set, blitter and AIs.
 
 * @param buffer The begin where to write at.
 
 * @param last   The last position in the buffer to write to.
 
 * @return the position of the \c '\0' character after the buffer.
 
 * @param output_iterator Iterator to write the output to.
 
 */
 
char *CrashLog::LogConfiguration(char *buffer, const char *last) const
 
void CrashLog::LogConfiguration(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	buffer += seprintf(buffer, last,
 
	fmt::format_to(output_iterator,
 
			"Configuration:\n"
 
			" Blitter:      %s\n"
 
			" Graphics set: %s (%u)\n"
 
			" Language:     %s\n"
 
			" Music driver: %s\n"
 
			" Music set:    %s (%u)\n"
 
			" Network:      %s\n"
 
			" Sound driver: %s\n"
 
			" Sound set:    %s (%u)\n"
 
			" Video driver: %s\n\n",
 
			" Blitter:      {}\n"
 
			" Graphics set: {} ({})\n"
 
			" Language:     {}\n"
 
			" Music driver: {}\n"
 
			" Music set:    {} ({})\n"
 
			" Network:      {}\n"
 
			" Sound driver: {}\n"
 
			" Sound set:    {} ({})\n"
 
			" Video driver: {}\n\n",
 
			BlitterFactory::GetCurrentBlitter() == nullptr ? "none" : BlitterFactory::GetCurrentBlitter()->GetName(),
 
			BaseGraphics::GetUsedSet() == nullptr ? "none" : BaseGraphics::GetUsedSet()->name.c_str(),
 
			BaseGraphics::GetUsedSet() == nullptr ? "none" : BaseGraphics::GetUsedSet()->name,
 
			BaseGraphics::GetUsedSet() == nullptr ? UINT32_MAX : BaseGraphics::GetUsedSet()->version,
 
			_current_language == nullptr ? "none" : _current_language->file,
 
			MusicDriver::GetInstance() == nullptr ? "none" : MusicDriver::GetInstance()->GetName(),
 
			BaseMusic::GetUsedSet() == nullptr ? "none" : BaseMusic::GetUsedSet()->name.c_str(),
 
			BaseMusic::GetUsedSet() == nullptr ? "none" : BaseMusic::GetUsedSet()->name,
 
			BaseMusic::GetUsedSet() == nullptr ? UINT32_MAX : BaseMusic::GetUsedSet()->version,
 
			_networking ? (_network_server ? "server" : "client") : "no",
 
			SoundDriver::GetInstance() == nullptr ? "none" : SoundDriver::GetInstance()->GetName(),
 
			BaseSounds::GetUsedSet() == nullptr ? "none" : BaseSounds::GetUsedSet()->name.c_str(),
 
			BaseSounds::GetUsedSet() == nullptr ? "none" : BaseSounds::GetUsedSet()->name,
 
			BaseSounds::GetUsedSet() == nullptr ? UINT32_MAX : BaseSounds::GetUsedSet()->version,
 
			VideoDriver::GetInstance() == nullptr ? "none" : VideoDriver::GetInstance()->GetInfoString()
 
	);
 

	
 
	buffer += seprintf(buffer, last,
 
	fmt::format_to(output_iterator,
 
			"Fonts:\n"
 
			" Small:  %s\n"
 
			" Medium: %s\n"
 
			" Large:  %s\n"
 
			" Mono:   %s\n\n",
 
			" Small:  {}\n"
 
			" Medium: {}\n"
 
			" Large:  {}\n"
 
			" Mono:   {}\n\n",
 
			FontCache::Get(FS_SMALL)->GetFontName(),
 
			FontCache::Get(FS_NORMAL)->GetFontName(),
 
			FontCache::Get(FS_LARGE)->GetFontName(),
 
			FontCache::Get(FS_MONO)->GetFontName()
 
	);
 

	
 
	buffer += seprintf(buffer, last, "AI Configuration (local: %i) (current: %i):\n", (int)_local_company, (int)_current_company);
 
	fmt::format_to(output_iterator, "AI Configuration (local: {}) (current: {}):\n", _local_company, _current_company);
 
	for (const Company *c : Company::Iterate()) {
 
		if (c->ai_info == nullptr) {
 
			buffer += seprintf(buffer, last, " %2i: Human\n", (int)c->index);
 
			fmt::format_to(output_iterator, " {:2}: Human\n", c->index);
 
		} else {
 
			buffer += seprintf(buffer, last, " %2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName().c_str(), c->ai_info->GetVersion());
 
			fmt::format_to(output_iterator, " {:2}: {} (v{})\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
 
		}
 
	}
 

	
 
	if (Game::GetInfo() != nullptr) {
 
		buffer += seprintf(buffer, last, " GS: %s (v%d)\n", Game::GetInfo()->GetName().c_str(), Game::GetInfo()->GetVersion());
 
		fmt::format_to(output_iterator, " GS: {} (v{})\n", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion());
 
	}
 
	buffer += seprintf(buffer, last, "\n");
 

	
 
	return buffer;
 
	fmt::format_to(output_iterator, "\n");
 
}
 

	
 
/**
 
 * Writes information (versions) of the used libraries.
 
 * @param buffer The begin where to write at.
 
 * @param last   The last position in the buffer to write to.
 
 * @return the position of the \c '\0' character after the buffer.
 
 * @param output_iterator Iterator to write the output to.
 
 */
 
char *CrashLog::LogLibraries(char *buffer, const char *last) const
 
void CrashLog::LogLibraries(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	buffer += seprintf(buffer, last, "Libraries:\n");
 
	fmt::format_to(output_iterator, "Libraries:\n");
 

	
 
#ifdef WITH_ALLEGRO
 
	buffer += seprintf(buffer, last, " Allegro:    %s\n", allegro_id);
 
	fmt::format_to(output_iterator, " Allegro:    {}\n", allegro_id);
 
#endif /* WITH_ALLEGRO */
 

	
 
#ifdef WITH_FONTCONFIG
 
	int version = FcGetVersion();
 
	buffer += seprintf(buffer, last, " FontConfig: %d.%d.%d\n", version / 10000, (version / 100) % 100, version % 100);
 
	fmt::format_to(output_iterator, " FontConfig: {}.{}.{}\n", version / 10000, (version / 100) % 100, version % 100);
 
#endif /* WITH_FONTCONFIG */
 

	
 
#ifdef WITH_FREETYPE
 
@@ -238,11 +228,11 @@ char *CrashLog::LogLibraries(char *buffe
 
	FT_Init_FreeType(&library);
 
	FT_Library_Version(library, &major, &minor, &patch);
 
	FT_Done_FreeType(library);
 
	buffer += seprintf(buffer, last, " FreeType:   %d.%d.%d\n", major, minor, patch);
 
	fmt::format_to(output_iterator, " FreeType:   {}.{}.{}\n", major, minor, patch);
 
#endif /* WITH_FREETYPE */
 

	
 
#if defined(WITH_HARFBUZZ)
 
	buffer += seprintf(buffer, last, " HarfBuzz:   %s\n", hb_version_string());
 
	fmt::format_to(output_iterator, " HarfBuzz:   {}\n", hb_version_string());
 
#endif /* WITH_HARFBUZZ */
 

	
 
#if defined(WITH_ICU_I18N)
 
@@ -251,82 +241,76 @@ char *CrashLog::LogLibraries(char *buffe
 
	UVersionInfo ver;
 
	u_getVersion(ver);
 
	u_versionToString(ver, buf);
 
	buffer += seprintf(buffer, last, " ICU i18n:   %s\n", buf);
 
	fmt::format_to(output_iterator, " ICU i18n:   {}\n", buf);
 
#endif /* WITH_ICU_I18N */
 

	
 
#ifdef WITH_LIBLZMA
 
	buffer += seprintf(buffer, last, " LZMA:       %s\n", lzma_version_string());
 
	fmt::format_to(output_iterator, " LZMA:       {}\n", lzma_version_string());
 
#endif
 

	
 
#ifdef WITH_LZO
 
	buffer += seprintf(buffer, last, " LZO:        %s\n", lzo_version_string());
 
	fmt::format_to(output_iterator, " LZO:        {}\n", lzo_version_string());
 
#endif
 

	
 
#ifdef WITH_PNG
 
	buffer += seprintf(buffer, last, " PNG:        %s\n", png_get_libpng_ver(nullptr));
 
	fmt::format_to(output_iterator, " PNG:        {}\n", png_get_libpng_ver(nullptr));
 
#endif /* WITH_PNG */
 

	
 
#ifdef WITH_SDL
 
	const SDL_version *sdl_v = SDL_Linked_Version();
 
	buffer += seprintf(buffer, last, " SDL1:       %d.%d.%d\n", sdl_v->major, sdl_v->minor, sdl_v->patch);
 
	fmt::format_to(output_iterator, " SDL1:       {}.{}.{}\n", sdl_v->major, sdl_v->minor, sdl_v->patch);
 
#elif defined(WITH_SDL2)
 
	SDL_version sdl2_v;
 
	SDL_GetVersion(&sdl2_v);
 
	buffer += seprintf(buffer, last, " SDL2:       %d.%d.%d\n", sdl2_v.major, sdl2_v.minor, sdl2_v.patch);
 
	fmt::format_to(output_iterator, " SDL2:       {}.{}.{}\n", sdl2_v.major, sdl2_v.minor, sdl2_v.patch);
 
#endif
 

	
 
#ifdef WITH_ZLIB
 
	buffer += seprintf(buffer, last, " Zlib:       %s\n", zlibVersion());
 
	fmt::format_to(output_iterator, " Zlib:       {}\n", zlibVersion());
 
#endif
 

	
 
#ifdef WITH_CURL
 
	auto *curl_v = curl_version_info(CURLVERSION_NOW);
 
	buffer += seprintf(buffer, last, " Curl:       %s\n", curl_v->version);
 
	fmt::format_to(output_iterator, " Curl:       {}\n", curl_v->version);
 
	if (curl_v->ssl_version != nullptr) {
 
		buffer += seprintf(buffer, last, " Curl SSL:   %s\n", curl_v->ssl_version);
 
		fmt::format_to(output_iterator, " Curl SSL:   {}\n", curl_v->ssl_version);
 
	} else {
 
		buffer += seprintf(buffer, last, " Curl SSL:   none\n");
 
		fmt::format_to(output_iterator, " Curl SSL:   none\n");
 
	}
 
#endif
 

	
 
	buffer += seprintf(buffer, last, "\n");
 
	return buffer;
 
	fmt::format_to(output_iterator, "\n");
 
}
 

	
 
/**
 
 * Writes the gamelog data to the buffer.
 
 * @param buffer The begin where to write at.
 
 * @param last   The last position in the buffer to write to.
 
 * @return the position of the \c '\0' character after the buffer.
 
 * @param output_iterator Iterator to write the output to.
 
 */
 
char *CrashLog::LogGamelog(char *buffer, const char *last) const
 
void CrashLog::LogGamelog(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	_gamelog.Print([&buffer, last](const std::string &s) {
 
		buffer += seprintf(buffer, last, "%s\n", s.c_str());
 
	_gamelog.Print([&output_iterator](const std::string &s) {
 
		fmt::format_to(output_iterator, "{}\n", s);
 
	});
 
	return buffer + seprintf(buffer, last, "\n");
 
	fmt::format_to(output_iterator, "\n");
 
}
 

	
 
/**
 
 * Writes up to 32 recent news messages to the buffer, with the most recent first.
 
 * @param buffer The begin where to write at.
 
 * @param last   The last position in the buffer to write to.
 
 * @return the position of the \c '\0' character after the buffer.
 
 * @param output_iterator Iterator to write the output to.
 
 */
 
char *CrashLog::LogRecentNews(char *buffer, const char *last) const
 
void CrashLog::LogRecentNews(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	buffer += seprintf(buffer, last, "Recent news messages:\n");
 
	fmt::format_to(output_iterator, "Recent news messages:\n");
 

	
 
	int i = 0;
 
	for (NewsItem *news = _latest_news; i < 32 && news != nullptr; news = news->prev, i++) {
 
		TimerGameCalendar::YearMonthDay ymd;
 
		TimerGameCalendar::ConvertDateToYMD(news->date, &ymd);
 
		buffer += seprintf(buffer, last, "(%i-%02i-%02i) StringID: %u, Type: %u, Ref1: %u, %u, Ref2: %u, %u\n",
 
		fmt::format_to(output_iterator, "({}-{:02}-{:02}) StringID: {}, Type: {}, Ref1: {}, {}, Ref2: {}, {}\n",
 
		                   ymd.year, ymd.month + 1, ymd.day, news->string_id, news->type,
 
		                   news->reftype1, news->ref1, news->reftype2, news->ref2);
 
	}
 
	buffer += seprintf(buffer, last, "\n");
 
	return buffer;
 
	fmt::format_to(output_iterator, "\n");
 
}
 

	
 
/**
 
@@ -349,34 +333,30 @@ int CrashLog::CreateFileName(char *filen
 

	
 
/**
 
 * Fill the crash log buffer with all data of a crash log.
 
 * @param buffer The begin where to write at.
 
 * @param last   The last position in the buffer to write to.
 
 * @return the position of the \c '\0' character after the buffer.
 
 * @param output_iterator Iterator to write the output to.
 
 */
 
char *CrashLog::FillCrashLog(char *buffer, const char *last) const
 
void CrashLog::FillCrashLog(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\n\n");
 
	std::string temp = fmt::format("Crash at: {:%Y-%m-%d %H:%M:%S} (UTC)\n", fmt::gmtime(time(nullptr)));
 
	buffer = strecpy(buffer, temp.c_str(), last);
 
	fmt::format_to(output_iterator, "*** OpenTTD Crash Report ***\n\n");
 
	fmt::format_to(output_iterator, "Crash at: {:%Y-%m-%d %H:%M:%S} (UTC)\n", fmt::gmtime(time(nullptr)));
 

	
 
	TimerGameCalendar::YearMonthDay ymd;
 
	TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
 
	buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i)\n\n", ymd.year, ymd.month + 1, ymd.day, TimerGameCalendar::date_fract);
 
	fmt::format_to(output_iterator, "In game date: {}-{:02}-{:02} ({})\n\n", ymd.year, ymd.month + 1, ymd.day, TimerGameCalendar::date_fract);
 

	
 
	buffer = this->LogError(buffer, last, CrashLog::message.c_str());
 
	buffer = this->LogOpenTTDVersion(buffer, last);
 
	buffer = this->LogRegisters(buffer, last);
 
	buffer = this->LogStacktrace(buffer, last);
 
	buffer = this->LogOSVersion(buffer, last);
 
	buffer = this->LogCompiler(buffer, last);
 
	buffer = this->LogConfiguration(buffer, last);
 
	buffer = this->LogLibraries(buffer, last);
 
	buffer = this->LogModules(buffer, last);
 
	buffer = this->LogGamelog(buffer, last);
 
	buffer = this->LogRecentNews(buffer, last);
 
	this->LogError(output_iterator, CrashLog::message);
 
	this->LogOpenTTDVersion(output_iterator);
 
	this->LogRegisters(output_iterator);
 
	this->LogStacktrace(output_iterator);
 
	this->LogOSVersion(output_iterator);
 
	this->LogCompiler(output_iterator);
 
	this->LogConfiguration(output_iterator);
 
	this->LogLibraries(output_iterator);
 
	this->LogModules(output_iterator);
 
	this->LogGamelog(output_iterator);
 
	this->LogRecentNews(output_iterator);
 

	
 
	buffer += seprintf(buffer, last, "*** End of OpenTTD Crash Report ***\n");
 
	return buffer;
 
	fmt::format_to(output_iterator, "*** End of OpenTTD Crash Report ***\n");
 
}
 

	
 
/**
 
@@ -475,16 +455,18 @@ bool CrashLog::MakeCrashLog() const
 
	crashlogged = true;
 

	
 
	char filename[MAX_PATH];
 
	char buffer[65536];
 
	std::string buffer;
 
	buffer.reserve(65536);
 
	auto output_iterator = std::back_inserter(buffer);
 
	bool ret = true;
 

	
 
	fmt::print("Crash encountered, generating crash log...\n");
 
	this->FillCrashLog(buffer, lastof(buffer));
 
	this->FillCrashLog(output_iterator);
 
	fmt::print("{}\n", buffer);
 
	fmt::print("Crash log generated.\n\n");
 

	
 
	fmt::print("Writing crash log to disk...\n");
 
	bool bret = this->WriteCrashLog(buffer, filename, lastof(filename));
 
	bool bret = this->WriteCrashLog(buffer.c_str(), filename, lastof(filename));
 
	if (bret) {
 
		fmt::print("Crash log written to {}. Please add this file to any bug reports.\n\n", filename);
 
	} else {
src/crashlog.h
Show inline comments
 
@@ -20,62 +20,50 @@ private:
 
protected:
 
	/**
 
	 * Writes OS' version to the buffer.
 
	 * @param buffer The begin where to write at.
 
	 * @param last   The last position in the buffer to write to.
 
	 * @return the position of the \c '\0' character after the buffer.
 
	 * @param output_iterator Iterator to write the output to.
 
	 */
 
	virtual char *LogOSVersion(char *buffer, const char *last) const = 0;
 
	virtual void LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const = 0;
 

	
 
	/**
 
	 * Writes compiler (and its version, if available) to the buffer.
 
	 * @param buffer The begin where to write at.
 
	 * @param last   The last position in the buffer to write to.
 
	 * @return the position of the \c '\0' character after the buffer.
 
	 * @param output_iterator Iterator to write the output to.
 
	 */
 
	virtual char *LogCompiler(char *buffer, const char *last) const;
 
	virtual void LogCompiler(std::back_insert_iterator<std::string> &output_iterator) const;
 

	
 
	/**
 
	 * Writes actually encountered error to the buffer.
 
	 * @param buffer  The begin where to write at.
 
	 * @param last    The last position in the buffer to write to.
 
	 * @param output_iterator Iterator to write the output to.
 
	 * @param message Message passed to use for errors.
 
	 * @return the position of the \c '\0' character after the buffer.
 
	 */
 
	virtual char *LogError(char *buffer, const char *last, const char *message) const = 0;
 
	virtual void LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const = 0;
 

	
 
	/**
 
	 * Writes the stack trace to the buffer, if there is information about it
 
	 * available.
 
	 * @param buffer The begin where to write at.
 
	 * @param last   The last position in the buffer to write to.
 
	 * @return the position of the \c '\0' character after the buffer.
 
	 * @param output_iterator Iterator to write the output to.
 
	 */
 
	virtual char *LogStacktrace(char *buffer, const char *last) const = 0;
 
	virtual void LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const = 0;
 

	
 
	/**
 
	 * Writes information about the data in the registers, if there is
 
	 * information about it available.
 
	 * @param buffer The begin where to write at.
 
	 * @param last   The last position in the buffer to write to.
 
	 * @return the position of the \c '\0' character after the buffer.
 
	 * @param output_iterator Iterator to write the output to.
 
	 */
 
	virtual char *LogRegisters(char *buffer, const char *last) const;
 
	virtual void LogRegisters(std::back_insert_iterator<std::string> &output_iterator) const;
 

	
 
	/**
 
	 * Writes the dynamically linked libraries/modules to the buffer, if there
 
	 * is information about it available.
 
	 * @param buffer The begin where to write at.
 
	 * @param last   The last position in the buffer to write to.
 
	 * @return the position of the \c '\0' character after the buffer.
 
	 * @param output_iterator Iterator to write the output to.
 
	 */
 
	virtual char *LogModules(char *buffer, const char *last) const;
 
	virtual void LogModules(std::back_insert_iterator<std::string> &output_iterator) const;
 

	
 

	
 
	char *LogOpenTTDVersion(char *buffer, const char *last) const;
 
	char *LogConfiguration(char *buffer, const char *last) const;
 
	char *LogLibraries(char *buffer, const char *last) const;
 
	char *LogGamelog(char *buffer, const char *last) const;
 
	char *LogRecentNews(char *buffer, const char *list) const;
 
	void LogOpenTTDVersion(std::back_insert_iterator<std::string> &output_iterator) const;
 
	void LogConfiguration(std::back_insert_iterator<std::string> &output_iterator) const;
 
	void LogLibraries(std::back_insert_iterator<std::string> &output_iterator) const;
 
	void LogGamelog(std::back_insert_iterator<std::string> &output_iterator) const;
 
	void LogRecentNews(std::back_insert_iterator<std::string> &output_iterator) const;
 

	
 
	int CreateFileName(char *filename, const char *filename_last, const char *ext, bool with_dir = true) const;
 

	
 
@@ -83,7 +71,7 @@ public:
 
	/** Stub destructor to silence some compilers. */
 
	virtual ~CrashLog() = default;
 

	
 
	char *FillCrashLog(char *buffer, const char *last) const;
 
	void FillCrashLog(std::back_insert_iterator<std::string> &output_iterator) const;
 
	bool WriteCrashLog(const char *buffer, char *filename, const char *filename_last) const;
 

	
 
	/**
src/os/macosx/crashlog_osx.cpp
Show inline comments
 
@@ -31,13 +31,6 @@
 
#define IS_ALIGNED(addr) (((uintptr_t)(addr) & 0xf) == 0)
 
#endif
 

	
 
/* printf format specification for 32/64-bit addresses. */
 
#ifdef __LP64__
 
#define PRINTF_PTR "0x%016lx"
 
#else
 
#define PRINTF_PTR "0x%08lx"
 
#endif
 

	
 
#define MAX_STACK_FRAMES 64
 

	
 
/**
 
@@ -51,20 +44,20 @@ class CrashLogOSX : public CrashLog {
 
	char filename_save[MAX_PATH];       ///< Path of crash.sav
 
	char filename_screenshot[MAX_PATH]; ///< Path of crash.(png|bmp|pcx)
 

	
 
	char *LogOSVersion(char *buffer, const char *last) const override
 
	void LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const override
 
	{
 
		int ver_maj, ver_min, ver_bug;
 
		GetMacOSVersion(&ver_maj, &ver_min, &ver_bug);
 

	
 
		const NXArchInfo *arch = NXGetLocalArchInfo();
 

	
 
		return buffer + seprintf(buffer, last,
 
		fmt::format_to(output_iterator,
 
				"Operating system:\n"
 
				" Name:     Mac OS X\n"
 
				" Release:  %d.%d.%d\n"
 
				" Machine:  %s\n"
 
				" Min Ver:  %d\n"
 
				" Max Ver:  %d\n",
 
				" Release:  {}.{}.{}\n"
 
				" Machine:  {}\n"
 
				" Min Ver:  {}\n"
 
				" Max Ver:  {}\n",
 
				ver_maj, ver_min, ver_bug,
 
				arch != nullptr ? arch->description : "unknown",
 
				MAC_OS_X_VERSION_MIN_REQUIRED,
 
@@ -72,25 +65,25 @@ class CrashLogOSX : public CrashLog {
 
		);
 
	}
 

	
 
	char *LogError(char *buffer, const char *last, const char *message) const override
 
	void LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const override
 
	{
 
		return buffer + seprintf(buffer, last,
 
		fmt::format_to(output_iterator,
 
				"Crash reason:\n"
 
				" Signal:  %s (%d)\n"
 
				" Message: %s\n\n",
 
				" Signal:  {} ({})\n"
 
				" Message: {}\n\n",
 
				strsignal(this->signum),
 
				this->signum,
 
				message
 
		);
 
	}
 

	
 
	char *LogStacktrace(char *buffer, const char *last) const override
 
	void LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const override
 
	{
 
		/* As backtrace() is only implemented in 10.5 or later,
 
		 * we're rolling our own here. Mostly based on
 
		 * http://stackoverflow.com/questions/289820/getting-the-current-stack-trace-on-mac-os-x
 
		 * and some details looked up in the Darwin sources. */
 
		buffer += seprintf(buffer, last, "\nStacktrace:\n");
 
		fmt::format_to(output_iterator, "\nStacktrace:\n");
 

	
 
		void **frame;
 
#if defined(__ppc__) || defined(__ppc64__)
 
@@ -110,7 +103,7 @@ class CrashLogOSX : public CrashLog {
 
			if (ip == nullptr) break;
 

	
 
			/* Print running index. */
 
			buffer += seprintf(buffer, last, " [%02d]", i);
 
			fmt::format_to(output_iterator, " [{:02}]", i);
 

	
 
			Dl_info dli;
 
			bool dl_valid = dladdr(ip, &dli) != 0;
 
@@ -126,7 +119,7 @@ class CrashLogOSX : public CrashLog {
 
				}
 
			}
 
			/* Print image name and IP. */
 
			buffer += seprintf(buffer, last, " %-20s " PRINTF_PTR, fname, (uintptr_t)ip);
 
			fmt::format_to(output_iterator, " {:20s} {}", fname, (uintptr_t)ip);
 

	
 
			/* Print function offset if information is available. */
 
			if (dl_valid && dli.dli_sname != nullptr && dli.dli_saddr != nullptr) {
 
@@ -135,11 +128,11 @@ class CrashLogOSX : public CrashLog {
 
				char *func_name = abi::__cxa_demangle(dli.dli_sname, nullptr, 0, &status);
 

	
 
				long int offset = (intptr_t)ip - (intptr_t)dli.dli_saddr;
 
				buffer += seprintf(buffer, last, " (%s + %ld)", func_name != nullptr ? func_name : dli.dli_sname, offset);
 
				fmt::format_to(output_iterator, " ({} + {})", func_name != nullptr ? func_name : dli.dli_sname, offset);
 

	
 
				free(func_name);
 
			}
 
			buffer += seprintf(buffer, last, "\n");
 
			fmt::format_to(output_iterator, "\n");
 

	
 
			/* Get address of next stack frame. */
 
			void **next = (void **)frame[0];
 
@@ -148,7 +141,7 @@ class CrashLogOSX : public CrashLog {
 
			frame = next;
 
		}
 

	
 
		return buffer + seprintf(buffer, last, "\n");
 
		fmt::format_to(output_iterator, "\n");
 
	}
 

	
 
public:
 
@@ -163,40 +156,6 @@ public:
 
		filename_screenshot[0] = '\0';
 
	}
 

	
 
	/** Generate the crash log. */
 
	bool MakeCrashLog()
 
	{
 
		char buffer[65536];
 
		bool ret = true;
 

	
 
		fmt::print("Crash encountered, generating crash log...\n");
 
		this->FillCrashLog(buffer, lastof(buffer));
 
		fmt::print("{}\n", buffer);
 
		fmt::print("Crash log generated.\n\n");
 

	
 
		fmt::print("Writing crash log to disk...\n");
 
		if (!this->WriteCrashLog(buffer, filename_log, lastof(filename_log))) {
 
			filename_log[0] = '\0';
 
			ret = false;
 
		}
 

	
 
		fmt::print("Writing crash savegame...\n");
 
		if (!this->WriteSavegame(filename_save, lastof(filename_save))) {
 
			filename_save[0] = '\0';
 
			ret = false;
 
		}
 

	
 
		fmt::print("Writing crash screenshot...\n");
 
		if (!this->WriteScreenshot(filename_screenshot, lastof(filename_screenshot))) {
 
			filename_screenshot[0] = '\0';
 
			ret = false;
 
		}
 

	
 
		this->SendSurvey();
 

	
 
		return ret;
 
	}
 

	
 
	/** Show a dialog with the crash information. */
 
	void DisplayCrashDialog() const
 
	{
src/os/unix/crashlog_unix.cpp
Show inline comments
 
@@ -38,19 +38,20 @@ class CrashLogUnix : public CrashLog {
 
	/** Signal that has been thrown. */
 
	int signum;
 

	
 
	char *LogOSVersion(char *buffer, const char *last) const override
 
	void LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const override
 
	{
 
		struct utsname name;
 
		if (uname(&name) < 0) {
 
			return buffer + seprintf(buffer, last, "Could not get OS version: %s\n", strerror(errno));
 
			 fmt::format_to(output_iterator, "Could not get OS version: {}\n", strerror(errno));
 
			 return;
 
		}
 

	
 
		return buffer + seprintf(buffer, last,
 
		fmt::format_to(output_iterator,
 
				"Operating system:\n"
 
				" Name:     %s\n"
 
				" Release:  %s\n"
 
				" Version:  %s\n"
 
				" Machine:  %s\n",
 
				" Name:     {}\n"
 
				" Release:  {}\n"
 
				" Version:  {}\n"
 
				" Machine:  {}\n",
 
				name.sysname,
 
				name.release,
 
				name.version,
 
@@ -58,12 +59,12 @@ class CrashLogUnix : public CrashLog {
 
		);
 
	}
 

	
 
	char *LogError(char *buffer, const char *last, const char *message) const override
 
	void LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const override
 
	{
 
		return buffer + seprintf(buffer, last,
 
				"Crash reason:\n"
 
				" Signal:  %s (%d)\n"
 
				" Message: %s\n\n",
 
		fmt::format_to(output_iterator,
 
			   "Crash reason:\n"
 
				" Signal:  {} ({})\n"
 
				" Message: {}\n\n",
 
				strsignal(this->signum),
 
				this->signum,
 
				message
 
@@ -73,9 +74,8 @@ class CrashLogUnix : public CrashLog {
 
#if defined(SUNOS)
 
	/** Data needed while walking up the stack */
 
	struct StackWalkerParams {
 
		char **bufptr;    ///< Buffer
 
		const char *last; ///< End of buffer
 
		int counter;      ///< We are at counter-th stack level
 
		std::back_insert_iterator<std::string> *output_iterator; ///< Buffer
 
		int counter; ///< We are at counter-th stack level
 
	};
 

	
 
	/**
 
@@ -92,10 +92,10 @@ class CrashLogUnix : public CrashLog {
 
		/* Resolve program counter to file and nearest symbol (if possible) */
 
		Dl_info dli;
 
		if (dladdr((void *)pc, &dli) != 0) {
 
			*wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] %s(%s+0x%x) [0x%x]\n",
 
			fmt::format_to(*wp->output_iterator, " [{:02}] {}({}+0x{:x}) [0x{:x}]\n",
 
					wp->counter, dli.dli_fname, dli.dli_sname, (int)((byte *)pc - (byte *)dli.dli_saddr), (uint)pc);
 
		} else {
 
			*wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] [0x%x]\n", wp->counter, (uint)pc);
 
			fmt::format_to(*wp->output_iterator, " [{:02}] [0x{:x}]\n", wp->counter, (uint)pc);
 
		}
 
		wp->counter++;
 

	
 
@@ -103,31 +103,31 @@ class CrashLogUnix : public CrashLog {
 
	}
 
#endif
 

	
 
	char *LogStacktrace(char *buffer, const char *last) const override
 
	void LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const override
 
	{
 
		buffer += seprintf(buffer, last, "Stacktrace:\n");
 
		fmt::format_to(output_iterator, "Stacktrace:\n");
 
#if defined(__GLIBC__)
 
		void *trace[64];
 
		int trace_size = backtrace(trace, lengthof(trace));
 

	
 
		char **messages = backtrace_symbols(trace, trace_size);
 
		for (int i = 0; i < trace_size; i++) {
 
			buffer += seprintf(buffer, last, " [%02i] %s\n", i, messages[i]);
 
			fmt::format_to(output_iterator, " [{:02}] {}\n", i, messages[i]);
 
		}
 
		free(messages);
 
#elif defined(SUNOS)
 
		ucontext_t uc;
 
		if (getcontext(&uc) != 0) {
 
			buffer += seprintf(buffer, last, " getcontext() failed\n\n");
 
			fmt::format_to(output_iterator, " getcontext() failed\n\n");
 
			return buffer;
 
		}
 

	
 
		StackWalkerParams wp = { &buffer, last, 0 };
 
		StackWalkerParams wp = { &output_iterator, 0 };
 
		walkcontext(&uc, &CrashLogUnix::SunOSStackWalker, &wp);
 
#else
 
		buffer += seprintf(buffer, last, " Not supported.\n");
 
		fmt::format_to(output_iterator, " Not supported.\n");
 
#endif
 
		return buffer + seprintf(buffer, last, "\n");
 
		fmt::format_to(output_iterator, "\n");
 
	}
 
public:
 
	/**
src/os/windows/crashlog_win.cpp
Show inline comments
 
@@ -25,13 +25,6 @@
 

	
 
#include "../../safeguards.h"
 

	
 
/* printf format specification for 32/64-bit addresses. */
 
#ifdef _M_AMD64
 
#define PRINTF_PTR "0x%016IX"
 
#else
 
#define PRINTF_PTR "0x%08X"
 
#endif
 

	
 
/**
 
 * Windows implementation for the crash logger.
 
 */
 
@@ -39,21 +32,21 @@ class CrashLogWindows : public CrashLog 
 
	/** Information about the encountered exception */
 
	EXCEPTION_POINTERS *ep;
 

	
 
	char *LogOSVersion(char *buffer, const char *last) const override;
 
	char *LogError(char *buffer, const char *last, const char *message) const override;
 
	char *LogStacktrace(char *buffer, const char *last) const override;
 
	char *LogRegisters(char *buffer, const char *last) const override;
 
	char *LogModules(char *buffer, const char *last) const override;
 
	void LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const override;
 
	void LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const override;
 
	void LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const override;
 
	void LogRegisters(std::back_insert_iterator<std::string> &output_iterator) const override;
 
	void LogModules(std::back_insert_iterator<std::string> &output_iterator) const override;
 
public:
 
#if defined(_MSC_VER)
 
	int WriteCrashDump(char *filename, const char *filename_last) const override;
 
	char *AppendDecodedStacktrace(char *buffer, const char *last) const;
 
	void AppendDecodedStacktrace(std::back_insert_iterator<std::string> &output_iterator) const;
 
#else
 
	char *AppendDecodedStacktrace(char *buffer, const char *last) const { return buffer; }
 
	void AppendDecodedStacktrace(std::back_insert_iterator<std::string> &output_iterator) const {}
 
#endif /* _MSC_VER */
 

	
 
	/** Buffer for the generated crash log */
 
	char crashlog[65536];
 
	std::string crashlog;
 
	/** Buffer for the filename of the crash log */
 
	char crashlog_filename[MAX_PATH];
 
	/** Buffer for the filename of the crash dump */
 
@@ -68,7 +61,7 @@ public:
 
	CrashLogWindows(EXCEPTION_POINTERS *ep = nullptr) :
 
		ep(ep)
 
	{
 
		this->crashlog[0] = '\0';
 
		this->crashlog.reserve(65536);
 
		this->crashlog_filename[0] = '\0';
 
		this->crashdump_filename[0] = '\0';
 
		this->screenshot_filename[0] = '\0';
 
@@ -82,36 +75,32 @@ public:
 

	
 
/* static */ CrashLogWindows *CrashLogWindows::current = nullptr;
 

	
 
/* virtual */ char *CrashLogWindows::LogOSVersion(char *buffer, const char *last) const
 
/* virtual */ void CrashLogWindows::LogOSVersion(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	_OSVERSIONINFOA os;
 
	os.dwOSVersionInfoSize = sizeof(os);
 
	GetVersionExA(&os);
 

	
 
	return buffer + seprintf(buffer, last,
 
	fmt::format_to(output_iterator,
 
			"Operating system:\n"
 
			" Name:     Windows\n"
 
			" Release:  %d.%d.%d (%s)\n",
 
			(int)os.dwMajorVersion,
 
			(int)os.dwMinorVersion,
 
			(int)os.dwBuildNumber,
 
			" Release:  {}.{}.{} ({})\n",
 
			os.dwMajorVersion,
 
			os.dwMinorVersion,
 
			os.dwBuildNumber,
 
			os.szCSDVersion
 
	);
 

	
 
}
 

	
 
/* virtual */ char *CrashLogWindows::LogError(char *buffer, const char *last, const char *message) const
 
/* virtual */ void CrashLogWindows::LogError(std::back_insert_iterator<std::string> &output_iterator, const std::string_view message) const
 
{
 
	return buffer + seprintf(buffer, last,
 
	fmt::format_to(output_iterator,
 
			"Crash reason:\n"
 
			" Exception: %.8X\n"
 
#ifdef _M_AMD64
 
			" Location:  %.16IX\n"
 
#else
 
			" Location:  %.8X\n"
 
#endif
 
			" Message:   %s\n\n",
 
			(int)ep->ExceptionRecord->ExceptionCode,
 
			" Exception: {:08X}\n"
 
			" Location:  {:X}\n"
 
			" Message:   {}\n\n",
 
			ep->ExceptionRecord->ExceptionCode,
 
			(size_t)ep->ExceptionRecord->ExceptionAddress,
 
			message
 
	);
 
@@ -179,16 +168,16 @@ static void GetFileInfo(DebugFileInfo *d
 
}
 

	
 

	
 
static char *PrintModuleInfo(char *output, const char *last, HMODULE mod)
 
static void PrintModuleInfo(std::back_insert_iterator<std::string> &output_iterator, HMODULE mod)
 
{
 
	wchar_t buffer[MAX_PATH];
 
	DebugFileInfo dfi;
 

	
 
	GetModuleFileName(mod, buffer, MAX_PATH);
 
	GetFileInfo(&dfi, buffer);
 
	output += seprintf(output, last, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
 
		FS2OTTD(buffer).c_str(),
 
		mod,
 
	fmt::format_to(output_iterator, " {:20s} handle: {:X} size: {} crc: {:8X} date: {}-{:02}-{:02} {:02}:{:02}:{:02}\n",
 
		FS2OTTD(buffer),
 
		(size_t)mod,
 
		dfi.size,
 
		dfi.crc32,
 
		dfi.file_time.wYear,
 
@@ -198,14 +187,13 @@ static char *PrintModuleInfo(char *outpu
 
		dfi.file_time.wMinute,
 
		dfi.file_time.wSecond
 
	);
 
	return output;
 
}
 

	
 
/* virtual */ char *CrashLogWindows::LogModules(char *output, const char *last) const
 
/* virtual */ void CrashLogWindows::LogModules(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	MakeCRCTable();
 

	
 
	output += seprintf(output, last, "Module information:\n");
 
	fmt::format_to(output_iterator, "Module information:\n");
 

	
 
	HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
 
	if (proc != nullptr) {
 
@@ -216,24 +204,25 @@ static char *PrintModuleInfo(char *outpu
 
		if (res) {
 
			size_t count = std::min<DWORD>(needed / sizeof(HMODULE), lengthof(modules));
 

	
 
			for (size_t i = 0; i != count; i++) output = PrintModuleInfo(output, last, modules[i]);
 
			return output + seprintf(output, last, "\n");
 
			for (size_t i = 0; i != count; i++) PrintModuleInfo(output_iterator, modules[i]);
 
			fmt::format_to(output_iterator, "\n");
 
			return;
 
		}
 
	}
 
	output = PrintModuleInfo(output, last, nullptr);
 
	return output + seprintf(output, last, "\n");
 
	PrintModuleInfo(output_iterator, nullptr);
 
	fmt::format_to(output_iterator, "\n");
 
}
 

	
 
/* virtual */ char *CrashLogWindows::LogRegisters(char *buffer, const char *last) const
 
/* virtual */ void CrashLogWindows::LogRegisters(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	buffer += seprintf(buffer, last, "Registers:\n");
 
	fmt::format_to(output_iterator, "Registers:\n");
 
#ifdef _M_AMD64
 
	buffer += seprintf(buffer, last,
 
		" RAX: %.16I64X RBX: %.16I64X RCX: %.16I64X RDX: %.16I64X\n"
 
		" RSI: %.16I64X RDI: %.16I64X RBP: %.16I64X RSP: %.16I64X\n"
 
		" R8:  %.16I64X R9:  %.16I64X R10: %.16I64X R11: %.16I64X\n"
 
		" R12: %.16I64X R13: %.16I64X R14: %.16I64X R15: %.16I64X\n"
 
		" RIP: %.16I64X EFLAGS: %.8lX\n",
 
	fmt::format_to(output_iterator,
 
		" RAX: {:016X} RBX: {:016X} RCX: {:016X} RDX: {:016X}\n"
 
		" RSI: {:016X} RDI: {:016X} RBP: {:016X} RSP: {:016X}\n"
 
		" R8:  {:016X} R9:  {:016X} R10: {:016X} R11: {:016X}\n"
 
		" R12: {:016X} R13: {:016X} R14: {:016X} R15: {:016X}\n"
 
		" RIP: {:016X} EFLAGS: {:08X}\n",
 
		ep->ContextRecord->Rax,
 
		ep->ContextRecord->Rbx,
 
		ep->ContextRecord->Rcx,
 
@@ -254,10 +243,10 @@ static char *PrintModuleInfo(char *outpu
 
		ep->ContextRecord->EFlags
 
	);
 
#elif defined(_M_IX86)
 
	buffer += seprintf(buffer, last,
 
		" EAX: %.8X EBX: %.8X ECX: %.8X EDX: %.8X\n"
 
		" ESI: %.8X EDI: %.8X EBP: %.8X ESP: %.8X\n"
 
		" EIP: %.8X EFLAGS: %.8X\n",
 
	fmt::format_to(output_iterator,
 
		" EAX: {:08X} EBX: {:08X} ECX: {:08X} EDX: {:08X}\n"
 
		" ESI: {:08X} EDI: {:08X} EBP: {:08X} ESP: {:08X}\n"
 
		" EIP: {:08X} EFLAGS: {:08X}\n",
 
		(int)ep->ContextRecord->Eax,
 
		(int)ep->ContextRecord->Ebx,
 
		(int)ep->ContextRecord->Ecx,
 
@@ -270,15 +259,15 @@ static char *PrintModuleInfo(char *outpu
 
		(int)ep->ContextRecord->EFlags
 
	);
 
#elif defined(_M_ARM64)
 
	buffer += seprintf(buffer, last,
 
		" X0:  %.16I64X X1:  %.16I64X X2:  %.16I64X X3:  %.16I64X\n"
 
		" X4:  %.16I64X X5:  %.16I64X X6:  %.16I64X X7:  %.16I64X\n"
 
		" X8:  %.16I64X X9:  %.16I64X X10: %.16I64X X11: %.16I64X\n"
 
		" X12: %.16I64X X13: %.16I64X X14: %.16I64X X15: %.16I64X\n"
 
		" X16: %.16I64X X17: %.16I64X X18: %.16I64X X19: %.16I64X\n"
 
		" X20: %.16I64X X21: %.16I64X X22: %.16I64X X23: %.16I64X\n"
 
		" X24: %.16I64X X25: %.16I64X X26: %.16I64X X27: %.16I64X\n"
 
		" X28: %.16I64X Fp:  %.16I64X Lr:  %.16I64X\n",
 
	fmt::format_to(output_iterator,
 
		" X0:  {:016X} X1:  {:016X} X2:  {:016X} X3:  {:016X}\n"
 
		" X4:  {:016X} X5:  {:016X} X6:  {:016X} X7:  {:016X}\n"
 
		" X8:  {:016X} X9:  {:016X} X10: {:016X} X11: {:016X}\n"
 
		" X12: {:016X} X13: {:016X} X14: {:016X} X15: {:016X}\n"
 
		" X16: {:016X} X17: {:016X} X18: {:016X} X19: {:016X}\n"
 
		" X20: {:016X} X21: {:016X} X22: {:016X} X23: {:016X}\n"
 
		" X24: {:016X} X25: {:016X} X26: {:016X} X27: {:016X}\n"
 
		" X28: {:016X} Fp:  {:016X} Lr:  {:016X}\n",
 
		ep->ContextRecord->X0,
 
		ep->ContextRecord->X1,
 
		ep->ContextRecord->X2,
 
@@ -313,7 +302,7 @@ static char *PrintModuleInfo(char *outpu
 
	);
 
#endif
 

	
 
	buffer += seprintf(buffer, last, "\n Bytes at instruction pointer:\n");
 
	fmt::format_to(output_iterator, "\n Bytes at instruction pointer:\n");
 
#ifdef _M_AMD64
 
	byte *b = (byte*)ep->ContextRecord->Rip;
 
#elif defined(_M_IX86)
 
@@ -323,18 +312,18 @@ static char *PrintModuleInfo(char *outpu
 
#endif
 
	for (int i = 0; i != 24; i++) {
 
		if (IsBadReadPtr(b, 1)) {
 
			buffer += seprintf(buffer, last, " ??"); // OCR: WAS: , 0);
 
			fmt::format_to(output_iterator, " ??"); // OCR: WAS: , 0);
 
		} else {
 
			buffer += seprintf(buffer, last, " %.2X", *b);
 
			fmt::format_to(output_iterator, " {:02X}", *b);
 
		}
 
		b++;
 
	}
 
	return buffer + seprintf(buffer, last, "\n\n");
 
	fmt::format_to(output_iterator, "\n\n");
 
}
 

	
 
/* virtual */ char *CrashLogWindows::LogStacktrace(char *buffer, const char *last) const
 
/* virtual */ void CrashLogWindows::LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	buffer += seprintf(buffer, last, "Stack trace:\n");
 
	fmt::format_to(output_iterator, "Stack trace:\n");
 
#ifdef _M_AMD64
 
	uint32 *b = (uint32*)ep->ContextRecord->Rsp;
 
#elif defined(_M_IX86)
 
@@ -345,15 +334,15 @@ static char *PrintModuleInfo(char *outpu
 
	for (int j = 0; j != 24; j++) {
 
		for (int i = 0; i != 8; i++) {
 
			if (IsBadReadPtr(b, sizeof(uint32))) {
 
				buffer += seprintf(buffer, last, " ????????"); // OCR: WAS - , 0);
 
				fmt::format_to(output_iterator, " ????????"); // OCR: WAS - , 0);
 
			} else {
 
				buffer += seprintf(buffer, last, " %.8X", *b);
 
				fmt::format_to(output_iterator, " {:08X}", *b);
 
			}
 
			b++;
 
		}
 
		buffer += seprintf(buffer, last, "\n");
 
		fmt::format_to(output_iterator, "\n");
 
	}
 
	return buffer + seprintf(buffer, last, "\n");
 
	fmt::format_to(output_iterator, "\n");
 
}
 

	
 
#if defined(_MSC_VER)
 
@@ -364,7 +353,7 @@ static const uint MAX_FRAMES     = 64;
 
#include <dbghelp.h>
 
#pragma warning(default:4091)
 

	
 
char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) const
 
void CrashLogWindows::AppendDecodedStacktrace(std::back_insert_iterator<std::string> &output_iterator) const
 
{
 
	DllLoader dbghelp(L"dbghelp.dll");
 
	struct ProcPtrs {
 
@@ -389,7 +378,7 @@ char *CrashLogWindows::AppendDecodedStac
 
		dbghelp.GetProcAddress("SymGetLineFromAddr64"),
 
	};
 

	
 
	buffer += seprintf(buffer, last, "\nDecoded stack trace:\n");
 
	fmt::format_to(output_iterator, "\nDecoded stack trace:\n");
 

	
 
	/* Try to load the functions from the DLL, if that fails because of a too old dbghelp.dll, just skip it. */
 
	if (dbghelp.Success()) {
 
@@ -440,7 +429,7 @@ char *CrashLogWindows::AppendDecodedStac
 
				hCur, GetCurrentThread(), &frame, &ctx, nullptr, proc.pSymFunctionTableAccess64, proc.pSymGetModuleBase64, nullptr)) break;
 

	
 
			if (frame.AddrPC.Offset == frame.AddrReturn.Offset) {
 
				buffer += seprintf(buffer, last, " <infinite loop>\n");
 
				fmt::format_to(output_iterator, " <infinite loop>\n");
 
				break;
 
			}
 

	
 
@@ -454,27 +443,27 @@ char *CrashLogWindows::AppendDecodedStac
 
			}
 

	
 
			/* Print module and instruction pointer. */
 
			buffer += seprintf(buffer, last, "[%02d] %-20s " PRINTF_PTR, num, mod_name, frame.AddrPC.Offset);
 
			fmt::format_to(output_iterator, "[{:02}] {:20s} {:X}", num, mod_name, frame.AddrPC.Offset);
 

	
 
			/* Get symbol name and line info if possible. */
 
			DWORD64 offset;
 
			if (proc.pSymGetSymFromAddr64(hCur, frame.AddrPC.Offset, &offset, sym_info)) {
 
				buffer += seprintf(buffer, last, " %s + %I64u", sym_info->Name, offset);
 
				fmt::format_to(output_iterator, " {} + {}", sym_info->Name, offset);
 

	
 
				DWORD line_offs;
 
				IMAGEHLP_LINE64 line;
 
				line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
 
				if (proc.pSymGetLineFromAddr64(hCur, frame.AddrPC.Offset, &line_offs, &line)) {
 
					buffer += seprintf(buffer, last, " (%s:%d)", line.FileName, line.LineNumber);
 
					fmt::format_to(output_iterator, " ({}:{})", line.FileName, line.LineNumber);
 
				}
 
			}
 
			buffer += seprintf(buffer, last, "\n");
 
			fmt::format_to(output_iterator, "\n");
 
		}
 

	
 
		proc.pSymCleanup(hCur);
 
	}
 

	
 
	return buffer + seprintf(buffer, last, "\n*** End of additional info ***\n");
 
	fmt::format_to(output_iterator, "\n*** End of additional info ***\n");
 
}
 

	
 
/* virtual */ int CrashLogWindows::WriteCrashDump(char *filename, const char *filename_last) const
 
@@ -498,8 +487,8 @@ char *CrashLogWindows::AppendDecodedStac
 
			MINIDUMP_USER_STREAM_INFORMATION musi;
 

	
 
			userstream.Type        = LastReservedStream + 1;
 
			userstream.Buffer      = (void*)this->crashlog;
 
			userstream.BufferSize  = (ULONG)strlen(this->crashlog) + 1;
 
			userstream.Buffer      = (void*)this->crashlog.data();
 
			userstream.BufferSize  = (ULONG)this->crashlog.size() + 1;
 

	
 
			musi.UserStreamCount   = 1;
 
			musi.UserStreamArray   = &userstream;
 
@@ -559,10 +548,11 @@ static LONG WINAPI ExceptionHandler(EXCE
 

	
 
	CrashLogWindows *log = new CrashLogWindows(ep);
 
	CrashLogWindows::current = log;
 
	char *buf = log->FillCrashLog(log->crashlog, lastof(log->crashlog));
 
	auto output_iterator = std::back_inserter(log->crashlog);
 
	log->FillCrashLog(output_iterator);
 
	log->WriteCrashDump(log->crashdump_filename, lastof(log->crashdump_filename));
 
	log->AppendDecodedStacktrace(buf, lastof(log->crashlog));
 
	log->WriteCrashLog(log->crashlog, log->crashlog_filename, lastof(log->crashlog_filename));
 
	log->AppendDecodedStacktrace(output_iterator);
 
	log->WriteCrashLog(log->crashlog.c_str(), log->crashlog_filename, lastof(log->crashlog_filename));
 
	log->WriteScreenshot(log->screenshot_filename, lastof(log->screenshot_filename));
 
	log->SendSurvey();
 

	
 
@@ -680,10 +670,10 @@ static INT_PTR CALLBACK CrashDialogFunc(
 
			/* We need to put the crash-log in a separate buffer because the default
 
			 * buffer in MB_TO_WIDE is not large enough (512 chars) */
 
			wchar_t filenamebuf[MAX_PATH * 2];
 
			wchar_t crash_msgW[lengthof(CrashLogWindows::current->crashlog)];
 
			wchar_t crash_msgW[65536];
 
			/* Convert unix -> dos newlines because the edit box only supports that properly :( */
 
			const char *unix_nl = CrashLogWindows::current->crashlog;
 
			char dos_nl[lengthof(CrashLogWindows::current->crashlog)];
 
			const char *unix_nl = CrashLogWindows::current->crashlog.data();
 
			char dos_nl[65536];
 
			char *p = dos_nl;
 
			WChar c;
 
			while ((c = Utf8Consume(&unix_nl)) && p < lastof(dos_nl) - 4) { // 4 is max number of bytes per character
0 comments (0 inline, 0 general)