cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

qemu-error.c (10081B)


      1/*
      2 * Error reporting
      3 *
      4 * Copyright (C) 2010 Red Hat Inc.
      5 *
      6 * Authors:
      7 *  Markus Armbruster <armbru@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 "qemu/osdep.h"
     14#include "monitor/monitor.h"
     15#include "qemu/error-report.h"
     16
     17/*
     18 * @report_type is the type of message: error, warning or
     19 * informational.
     20 */
     21typedef enum {
     22    REPORT_TYPE_ERROR,
     23    REPORT_TYPE_WARNING,
     24    REPORT_TYPE_INFO,
     25} report_type;
     26
     27/* Prepend timestamp to messages */
     28bool message_with_timestamp;
     29bool error_with_guestname;
     30const char *error_guest_name;
     31
     32int error_printf(const char *fmt, ...)
     33{
     34    va_list ap;
     35    int ret;
     36
     37    va_start(ap, fmt);
     38    ret = error_vprintf(fmt, ap);
     39    va_end(ap);
     40    return ret;
     41}
     42
     43int error_printf_unless_qmp(const char *fmt, ...)
     44{
     45    va_list ap;
     46    int ret;
     47
     48    va_start(ap, fmt);
     49    ret = error_vprintf_unless_qmp(fmt, ap);
     50    va_end(ap);
     51    return ret;
     52}
     53
     54static Location std_loc = {
     55    .kind = LOC_NONE
     56};
     57static 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 */
     64Location *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 */
     78Location *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 */
     89Location *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 */
    100Location *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 */
    110void 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 */
    121void 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 */
    129void 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 */
    139void 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
    149static const char *progname;
    150
    151/*
    152 * Set the program name for error_print_loc().
    153 */
    154static void error_set_progname(const char *argv0)
    155{
    156    const char *p = strrchr(argv0, '/');
    157    progname = p ? p + 1 : argv0;
    158}
    159
    160const char *error_get_progname(void)
    161{
    162    return progname;
    163}
    164
    165/*
    166 * Print current location to current monitor if we have one, else to stderr.
    167 */
    168static void print_loc(void)
    169{
    170    const char *sep = "";
    171    int i;
    172    const char *const *argp;
    173
    174    if (!monitor_cur() && progname) {
    175        fprintf(stderr, "%s:", progname);
    176        sep = " ";
    177    }
    178    switch (cur_loc->kind) {
    179    case LOC_CMDLINE:
    180        argp = cur_loc->ptr;
    181        for (i = 0; i < cur_loc->num; i++) {
    182            error_printf("%s%s", sep, argp[i]);
    183            sep = " ";
    184        }
    185        error_printf(": ");
    186        break;
    187    case LOC_FILE:
    188        error_printf("%s:", (const char *)cur_loc->ptr);
    189        if (cur_loc->num) {
    190            error_printf("%d:", cur_loc->num);
    191        }
    192        error_printf(" ");
    193        break;
    194    default:
    195        error_printf("%s", sep);
    196    }
    197}
    198
    199/*
    200 * Print a message to current monitor if we have one, else to stderr.
    201 * @report_type is the type of message: error, warning or informational.
    202 * Format arguments like vsprintf().  The resulting message should be
    203 * a single phrase, with no newline or trailing punctuation.
    204 * Prepend the current location and append a newline.
    205 */
    206static void vreport(report_type type, const char *fmt, va_list ap)
    207{
    208    GTimeVal tv;
    209    gchar *timestr;
    210
    211    if (message_with_timestamp && !monitor_cur()) {
    212        g_get_current_time(&tv);
    213        timestr = g_time_val_to_iso8601(&tv);
    214        error_printf("%s ", timestr);
    215        g_free(timestr);
    216    }
    217
    218    /* Only prepend guest name if -msg guest-name and -name guest=... are set */
    219    if (error_with_guestname && error_guest_name && !monitor_cur()) {
    220        error_printf("%s ", error_guest_name);
    221    }
    222
    223    print_loc();
    224
    225    switch (type) {
    226    case REPORT_TYPE_ERROR:
    227        break;
    228    case REPORT_TYPE_WARNING:
    229        error_printf("warning: ");
    230        break;
    231    case REPORT_TYPE_INFO:
    232        error_printf("info: ");
    233        break;
    234    }
    235
    236    error_vprintf(fmt, ap);
    237    error_printf("\n");
    238}
    239
    240/*
    241 * Print an error message to current monitor if we have one, else to stderr.
    242 * Format arguments like vsprintf().  The resulting message should be
    243 * a single phrase, with no newline or trailing punctuation.
    244 * Prepend the current location and append a newline.
    245 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
    246 */
    247void error_vreport(const char *fmt, va_list ap)
    248{
    249    vreport(REPORT_TYPE_ERROR, fmt, ap);
    250}
    251
    252/*
    253 * Print a warning message to current monitor if we have one, else to stderr.
    254 * Format arguments like vsprintf().  The resulting message should be
    255 * a single phrase, with no newline or trailing punctuation.
    256 * Prepend the current location and append a newline.
    257 */
    258void warn_vreport(const char *fmt, va_list ap)
    259{
    260    vreport(REPORT_TYPE_WARNING, fmt, ap);
    261}
    262
    263/*
    264 * Print an information message to current monitor if we have one, else to
    265 * stderr.
    266 * Format arguments like vsprintf().  The resulting message should be
    267 * a single phrase, with no newline or trailing punctuation.
    268 * Prepend the current location and append a newline.
    269 */
    270void info_vreport(const char *fmt, va_list ap)
    271{
    272    vreport(REPORT_TYPE_INFO, fmt, ap);
    273}
    274
    275/*
    276 * Print an error message to current monitor if we have one, else to stderr.
    277 * Format arguments like sprintf().  The resulting message should be
    278 * a single phrase, with no newline or trailing punctuation.
    279 * Prepend the current location and append a newline.
    280 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
    281 */
    282void error_report(const char *fmt, ...)
    283{
    284    va_list ap;
    285
    286    va_start(ap, fmt);
    287    vreport(REPORT_TYPE_ERROR, fmt, ap);
    288    va_end(ap);
    289}
    290
    291/*
    292 * Print a warning message to current monitor if we have one, else to stderr.
    293 * Format arguments like sprintf(). The resulting message should be a
    294 * single phrase, with no newline or trailing punctuation.
    295 * Prepend the current location and append a newline.
    296 */
    297void warn_report(const char *fmt, ...)
    298{
    299    va_list ap;
    300
    301    va_start(ap, fmt);
    302    vreport(REPORT_TYPE_WARNING, fmt, ap);
    303    va_end(ap);
    304}
    305
    306/*
    307 * Print an information message to current monitor if we have one, else to
    308 * stderr.
    309 * Format arguments like sprintf(). The resulting message should be a
    310 * single phrase, with no newline or trailing punctuation.
    311 * Prepend the current location and append a newline.
    312 */
    313void info_report(const char *fmt, ...)
    314{
    315    va_list ap;
    316
    317    va_start(ap, fmt);
    318    vreport(REPORT_TYPE_INFO, fmt, ap);
    319    va_end(ap);
    320}
    321
    322/*
    323 * Like error_report(), except print just once.
    324 * If *printed is false, print the message, and flip *printed to true.
    325 * Return whether the message was printed.
    326 */
    327bool error_report_once_cond(bool *printed, const char *fmt, ...)
    328{
    329    va_list ap;
    330
    331    assert(printed);
    332    if (*printed) {
    333        return false;
    334    }
    335    *printed = true;
    336    va_start(ap, fmt);
    337    vreport(REPORT_TYPE_ERROR, fmt, ap);
    338    va_end(ap);
    339    return true;
    340}
    341
    342/*
    343 * Like warn_report(), except print just once.
    344 * If *printed is false, print the message, and flip *printed to true.
    345 * Return whether the message was printed.
    346 */
    347bool warn_report_once_cond(bool *printed, const char *fmt, ...)
    348{
    349    va_list ap;
    350
    351    assert(printed);
    352    if (*printed) {
    353        return false;
    354    }
    355    *printed = true;
    356    va_start(ap, fmt);
    357    vreport(REPORT_TYPE_WARNING, fmt, ap);
    358    va_end(ap);
    359    return true;
    360}
    361
    362static char *qemu_glog_domains;
    363
    364static void qemu_log_func(const gchar *log_domain,
    365                          GLogLevelFlags log_level,
    366                          const gchar *message,
    367                          gpointer user_data)
    368{
    369    switch (log_level & G_LOG_LEVEL_MASK) {
    370    case G_LOG_LEVEL_DEBUG:
    371    case G_LOG_LEVEL_INFO:
    372        /*
    373         * Use same G_MESSAGES_DEBUG logic as glib to enable/disable debug
    374         * messages
    375         */
    376        if (qemu_glog_domains == NULL) {
    377            break;
    378        }
    379        if (strcmp(qemu_glog_domains, "all") != 0 &&
    380          (log_domain == NULL || !strstr(qemu_glog_domains, log_domain))) {
    381            break;
    382        }
    383        /* Fall through */
    384    case G_LOG_LEVEL_MESSAGE:
    385        info_report("%s%s%s",
    386                    log_domain ?: "", log_domain ? ": " : "", message);
    387
    388        break;
    389    case G_LOG_LEVEL_WARNING:
    390        warn_report("%s%s%s",
    391                    log_domain ?: "", log_domain ? ": " : "", message);
    392        break;
    393    case G_LOG_LEVEL_CRITICAL:
    394    case G_LOG_LEVEL_ERROR:
    395        error_report("%s%s%s",
    396                     log_domain ?: "", log_domain ? ": " : "", message);
    397        break;
    398    }
    399}
    400
    401void error_init(const char *argv0)
    402{
    403    /* Set the program name for error_print_loc(). */
    404    error_set_progname(argv0);
    405
    406    /*
    407     * This sets up glib logging so libraries using it also print their logs
    408     * through error_report(), warn_report(), info_report().
    409     */
    410    g_log_set_default_handler(qemu_log_func, NULL);
    411    g_warn_if_fail(qemu_glog_domains == NULL);
    412    qemu_glog_domains = g_strdup(g_getenv("G_MESSAGES_DEBUG"));
    413}