Home | History | Annotate | Download | only in qemu
      1 /*
      2  * Error reporting
      3  *
      4  * Copyright (C) 2010 Red Hat Inc.
      5  *
      6  * Authors:
      7  *  Markus Armbruster <armbru (at) redhat.com>,
      8  *
      9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
     10  * See the COPYING file in the top-level directory.
     11  */
     12 
     13 #include <stdio.h>
     14 #include "monitor.h"
     15 
     16 /*
     17  * Print to current monitor if we have one, else to stderr.
     18  * TODO should return int, so callers can calculate width, but that
     19  * requires surgery to monitor_vprintf().  Left for another day.
     20  */
     21 void error_vprintf(const char *fmt, va_list ap)
     22 {
     23     if (cur_mon) {
     24         monitor_vprintf(cur_mon, fmt, ap);
     25     } else {
     26         vfprintf(stderr, fmt, ap);
     27     }
     28 }
     29 
     30 /*
     31  * Print to current monitor if we have one, else to stderr.
     32  * TODO just like error_vprintf()
     33  */
     34 void error_printf(const char *fmt, ...)
     35 {
     36     va_list ap;
     37 
     38     va_start(ap, fmt);
     39     error_vprintf(fmt, ap);
     40     va_end(ap);
     41 }
     42 
     43 void error_printf_unless_qmp(const char *fmt, ...)
     44 {
     45     va_list ap;
     46 
     47     if (!monitor_cur_is_qmp()) {
     48         va_start(ap, fmt);
     49         error_vprintf(fmt, ap);
     50         va_end(ap);
     51     }
     52 }
     53 
     54 static Location std_loc = {
     55     .kind = LOC_NONE
     56 };
     57 static Location *cur_loc = &std_loc;
     58 
     59 /*
     60  * Push location saved in LOC onto the location stack, return it.
     61  * The top of that stack is the current location.
     62  * Needs a matching loc_pop().
     63  */
     64 Location *loc_push_restore(Location *loc)
     65 {
     66     assert(!loc->prev);
     67     loc->prev = cur_loc;
     68     cur_loc = loc;
     69     return loc;
     70 }
     71 
     72 /*
     73  * Initialize *LOC to "nowhere", push it onto the location stack.
     74  * The top of that stack is the current location.
     75  * Needs a matching loc_pop().
     76  * Return LOC.
     77  */
     78 Location *loc_push_none(Location *loc)
     79 {
     80     loc->kind = LOC_NONE;
     81     loc->prev = NULL;
     82     return loc_push_restore(loc);
     83 }
     84 
     85 /*
     86  * Pop the location stack.
     87  * LOC must be the current location, i.e. the top of the stack.
     88  */
     89 Location *loc_pop(Location *loc)
     90 {
     91     assert(cur_loc == loc && loc->prev);
     92     cur_loc = loc->prev;
     93     loc->prev = NULL;
     94     return loc;
     95 }
     96 
     97 /*
     98  * Save the current location in LOC, return LOC.
     99  */
    100 Location *loc_save(Location *loc)
    101 {
    102     *loc = *cur_loc;
    103     loc->prev = NULL;
    104     return loc;
    105 }
    106 
    107 /*
    108  * Change the current location to the one saved in LOC.
    109  */
    110 void loc_restore(Location *loc)
    111 {
    112     Location *prev = cur_loc->prev;
    113     assert(!loc->prev);
    114     *cur_loc = *loc;
    115     cur_loc->prev = prev;
    116 }
    117 
    118 /*
    119  * Change the current location to "nowhere in particular".
    120  */
    121 void loc_set_none(void)
    122 {
    123     cur_loc->kind = LOC_NONE;
    124 }
    125 
    126 /*
    127  * Change the current location to argument ARGV[IDX..IDX+CNT-1].
    128  */
    129 void loc_set_cmdline(char **argv, int idx, int cnt)
    130 {
    131     cur_loc->kind = LOC_CMDLINE;
    132     cur_loc->num = cnt;
    133     cur_loc->ptr = argv + idx;
    134 }
    135 
    136 /*
    137  * Change the current location to file FNAME, line LNO.
    138  */
    139 void loc_set_file(const char *fname, int lno)
    140 {
    141     assert (fname || cur_loc->kind == LOC_FILE);
    142     cur_loc->kind = LOC_FILE;
    143     cur_loc->num = lno;
    144     if (fname) {
    145         cur_loc->ptr = fname;
    146     }
    147 }
    148 
    149 static const char *progname;
    150 
    151 /*
    152  * Set the program name for error_print_loc().
    153  */
    154 void error_set_progname(const char *argv0)
    155 {
    156     const char *p = strrchr(argv0, '/');
    157     progname = p ? p + 1 : argv0;
    158 }
    159 
    160 /*
    161  * Print current location to current monitor if we have one, else to stderr.
    162  */
    163 void error_print_loc(void)
    164 {
    165     const char *sep = "";
    166     int i;
    167     const char *const *argp;
    168 
    169     if (!cur_mon && progname) {
    170         fprintf(stderr, "%s:", progname);
    171         sep = " ";
    172     }
    173     switch (cur_loc->kind) {
    174     case LOC_CMDLINE:
    175         argp = cur_loc->ptr;
    176         for (i = 0; i < cur_loc->num; i++) {
    177             error_printf("%s%s", sep, argp[i]);
    178             sep = " ";
    179         }
    180         error_printf(": ");
    181         break;
    182     case LOC_FILE:
    183         error_printf("%s:", (const char *)cur_loc->ptr);
    184         if (cur_loc->num) {
    185             error_printf("%d:", cur_loc->num);
    186         }
    187         error_printf(" ");
    188         break;
    189     default:
    190         error_printf("%s", sep);
    191     }
    192 }
    193 
    194 /*
    195  * Print an error message to current monitor if we have one, else to stderr.
    196  * Prepend the current location and append a newline.
    197  * It's wrong to call this in a QMP monitor.  Use qerror_report() there.
    198  */
    199 void error_report(const char *fmt, ...)
    200 {
    201     va_list ap;
    202 
    203     error_print_loc();
    204     va_start(ap, fmt);
    205     error_vprintf(fmt, ap);
    206     va_end(ap);
    207     error_printf("\n");
    208 }
    209