~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Bochs x86 Emulator
bochs/logio.cc

Version: ~ [ 2.3.5 ] ~ [ 2.3 ] ~

** Warning: Cannot open xref database.

1 ///////////////////////////////////////////////////////////////////////// 2 // $Id: logio.cc,v 1.60 2006/11/19 16:18:41 sshwarts Exp $ 3 ///////////////////////////////////////////////////////////////////////// 4 // 5 // Copyright (C) 2001 MandrakeSoft S.A. 6 // 7 // MandrakeSoft S.A. 8 // 43, rue d'Aboukir 9 // 75002 Paris - France 10 // http://www.linux-mandrake.com/ 11 // http://www.mandrakesoft.com/ 12 // 13 // This library is free software; you can redistribute it and/or 14 // modify it under the terms of the GNU Lesser General Public 15 // License as published by the Free Software Foundation; either 16 // version 2 of the License, or (at your option) any later version. 17 // 18 // This library is distributed in the hope that it will be useful, 19 // but WITHOUT ANY WARRANTY; without even the implied warranty of 20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 // Lesser General Public License for more details. 22 // 23 // You should have received a copy of the GNU Lesser General Public 24 // License along with this library; if not, write to the Free Software 25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 27 28 #include "bochs.h" 29 #include "cpu/cpu.h" 30 #include "iodev/iodev.h" 31 #include <assert.h> 32 33 #if BX_WITH_CARBON 34 #define Float32 KLUDGE_Float32 35 #define Float64 KLUDGE_Float64 36 #include <Carbon/Carbon.h> 37 #undef Float32 38 #undef Float64 39 #endif 40 41 // Just for the iofunctions 42 43 static int Allocio=0; 44 45 void iofunctions::flush(void) 46 { 47 if(logfd && magic == MAGIC_LOGNUM) { 48 fflush(logfd); 49 } 50 } 51 52 void iofunctions::init(void) 53 { 54 // iofunctions methods must not be called before this magic 55 // number is set. 56 magic=MAGIC_LOGNUM; 57 58 // sets the default logprefix 59 strcpy(logprefix,"%t%e%d"); 60 n_logfn = 0; 61 init_log(stderr); 62 log = new logfunc_t(this); 63 log->put("IO"); 64 log->settype(IOLOG); 65 log->ldebug("Init(log file: '%s').",logfn); 66 } 67 68 void iofunctions::add_logfn(logfunc_t *fn) 69 { 70 assert(n_logfn < MAX_LOGFNS); 71 logfn_list[n_logfn++] = fn; 72 } 73 74 void iofunctions::remove_logfn(logfunc_t *fn) 75 { 76 assert(n_logfn > 0); 77 int i = 0; 78 while ((fn != logfn_list[i]) && (i < n_logfn)) { 79 i++; 80 }; 81 if (i < n_logfn) { 82 for (int j=i; j<n_logfn-1; j++) { 83 logfn_list[j] = logfn_list[j+1]; 84 } 85 n_logfn--; 86 } 87 } 88 89 void iofunctions::set_log_action(int loglevel, int action) 90 { 91 for(int i=0; i<n_logfn; i++) 92 logfn_list[i]->setonoff(loglevel, action); 93 } 94 95 void iofunctions::init_log(const char *fn) 96 { 97 assert(magic==MAGIC_LOGNUM); 98 // use newfd/newfn so that we can log the message to the OLD log 99 // file descriptor. 100 FILE *newfd = stderr; 101 char *newfn = "/dev/stderr"; 102 if(strcmp(fn, "-") != 0) { 103 newfd = fopen(fn, "w"); 104 if(newfd != NULL) { 105 newfn = strdup(fn); 106 log->ldebug("Opened log file '%s'.", fn ); 107 } else { 108 // in constructor, genlog might not exist yet, so do it the safe way. 109 log->error("Couldn't open log file: %s, using stderr instead", fn); 110 newfd = stderr; 111 } 112 } 113 logfd = newfd; 114 logfn = newfn; 115 } 116 117 void iofunctions::init_log(FILE *fs) 118 { 119 assert(magic==MAGIC_LOGNUM); 120 logfd = fs; 121 122 if(fs == stderr) { 123 logfn = "/dev/stderr"; 124 } else if(fs == stdout) { 125 logfn = "/dev/stdout"; 126 } else { 127 logfn = "(unknown)"; 128 } 129 } 130 131 void iofunctions::init_log(int fd) 132 { 133 assert(magic==MAGIC_LOGNUM); 134 FILE *tmpfd; 135 if((tmpfd = fdopen(fd,"w")) == NULL) { 136 log->panic("Couldn't open fd %d as a stream for writing", fd); 137 return; 138 } 139 140 init_log(tmpfd); 141 }; 142 143 void iofunctions::exit_log() 144 { 145 flush(); 146 if (logfd != stderr) { 147 fclose(logfd); 148 logfd = stderr; 149 free(logfn); 150 logfn = "/dev/stderr"; 151 } 152 } 153 154 // all other functions may use genlog safely. 155 #define LOG_THIS genlog-> 156 157 // This converts the option string to a printf style string with the following args: 158 // 1. timer, 2. event, 3. cpu0 eip, 4. device 159 void iofunctions::set_log_prefix(const char* prefix) 160 { 161 strcpy(logprefix, prefix); 162 } 163 164 // iofunctions::out( class, level, prefix, fmt, ap) 165 // DO NOT nest out() from ::info() and the like. 166 // fmt and ap retained for direct printinf from iofunctions only! 167 168 void iofunctions::out(int f, int l, const char *prefix, const char *fmt, va_list ap) 169 { 170 char c=' ', *s; 171 assert(magic==MAGIC_LOGNUM); 172 assert(this != NULL); 173 assert(logfd != NULL); 174 175 switch(l) { 176 case LOGLEV_INFO: c='i'; break; 177 case LOGLEV_PANIC: c='p'; break; 178 case LOGLEV_PASS: c='s'; break; 179 case LOGLEV_ERROR: c='e'; break; 180 case LOGLEV_DEBUG: c='d'; break; 181 default: break; 182 } 183 184 s=logprefix; 185 while(*s) { 186 switch(*s) { 187 case '%': 188 if(*(s+1)) s++; 189 else break; 190 switch(*s) { 191 case 'd': 192 fprintf(logfd, "%s", prefix==NULL?"":prefix); 193 break; 194 case 't': 195 fprintf(logfd, FMT_TICK, bx_pc_system.time_ticks()); 196 break; 197 case 'i': 198 #if BX_SUPPORT_SMP == 0 199 fprintf(logfd, "%08x", BX_CPU(0)->dword.eip); 200 #endif 201 break; 202 case 'e': 203 fprintf(logfd, "%c", c); 204 break; 205 case '%': 206 fprintf(logfd,"%%"); 207 break; 208 default: 209 fprintf(logfd,"%%%c",*s); 210 } 211 break; 212 default : 213 fprintf(logfd,"%c",*s); 214 } 215 s++; 216 } 217 218 fprintf(logfd," "); 219 220 if(l==LOGLEV_PANIC) 221 fprintf(logfd, ">>PANIC<< "); 222 if(l==LOGLEV_PASS) 223 fprintf(logfd, ">>PASS<< "); 224 225 vfprintf(logfd, fmt, ap); 226 fprintf(logfd, "\n"); 227 fflush(logfd); 228 } 229 230 iofunctions::iofunctions(FILE *fs) 231 { 232 init(); 233 init_log(fs); 234 } 235 236 iofunctions::iofunctions(const char *fn) 237 { 238 init(); 239 init_log(fn); 240 } 241 242 iofunctions::iofunctions(int fd) 243 { 244 init(); 245 init_log(fd); 246 } 247 248 iofunctions::iofunctions() 249 { 250 init(); 251 } 252 253 iofunctions::~iofunctions(void) 254 { 255 // flush before erasing magic number, or flush does nothing. 256 flush(); 257 magic=0; 258 } 259 260 #define LOG_THIS genlog-> 261 262 int logfunctions::default_onoff[N_LOGLEV] = 263 { 264 ACT_IGNORE, // ignore debug 265 ACT_REPORT, // report info 266 ACT_REPORT, // report error 267 #if BX_WITH_WX || BX_WITH_WIN32 || BX_WITH_X11 268 ACT_ASK, // on panic, ask user what to do 269 #else 270 ACT_FATAL, // on panic, quit 271 #endif 272 ACT_FATAL 273 }; 274 275 logfunctions::logfunctions(void) 276 { 277 prefix = NULL; 278 put(" "); 279 settype(GENLOG); 280 if (io == NULL && Allocio == 0) { 281 Allocio = 1; 282 io = new iofunc_t(stderr); 283 } 284 setio(io); 285 // BUG: unfortunately this can be called before the bochsrc is read, 286 // which means that the bochsrc has no effect on the actions. 287 for (int i=0; i<N_LOGLEV; i++) 288 onoff[i] = get_default_action(i); 289 } 290 291 logfunctions::logfunctions(iofunc_t *iofunc) 292 { 293 prefix = NULL; 294 put(" "); 295 settype(GENLOG); 296 setio(iofunc); 297 // BUG: unfortunately this can be called before the bochsrc is read, 298 // which means that the bochsrc has no effect on the actions. 299 for (int i=0; i<N_LOGLEV; i++) 300 onoff[i] = get_default_action(i); 301 } 302 303 logfunctions::~logfunctions() 304 { 305 this->logio->remove_logfn(this); 306 if (prefix) free(prefix); 307 } 308 309 void logfunctions::setio(iofunc_t *i) 310 { 311 // add pointer to iofunction object to use 312 this->logio = i; 313 // give iofunction a pointer to me 314 i->add_logfn(this); 315 } 316 317 void logfunctions::put(char *p) 318 { 319 char * tmpbuf=strdup("[ ]"); // if we ever have more than 32 chars, 320 // we need to rethink this 321 322 if (tmpbuf == NULL) 323 { 324 return; // allocation not successful 325 } 326 327 if (this->prefix != NULL) 328 { 329 free(this->prefix); // free previously allocated memory 330 prefix = NULL; 331 } 332 333 int len=strlen(p); 334 for(int i=1;i<len+1;i++) { 335 tmpbuf[i]=p[i-1]; 336 } 337 338 switch(len) { 339 case 1: tmpbuf[2]=' '; 340 case 2: tmpbuf[3]=' '; 341 case 3: tmpbuf[4]=' '; 342 case 4: tmpbuf[5]=' '; 343 default: tmpbuf[6]=']'; tmpbuf[7]='\0'; break; 344 } 345 346 prefix=tmpbuf; 347 } 348 349 void logfunctions::settype(int t) 350 { 351 type=t; 352 } 353 354 void logfunctions::info(const char *fmt, ...) 355 { 356 va_list ap; 357 358 assert(this != NULL); 359 assert(this->logio != NULL); 360 361 if(!onoff[LOGLEV_INFO]) return; 362 363 va_start(ap, fmt); 364 this->logio->out(this->type,LOGLEV_INFO,this->prefix, fmt, ap); 365 if (onoff[LOGLEV_INFO] == ACT_ASK) 366 ask(LOGLEV_INFO, this->prefix, fmt, ap); 367 if (onoff[LOGLEV_INFO] == ACT_FATAL) 368 fatal(this->prefix, fmt, ap, 1); 369 va_end(ap); 370 } 371 372 void logfunctions::error(const char *fmt, ...) 373 { 374 va_list ap; 375 376 assert(this != NULL); 377 assert(this->logio != NULL); 378 379 if(!onoff[LOGLEV_ERROR]) return; 380 381 va_start(ap, fmt); 382 this->logio->out(this->type,LOGLEV_ERROR,this->prefix, fmt, ap); 383 if (onoff[LOGLEV_ERROR] == ACT_ASK) 384 ask(LOGLEV_ERROR, this->prefix, fmt, ap); 385 if (onoff[LOGLEV_ERROR] == ACT_FATAL) 386 fatal(this->prefix, fmt, ap, 1); 387 va_end(ap); 388 } 389 390 void logfunctions::panic(const char *fmt, ...) 391 { 392 va_list ap; 393 394 assert(this != NULL); 395 assert(this->logio != NULL); 396 397 // Special case for panics since they are so important. Always print 398 // the panic to the log, no matter what the log action says. 399 //if(!onoff[LOGLEV_PANIC]) return; 400 401 va_start(ap, fmt); 402 this->logio->out(this->type,LOGLEV_PANIC,this->prefix, fmt, ap); 403 404 // This fixes a funny bug on linuxppc where va_list is no pointer but a struct 405 va_end(ap); 406 va_start(ap, fmt); 407 408 if (onoff[LOGLEV_PANIC] == ACT_ASK) 409 ask(LOGLEV_PANIC, this->prefix, fmt, ap); 410 if (onoff[LOGLEV_PANIC] == ACT_FATAL) 411 fatal(this->prefix, fmt, ap, 1); 412 va_end(ap); 413 } 414 415 void logfunctions::pass(const char *fmt, ...) 416 { 417 va_list ap; 418 419 assert(this != NULL); 420 assert(this->logio != NULL); 421 422 // Special case for panics since they are so important. Always print 423 // the panic to the log, no matter what the log action says. 424 //if(!onoff[LOGLEV_PASS]) return; 425 426 va_start(ap, fmt); 427 this->logio->out(this->type,LOGLEV_PASS,this->prefix, fmt, ap); 428 429 // This fixes a funny bug on linuxppc where va_list is no pointer but a struct 430 va_end(ap); 431 va_start(ap, fmt); 432 433 if (onoff[LOGLEV_PASS] == ACT_ASK) 434 ask(LOGLEV_PASS, this->prefix, fmt, ap); 435 if (onoff[LOGLEV_PASS] == ACT_FATAL) 436 fatal(this->prefix, fmt, ap, 101); 437 va_end(ap); 438 } 439 440 void logfunctions::ldebug(const char *fmt, ...) 441 { 442 va_list ap; 443 444 assert(this != NULL); 445 assert(this->logio != NULL); 446 447 if(!onoff[LOGLEV_DEBUG]) return; 448 449 va_start(ap, fmt); 450 this->logio->out(this->type,LOGLEV_DEBUG,this->prefix, fmt, ap); 451 if (onoff[LOGLEV_DEBUG] == ACT_ASK) 452 ask(LOGLEV_DEBUG, this->prefix, fmt, ap); 453 if (onoff[LOGLEV_DEBUG] == ACT_FATAL) 454 fatal(this->prefix, fmt, ap, 1); 455 va_end(ap); 456 } 457 458 void logfunctions::ask(int level, const char *prefix, const char *fmt, va_list ap) 459 { 460 // Guard against reentry on ask() function. The danger is that some 461 // function that's called within ask() could trigger another 462 // BX_PANIC that could call ask() again, leading to infinite 463 // recursion and infinite asks. 464 static char in_ask_already = 0; 465 char buf1[1024]; 466 if (in_ask_already) { 467 fprintf(stderr, "logfunctions::ask() should not reenter!!\n"); 468 return; 469 } 470 in_ask_already = 1; 471 vsnprintf(buf1, sizeof(buf1), fmt, ap); 472 // FIXME: facility set to 0 because it's unknown. 473 474 // update vga screen. This is useful because sometimes useful messages 475 // are printed on the screen just before a panic. It's also potentially 476 // dangerous if this function calls ask again... That's why I added 477 // the reentry check above. 478 if (SIM->get_init_done()) DEV_vga_refresh(); 479 480 #if !BX_EXTERNAL_DEBUGGER 481 // ensure the text screen is showing 482 SIM->set_display_mode(DISP_MODE_CONFIG); 483 int val = SIM->log_msg(prefix, level, buf1); 484 switch(val) 485 { 486 case BX_LOG_ASK_CHOICE_CONTINUE: 487 break; 488 case BX_LOG_ASK_CHOICE_CONTINUE_ALWAYS: 489 // user said continue, and don't "ask" for this facility again. 490 setonoff(level, ACT_REPORT); 491 break; 492 case BX_LOG_ASK_CHOICE_DIE: 493 case BX_LOG_NOTIFY_FAILED: 494 bx_user_quit = (val==BX_LOG_ASK_CHOICE_DIE)?1:0; 495 in_ask_already = 0; // because fatal will longjmp out 496 fatal(prefix, buf1, ap, 1); 497 // should never get here 498 BX_PANIC(("in ask(), fatal() should never return!")); 499 break; 500 case BX_LOG_ASK_CHOICE_DUMP_CORE: 501 fprintf(stderr, "User chose to dump core...\n"); 502 #if BX_HAVE_ABORT 503 abort(); 504 #else 505 // do something highly illegal that should kill the process. 506 // Hey, this is fun! 507 { 508 char *crashptr = (char *)0; char c = *crashptr; 509 } 510 fprintf(stderr, "Sorry, I couldn't find your abort() function. Exiting."); 511 exit(0); 512 #endif 513 #if BX_DEBUGGER 514 case BX_LOG_ASK_CHOICE_ENTER_DEBUG: 515 // user chose debugger. To "drop into the debugger" we just set the 516 // interrupt_requested bit and continue execution. Before the next 517 // instruction, it should notice the user interrupt and return to 518 // the debugger. 519 bx_debug_break(); 520 break; 521 #elif BX_GDBSTUB 522 case BX_LOG_ASK_CHOICE_ENTER_DEBUG: 523 bx_gdbstub_break(); 524 break; 525 #endif 526 default: 527 // this happens if panics happen before the callback is initialized 528 // in gui/control.cc. 529 fprintf(stderr, "WARNING: log_msg returned unexpected value %d\n", val); 530 } 531 #else 532 // external debugger ask code goes here 533 #endif 534 // return to simulation mode 535 SIM->set_display_mode(DISP_MODE_SIM); 536 in_ask_already = 0; 537 } 538 539 #if BX_WITH_CARBON 540 /* Panic button to display fatal errors. 541 Completely self contained, can't rely on carbon.cc being available */ 542 static void carbonFatalDialog(const char *error, const char *exposition) 543 { 544 DialogRef alertDialog; 545 CFStringRef cfError; 546 CFStringRef cfExposition; 547 DialogItemIndex index; 548 AlertStdCFStringAlertParamRec alertParam = {0}; 549 550 // Init libraries 551 InitCursor(); 552 // Assemble dialog 553 cfError = CFStringCreateWithCString(NULL, error, kCFStringEncodingASCII); 554 if(exposition != NULL) 555 { 556 cfExposition = CFStringCreateWithCString(NULL, exposition, kCFStringEncodingASCII); 557 } 558 else { 559 cfExposition = NULL; 560 } 561 alertParam.version = kStdCFStringAlertVersionOne; 562 alertParam.defaultText = CFSTR("Quit"); 563 alertParam.position = kWindowDefaultPosition; 564 alertParam.defaultButton = kAlertStdAlertOKButton; 565 // Display Dialog 566 CreateStandardAlert( 567 kAlertStopAlert, 568 cfError, 569 cfExposition, /* can be NULL */ 570 &alertParam, /* can be NULL */ 571 &alertDialog); 572 RunStandardAlert(alertDialog, NULL, &index); 573 // Cleanup 574 CFRelease(cfError); 575 if(cfExposition != NULL) { CFRelease(cfExposition); } 576 } 577 #endif 578 579 void logfunctions::fatal(const char *prefix, const char *fmt, va_list ap, int exit_status) 580 { 581 #if !BX_DEBUGGER 582 bx_atexit(); 583 #endif 584 #if BX_WITH_CARBON 585 if(!isatty(STDIN_FILENO) && !SIM->get_init_done()) 586 { 587 char buf1[1024]; 588 char buf2[1024]; 589 vsnprintf(buf1, sizeof(buf1), fmt, ap); 590 snprintf(buf2, sizeof(buf2), "Bochs startup error\n%s", buf1); 591 carbonFatalDialog(buf2, 592 "For more information, try running Bochs within Terminal by clicking on \"bochs.scpt\"."); 593 } 594 #endif 595 #if !BX_WITH_WX 596 static char *divider = "========================================================================"; 597 fprintf(stderr, "%s\n", divider); 598 fprintf(stderr, "Bochs is exiting with the following message:\n"); 599 fprintf(stderr, "%s ", prefix); 600 vfprintf(stderr, fmt, ap); 601 fprintf(stderr, "\n%s\n", divider); 602 #endif 603 #if !BX_DEBUGGER 604 BX_EXIT(exit_status); 605 #else 606 static bx_bool dbg_exit_called = 0; 607 if (dbg_exit_called == 0) { 608 dbg_exit_called = 1; 609 bx_dbg_exit(exit_status); 610 } 611 #endif 612 // not safe to use BX_* log functions in here. 613 fprintf(stderr, "fatal() should never return, but it just did\n"); 614 } 615 616 iofunc_t *io = NULL; 617 logfunc_t *genlog = NULL; 618 619 void bx_center_print(FILE *file, char *line, int maxwidth) 620 { 621 int len = strlen(line); 622 if (len > maxwidth) 623 BX_PANIC(("bx_center_print: line is too long: '%s'", line)); 624 int imax = (maxwidth - len) >> 1; 625 for (int i=0; i<imax; i++) fputc(' ', file); 626 fputs(line, file); 627 } 628

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.