00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "crashlog.h"
00014 #include "gamelog.h"
00015 #include "date_func.h"
00016 #include "map_func.h"
00017 #include "rev.h"
00018 #include "strings_func.h"
00019 #include "blitter/factory.hpp"
00020 #include "base_media_base.h"
00021 #include "music/music_driver.hpp"
00022 #include "sound/sound_driver.hpp"
00023 #include "video/video_driver.hpp"
00024 #include "saveload/saveload.h"
00025 #include "screenshot.h"
00026 #include "gfx_func.h"
00027 #include "network/network.h"
00028 #include "language.h"
00029 #include "fontcache.h"
00030
00031 #include "ai/ai_info.hpp"
00032 #include "game/game.hpp"
00033 #include "game/game_info.hpp"
00034 #include "company_base.h"
00035 #include "company_func.h"
00036
00037 #include <time.h>
00038
00039 const char *CrashLog::message = NULL;
00040 char *CrashLog::gamelog_buffer = NULL;
00041 const char *CrashLog::gamelog_last = NULL;
00042
00043 char *CrashLog::LogCompiler(char *buffer, const char *last) const
00044 {
00045 buffer += seprintf(buffer, last, " Compiler: "
00046 #if defined(_MSC_VER)
00047 "MSVC %d", _MSC_VER
00048 #elif defined(__ICC) && defined(__GNUC__)
00049 "ICC %d (GCC %d.%d.%d mode)", __ICC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__
00050 #elif defined(__ICC)
00051 "ICC %d", __ICC
00052 #elif defined(__GNUC__)
00053 "GCC %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__
00054 #elif defined(__WATCOMC__)
00055 "WatcomC %d", __WATCOMC__
00056 #else
00057 "<unknown>"
00058 #endif
00059 );
00060 #if defined(__VERSION__)
00061 return buffer + seprintf(buffer, last, " \"" __VERSION__ "\"\n\n");
00062 #else
00063 return buffer + seprintf(buffer, last, "\n\n");
00064 #endif
00065 }
00066
00067 char *CrashLog::LogRegisters(char *buffer, const char *last) const
00068 {
00069
00070 return buffer;
00071 }
00072
00073 char *CrashLog::LogModules(char *buffer, const char *last) const
00074 {
00075
00076 return buffer;
00077 }
00078
00085 char *CrashLog::LogOpenTTDVersion(char *buffer, const char *last) const
00086 {
00087 return buffer + seprintf(buffer, last,
00088 "OpenTTD version:\n"
00089 " Version: %s (%d)\n"
00090 " NewGRF ver: %08x\n"
00091 " Bits: %d\n"
00092 " Endian: %s\n"
00093 " Dedicated: %s\n"
00094 " Build date: %s\n\n",
00095 _openttd_revision,
00096 _openttd_revision_modified,
00097 _openttd_newgrf_version,
00098 #ifdef _SQ64
00099 64,
00100 #else
00101 32,
00102 #endif
00103 #if (TTD_ENDIAN == TTD_LITTLE_ENDIAN)
00104 "little",
00105 #else
00106 "big",
00107 #endif
00108 #ifdef DEDICATED
00109 "yes",
00110 #else
00111 "no",
00112 #endif
00113 _openttd_build_date
00114 );
00115 }
00116
00124 char *CrashLog::LogConfiguration(char *buffer, const char *last) const
00125 {
00126 buffer += seprintf(buffer, last,
00127 "Configuration:\n"
00128 " Blitter: %s\n"
00129 " Graphics set: %s (%u)\n"
00130 " Language: %s\n"
00131 " Music driver: %s\n"
00132 " Music set: %s (%u)\n"
00133 " Network: %s\n"
00134 " Sound driver: %s\n"
00135 " Sound set: %s (%u)\n"
00136 " Video driver: %s\n\n",
00137 BlitterFactory::GetCurrentBlitter() == NULL ? "none" : BlitterFactory::GetCurrentBlitter()->GetName(),
00138 BaseGraphics::GetUsedSet() == NULL ? "none" : BaseGraphics::GetUsedSet()->name,
00139 BaseGraphics::GetUsedSet() == NULL ? UINT32_MAX : BaseGraphics::GetUsedSet()->version,
00140 _current_language == NULL ? "none" : _current_language->file,
00141 MusicDriver::GetInstance() == NULL ? "none" : MusicDriver::GetInstance()->GetName(),
00142 BaseMusic::GetUsedSet() == NULL ? "none" : BaseMusic::GetUsedSet()->name,
00143 BaseMusic::GetUsedSet() == NULL ? UINT32_MAX : BaseMusic::GetUsedSet()->version,
00144 _networking ? (_network_server ? "server" : "client") : "no",
00145 SoundDriver::GetInstance() == NULL ? "none" : SoundDriver::GetInstance()->GetName(),
00146 BaseSounds::GetUsedSet() == NULL ? "none" : BaseSounds::GetUsedSet()->name,
00147 BaseSounds::GetUsedSet() == NULL ? UINT32_MAX : BaseSounds::GetUsedSet()->version,
00148 VideoDriver::GetInstance() == NULL ? "none" : VideoDriver::GetInstance()->GetName()
00149 );
00150
00151 buffer += seprintf(buffer, last,
00152 "Fonts:\n"
00153 " Small: %s\n"
00154 " Medium: %s\n"
00155 " Large: %s\n"
00156 " Mono: %s\n\n",
00157 FontCache::Get(FS_SMALL)->GetFontName(),
00158 FontCache::Get(FS_NORMAL)->GetFontName(),
00159 FontCache::Get(FS_LARGE)->GetFontName(),
00160 FontCache::Get(FS_MONO)->GetFontName()
00161 );
00162
00163 buffer += seprintf(buffer, last, "AI Configuration (local: %i):\n", (int)_local_company);
00164 const Company *c;
00165 FOR_ALL_COMPANIES(c) {
00166 if (c->ai_info == NULL) {
00167 buffer += seprintf(buffer, last, " %2i: Human\n", (int)c->index);
00168 } else {
00169 buffer += seprintf(buffer, last, " %2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
00170 }
00171 }
00172
00173 if (Game::GetInfo() != NULL) {
00174 buffer += seprintf(buffer, last, " GS: %s (v%d)\n", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion());
00175 }
00176 buffer += seprintf(buffer, last, "\n");
00177
00178 return buffer;
00179 }
00180
00181
00182 #ifdef WITH_ALLEGRO
00183 # include <allegro.h>
00184 #endif
00185 #ifdef WITH_FONTCONFIG
00186 # include <fontconfig/fontconfig.h>
00187 #endif
00188 #ifdef WITH_PNG
00189
00190
00191 # include <png.h>
00192 #endif
00193 #ifdef WITH_FREETYPE
00194 # include <ft2build.h>
00195 # include FT_FREETYPE_H
00196 #endif
00197 #ifdef WITH_ICU
00198 # include <unicode/uversion.h>
00199 #endif
00200 #ifdef WITH_LZMA
00201 # include <lzma.h>
00202 #endif
00203 #ifdef WITH_LZO
00204 #include <lzo/lzo1x.h>
00205 #endif
00206 #ifdef WITH_SDL
00207 # include "sdl.h"
00208 # include <SDL.h>
00209 #endif
00210 #ifdef WITH_ZLIB
00211 # include <zlib.h>
00212 #endif
00213
00220 char *CrashLog::LogLibraries(char *buffer, const char *last) const
00221 {
00222 buffer += seprintf(buffer, last, "Libraries:\n");
00223
00224 #ifdef WITH_ALLEGRO
00225 buffer += seprintf(buffer, last, " Allegro: %s\n", allegro_id);
00226 #endif
00227
00228 #ifdef WITH_FONTCONFIG
00229 int version = FcGetVersion();
00230 buffer += seprintf(buffer, last, " FontConfig: %d.%d.%d\n", version / 10000, (version / 100) % 100, version % 100);
00231 #endif
00232
00233 #ifdef WITH_FREETYPE
00234 FT_Library library;
00235 int major, minor, patch;
00236 FT_Init_FreeType(&library);
00237 FT_Library_Version(library, &major, &minor, &patch);
00238 FT_Done_FreeType(library);
00239 buffer += seprintf(buffer, last, " FreeType: %d.%d.%d\n", major, minor, patch);
00240 #endif
00241
00242 #ifdef WITH_ICU
00243
00244 char buf[4 * 3 + 3 + 1];
00245 UVersionInfo ver;
00246 u_getVersion(ver);
00247 u_versionToString(ver, buf);
00248 buffer += seprintf(buffer, last, " ICU: %s\n", buf);
00249 #endif
00250
00251 #ifdef WITH_LZMA
00252 buffer += seprintf(buffer, last, " LZMA: %s\n", lzma_version_string());
00253 #endif
00254
00255 #ifdef WITH_LZO
00256 buffer += seprintf(buffer, last, " LZO: %s\n", lzo_version_string());
00257 #endif
00258
00259 #ifdef WITH_PNG
00260 buffer += seprintf(buffer, last, " PNG: %s\n", png_get_libpng_ver(NULL));
00261 #endif
00262
00263 #ifdef WITH_SDL
00264 #ifdef DYNAMICALLY_LOADED_SDL
00265 if (SDL_CALL SDL_Linked_Version != NULL) {
00266 #else
00267 {
00268 #endif
00269 const SDL_version *v = SDL_CALL SDL_Linked_Version();
00270 buffer += seprintf(buffer, last, " SDL: %d.%d.%d\n", v->major, v->minor, v->patch);
00271 }
00272 #endif
00273
00274 #ifdef WITH_ZLIB
00275 buffer += seprintf(buffer, last, " Zlib: %s\n", zlibVersion());
00276 #endif
00277
00278 buffer += seprintf(buffer, last, "\n");
00279 return buffer;
00280 }
00281
00286 void CrashLog::GamelogFillCrashLog(const char *s)
00287 {
00288 CrashLog::gamelog_buffer += seprintf(CrashLog::gamelog_buffer, CrashLog::gamelog_last, "%s\n", s);
00289 }
00290
00297 char *CrashLog::LogGamelog(char *buffer, const char *last) const
00298 {
00299 CrashLog::gamelog_buffer = buffer;
00300 CrashLog::gamelog_last = last;
00301 GamelogPrint(&CrashLog::GamelogFillCrashLog);
00302 return CrashLog::gamelog_buffer + seprintf(CrashLog::gamelog_buffer, last, "\n");
00303 }
00304
00311 char *CrashLog::FillCrashLog(char *buffer, const char *last) const
00312 {
00313 time_t cur_time = time(NULL);
00314 buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\n\n");
00315 buffer += seprintf(buffer, last, "Crash at: %s", asctime(gmtime(&cur_time)));
00316
00317 YearMonthDay ymd;
00318 ConvertDateToYMD(_date, &ymd);
00319 buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i)\n\n", ymd.year, ymd.month + 1, ymd.day, _date_fract);
00320
00321 buffer = this->LogError(buffer, last, CrashLog::message);
00322 buffer = this->LogOpenTTDVersion(buffer, last);
00323 buffer = this->LogRegisters(buffer, last);
00324 buffer = this->LogStacktrace(buffer, last);
00325 buffer = this->LogOSVersion(buffer, last);
00326 buffer = this->LogCompiler(buffer, last);
00327 buffer = this->LogConfiguration(buffer, last);
00328 buffer = this->LogLibraries(buffer, last);
00329 buffer = this->LogModules(buffer, last);
00330 buffer = this->LogGamelog(buffer, last);
00331
00332 buffer += seprintf(buffer, last, "*** End of OpenTTD Crash Report ***\n");
00333 return buffer;
00334 }
00335
00345 bool CrashLog::WriteCrashLog(const char *buffer, char *filename, const char *filename_last) const
00346 {
00347 seprintf(filename, filename_last, "%scrash.log", _personal_dir);
00348
00349 FILE *file = FioFOpenFile(filename, "w", NO_DIRECTORY);
00350 if (file == NULL) return false;
00351
00352 size_t len = strlen(buffer);
00353 size_t written = fwrite(buffer, 1, len, file);
00354
00355 FioFCloseFile(file);
00356 return len == written;
00357 }
00358
00359 int CrashLog::WriteCrashDump(char *filename, const char *filename_last) const
00360 {
00361
00362 return 0;
00363 }
00364
00373 bool CrashLog::WriteSavegame(char *filename, const char *filename_last) const
00374 {
00375
00376
00377 if (_m == NULL) return false;
00378
00379 try {
00380 GamelogEmergency();
00381
00382 seprintf(filename, filename_last, "%scrash.sav", _personal_dir);
00383
00384
00385 return SaveOrLoad(filename, SL_SAVE, NO_DIRECTORY, false) == SL_OK;
00386 } catch (...) {
00387 return false;
00388 }
00389 }
00390
00399 bool CrashLog::WriteScreenshot(char *filename, const char *filename_last) const
00400 {
00401
00402 if (_screen.width < 1 || _screen.height < 1 || _screen.dst_ptr == NULL) return false;
00403
00404 bool res = MakeScreenshot(SC_CRASHLOG, "crash");
00405 if (res) strecpy(filename, _full_screenshot_name, filename_last);
00406 return res;
00407 }
00408
00415 bool CrashLog::MakeCrashLog() const
00416 {
00417
00418 static bool crashlogged = false;
00419 if (crashlogged) return false;
00420 crashlogged = true;
00421
00422 char filename[MAX_PATH];
00423 char buffer[65536];
00424 bool ret = true;
00425
00426 printf("Crash encountered, generating crash log...\n");
00427 this->FillCrashLog(buffer, lastof(buffer));
00428 printf("%s\n", buffer);
00429 printf("Crash log generated.\n\n");
00430
00431 printf("Writing crash log to disk...\n");
00432 bool bret = this->WriteCrashLog(buffer, filename, lastof(filename));
00433 if (bret) {
00434 printf("Crash log written to %s. Please add this file to any bug reports.\n\n", filename);
00435 } else {
00436 printf("Writing crash log failed. Please attach the output above to any bug reports.\n\n");
00437 ret = false;
00438 }
00439
00440
00441 int dret = this->WriteCrashDump(filename, lastof(filename));
00442 if (dret < 0) {
00443 printf("Writing crash dump failed.\n\n");
00444 ret = false;
00445 } else if (dret > 0) {
00446 printf("Crash dump written to %s. Please add this file to any bug reports.\n\n", filename);
00447 }
00448
00449 printf("Writing crash savegame...\n");
00450 bret = this->WriteSavegame(filename, lastof(filename));
00451 if (bret) {
00452 printf("Crash savegame written to %s. Please add this file and the last (auto)save to any bug reports.\n\n", filename);
00453 } else {
00454 ret = false;
00455 printf("Writing crash savegame failed. Please attach the last (auto)save to any bug reports.\n\n");
00456 }
00457
00458 printf("Writing crash screenshot...\n");
00459 bret = this->WriteScreenshot(filename, lastof(filename));
00460 if (bret) {
00461 printf("Crash screenshot written to %s. Please add this file to any bug reports.\n\n", filename);
00462 } else {
00463 ret = false;
00464 printf("Writing crash screenshot failed.\n\n");
00465 }
00466
00467 return ret;
00468 }
00469
00474 void CrashLog::SetErrorMessage(const char *message)
00475 {
00476 CrashLog::message = message;
00477 }
00478
00483 void CrashLog::AfterCrashLogCleanup()
00484 {
00485 if (MusicDriver::GetInstance() != NULL) MusicDriver::GetInstance()->Stop();
00486 if (SoundDriver::GetInstance() != NULL) SoundDriver::GetInstance()->Stop();
00487 if (VideoDriver::GetInstance() != NULL) VideoDriver::GetInstance()->Stop();
00488 }