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

string-output-visitor.c (10506B)


      1/*
      2 * String printing Visitor
      3 *
      4 * Copyright Red Hat, Inc. 2012-2016
      5 *
      6 * Author: Paolo Bonzini <pbonzini@redhat.com>
      7 *
      8 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
      9 * See the COPYING.LIB file in the top-level directory.
     10 *
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "qemu/cutils.h"
     15#include "qapi/string-output-visitor.h"
     16#include "qapi/visitor-impl.h"
     17#include "qemu/host-utils.h"
     18#include <math.h>
     19#include "qemu/range.h"
     20
     21enum ListMode {
     22    LM_NONE,             /* not traversing a list of repeated options */
     23    LM_STARTED,          /* next_list() ready to be called */
     24
     25    LM_IN_PROGRESS,      /* next_list() has been called.
     26                          *
     27                          * Generating the next list link will consume the most
     28                          * recently parsed QemuOpt instance of the repeated
     29                          * option.
     30                          *
     31                          * Parsing a value into the list link will examine the
     32                          * next QemuOpt instance of the repeated option, and
     33                          * possibly enter LM_SIGNED_INTERVAL or
     34                          * LM_UNSIGNED_INTERVAL.
     35                          */
     36
     37    LM_SIGNED_INTERVAL,  /* next_list() has been called.
     38                          *
     39                          * Generating the next list link will consume the most
     40                          * recently stored element from the signed interval,
     41                          * parsed from the most recent QemuOpt instance of the
     42                          * repeated option. This may consume QemuOpt itself
     43                          * and return to LM_IN_PROGRESS.
     44                          *
     45                          * Parsing a value into the list link will store the
     46                          * next element of the signed interval.
     47                          */
     48
     49    LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */
     50
     51    LM_END,              /* next_list() called, about to see last element. */
     52};
     53
     54typedef enum ListMode ListMode;
     55
     56struct StringOutputVisitor
     57{
     58    Visitor visitor;
     59    bool human;
     60    GString *string;
     61    char **result;
     62    ListMode list_mode;
     63    union {
     64        int64_t s;
     65        uint64_t u;
     66    } range_start, range_end;
     67    GList *ranges;
     68    void *list; /* Only needed for sanity checking the caller */
     69};
     70
     71static StringOutputVisitor *to_sov(Visitor *v)
     72{
     73    return container_of(v, StringOutputVisitor, visitor);
     74}
     75
     76static void string_output_set(StringOutputVisitor *sov, char *string)
     77{
     78    if (sov->string) {
     79        g_string_free(sov->string, true);
     80    }
     81    sov->string = g_string_new(string);
     82    g_free(string);
     83}
     84
     85static void string_output_append(StringOutputVisitor *sov, int64_t a)
     86{
     87    Range *r = g_malloc0(sizeof(*r));
     88
     89    range_set_bounds(r, a, a);
     90    sov->ranges = range_list_insert(sov->ranges, r);
     91}
     92
     93static void string_output_append_range(StringOutputVisitor *sov,
     94                                       int64_t s, int64_t e)
     95{
     96    Range *r = g_malloc0(sizeof(*r));
     97
     98    range_set_bounds(r, s, e);
     99    sov->ranges = range_list_insert(sov->ranges, r);
    100}
    101
    102static void format_string(StringOutputVisitor *sov, Range *r, bool next,
    103                          bool human)
    104{
    105    if (range_lob(r) != range_upb(r)) {
    106        if (human) {
    107            g_string_append_printf(sov->string, "0x%" PRIx64 "-0x%" PRIx64,
    108                                   range_lob(r), range_upb(r));
    109
    110        } else {
    111            g_string_append_printf(sov->string, "%" PRId64 "-%" PRId64,
    112                                   range_lob(r), range_upb(r));
    113        }
    114    } else {
    115        if (human) {
    116            g_string_append_printf(sov->string, "0x%" PRIx64, range_lob(r));
    117        } else {
    118            g_string_append_printf(sov->string, "%" PRId64, range_lob(r));
    119        }
    120    }
    121    if (next) {
    122        g_string_append(sov->string, ",");
    123    }
    124}
    125
    126static bool print_type_int64(Visitor *v, const char *name, int64_t *obj,
    127                             Error **errp)
    128{
    129    StringOutputVisitor *sov = to_sov(v);
    130    GList *l;
    131
    132    switch (sov->list_mode) {
    133    case LM_NONE:
    134        string_output_append(sov, *obj);
    135        break;
    136
    137    case LM_STARTED:
    138        sov->range_start.s = *obj;
    139        sov->range_end.s = *obj;
    140        sov->list_mode = LM_IN_PROGRESS;
    141        return true;
    142
    143    case LM_IN_PROGRESS:
    144        if (sov->range_end.s + 1 == *obj) {
    145            sov->range_end.s++;
    146        } else {
    147            if (sov->range_start.s == sov->range_end.s) {
    148                string_output_append(sov, sov->range_end.s);
    149            } else {
    150                assert(sov->range_start.s < sov->range_end.s);
    151                string_output_append_range(sov, sov->range_start.s,
    152                                           sov->range_end.s);
    153            }
    154
    155            sov->range_start.s = *obj;
    156            sov->range_end.s = *obj;
    157        }
    158        return true;
    159
    160    case LM_END:
    161        if (sov->range_end.s + 1 == *obj) {
    162            sov->range_end.s++;
    163            assert(sov->range_start.s < sov->range_end.s);
    164            string_output_append_range(sov, sov->range_start.s,
    165                                       sov->range_end.s);
    166        } else {
    167            if (sov->range_start.s == sov->range_end.s) {
    168                string_output_append(sov, sov->range_end.s);
    169            } else {
    170                assert(sov->range_start.s < sov->range_end.s);
    171
    172                string_output_append_range(sov, sov->range_start.s,
    173                                           sov->range_end.s);
    174            }
    175            string_output_append(sov, *obj);
    176        }
    177        break;
    178
    179    default:
    180        abort();
    181    }
    182
    183    l = sov->ranges;
    184    while (l) {
    185        Range *r = l->data;
    186        format_string(sov, r, l->next != NULL, false);
    187        l = l->next;
    188    }
    189
    190    if (sov->human) {
    191        l = sov->ranges;
    192        g_string_append(sov->string, " (");
    193        while (l) {
    194            Range *r = l->data;
    195            format_string(sov, r, l->next != NULL, true);
    196            l = l->next;
    197        }
    198        g_string_append(sov->string, ")");
    199    }
    200
    201    return true;
    202}
    203
    204static bool print_type_uint64(Visitor *v, const char *name, uint64_t *obj,
    205                             Error **errp)
    206{
    207    /* FIXME: print_type_int64 mishandles values over INT64_MAX */
    208    int64_t i = *obj;
    209    return print_type_int64(v, name, &i, errp);
    210}
    211
    212static bool print_type_size(Visitor *v, const char *name, uint64_t *obj,
    213                            Error **errp)
    214{
    215    StringOutputVisitor *sov = to_sov(v);
    216    uint64_t val;
    217    char *out, *psize;
    218
    219    if (!sov->human) {
    220        out = g_strdup_printf("%"PRIu64, *obj);
    221        string_output_set(sov, out);
    222        return true;
    223    }
    224
    225    val = *obj;
    226    psize = size_to_str(val);
    227    out = g_strdup_printf("%"PRIu64" (%s)", val, psize);
    228    string_output_set(sov, out);
    229
    230    g_free(psize);
    231    return true;
    232}
    233
    234static bool print_type_bool(Visitor *v, const char *name, bool *obj,
    235                            Error **errp)
    236{
    237    StringOutputVisitor *sov = to_sov(v);
    238    string_output_set(sov, g_strdup(*obj ? "true" : "false"));
    239    return true;
    240}
    241
    242static bool print_type_str(Visitor *v, const char *name, char **obj,
    243                           Error **errp)
    244{
    245    StringOutputVisitor *sov = to_sov(v);
    246    char *out;
    247
    248    if (sov->human) {
    249        out = *obj ? g_strdup_printf("\"%s\"", *obj) : g_strdup("<null>");
    250    } else {
    251        out = g_strdup(*obj ? *obj : "");
    252    }
    253    string_output_set(sov, out);
    254    return true;
    255}
    256
    257static bool print_type_number(Visitor *v, const char *name, double *obj,
    258                              Error **errp)
    259{
    260    StringOutputVisitor *sov = to_sov(v);
    261    string_output_set(sov, g_strdup_printf("%.17g", *obj));
    262    return true;
    263}
    264
    265static bool print_type_null(Visitor *v, const char *name, QNull **obj,
    266                            Error **errp)
    267{
    268    StringOutputVisitor *sov = to_sov(v);
    269    char *out;
    270
    271    if (sov->human) {
    272        out = g_strdup("<null>");
    273    } else {
    274        out = g_strdup("");
    275    }
    276    string_output_set(sov, out);
    277    return true;
    278}
    279
    280static bool
    281start_list(Visitor *v, const char *name, GenericList **list, size_t size,
    282           Error **errp)
    283{
    284    StringOutputVisitor *sov = to_sov(v);
    285
    286    /* we can't traverse a list in a list */
    287    assert(sov->list_mode == LM_NONE);
    288    /* We don't support visits without a list */
    289    assert(list);
    290    sov->list = list;
    291    /* List handling is only needed if there are at least two elements */
    292    if (*list && (*list)->next) {
    293        sov->list_mode = LM_STARTED;
    294    }
    295    return true;
    296}
    297
    298static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
    299{
    300    StringOutputVisitor *sov = to_sov(v);
    301    GenericList *ret = tail->next;
    302
    303    if (ret && !ret->next) {
    304        sov->list_mode = LM_END;
    305    }
    306    return ret;
    307}
    308
    309static void end_list(Visitor *v, void **obj)
    310{
    311    StringOutputVisitor *sov = to_sov(v);
    312
    313    assert(sov->list == obj);
    314    assert(sov->list_mode == LM_STARTED ||
    315           sov->list_mode == LM_END ||
    316           sov->list_mode == LM_NONE ||
    317           sov->list_mode == LM_IN_PROGRESS);
    318    sov->list_mode = LM_NONE;
    319}
    320
    321static void string_output_complete(Visitor *v, void *opaque)
    322{
    323    StringOutputVisitor *sov = to_sov(v);
    324
    325    assert(opaque == sov->result);
    326    *sov->result = g_string_free(sov->string, false);
    327    sov->string = NULL;
    328}
    329
    330static void free_range(void *range, void *dummy)
    331{
    332    g_free(range);
    333}
    334
    335static void string_output_free(Visitor *v)
    336{
    337    StringOutputVisitor *sov = to_sov(v);
    338
    339    if (sov->string) {
    340        g_string_free(sov->string, true);
    341    }
    342
    343    g_list_foreach(sov->ranges, free_range, NULL);
    344    g_list_free(sov->ranges);
    345    g_free(sov);
    346}
    347
    348Visitor *string_output_visitor_new(bool human, char **result)
    349{
    350    StringOutputVisitor *v;
    351
    352    v = g_malloc0(sizeof(*v));
    353
    354    v->string = g_string_new(NULL);
    355    v->human = human;
    356    v->result = result;
    357    *result = NULL;
    358
    359    v->visitor.type = VISITOR_OUTPUT;
    360    v->visitor.type_int64 = print_type_int64;
    361    v->visitor.type_uint64 = print_type_uint64;
    362    v->visitor.type_size = print_type_size;
    363    v->visitor.type_bool = print_type_bool;
    364    v->visitor.type_str = print_type_str;
    365    v->visitor.type_number = print_type_number;
    366    v->visitor.type_null = print_type_null;
    367    v->visitor.start_list = start_list;
    368    v->visitor.next_list = next_list;
    369    v->visitor.end_list = end_list;
    370    v->visitor.complete = string_output_complete;
    371    v->visitor.free = string_output_free;
    372
    373    return &v->visitor;
    374}