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

readline.c (15160B)


      1/*
      2 * QEMU readline utility
      3 *
      4 * Copyright (c) 2003-2004 Fabrice Bellard
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "qemu/readline.h"
     27#include "qemu/ctype.h"
     28#include "qemu/cutils.h"
     29
     30#define IS_NORM 0
     31#define IS_ESC  1
     32#define IS_CSI  2
     33#define IS_SS3  3
     34
     35void readline_show_prompt(ReadLineState *rs)
     36{
     37    rs->printf_func(rs->opaque, "%s", rs->prompt);
     38    rs->flush_func(rs->opaque);
     39    rs->last_cmd_buf_index = 0;
     40    rs->last_cmd_buf_size = 0;
     41    rs->esc_state = IS_NORM;
     42}
     43
     44/* update the displayed command line */
     45static void readline_update(ReadLineState *rs)
     46{
     47    int i, delta, len;
     48
     49    if (rs->cmd_buf_size != rs->last_cmd_buf_size ||
     50        memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) {
     51        for (i = 0; i < rs->last_cmd_buf_index; i++) {
     52            rs->printf_func(rs->opaque, "\033[D");
     53        }
     54        rs->cmd_buf[rs->cmd_buf_size] = '\0';
     55        if (rs->read_password) {
     56            len = strlen(rs->cmd_buf);
     57            for (i = 0; i < len; i++) {
     58                rs->printf_func(rs->opaque, "*");
     59            }
     60        } else {
     61            rs->printf_func(rs->opaque, "%s", rs->cmd_buf);
     62        }
     63        rs->printf_func(rs->opaque, "\033[K");
     64        memcpy(rs->last_cmd_buf, rs->cmd_buf, rs->cmd_buf_size);
     65        rs->last_cmd_buf_size = rs->cmd_buf_size;
     66        rs->last_cmd_buf_index = rs->cmd_buf_size;
     67    }
     68    if (rs->cmd_buf_index != rs->last_cmd_buf_index) {
     69        delta = rs->cmd_buf_index - rs->last_cmd_buf_index;
     70        if (delta > 0) {
     71            for (i = 0; i < delta; i++) {
     72                rs->printf_func(rs->opaque, "\033[C");
     73            }
     74        } else {
     75            delta = -delta;
     76            for (i = 0; i < delta; i++) {
     77                rs->printf_func(rs->opaque, "\033[D");
     78            }
     79        }
     80        rs->last_cmd_buf_index = rs->cmd_buf_index;
     81    }
     82    rs->flush_func(rs->opaque);
     83}
     84
     85static void readline_insert_char(ReadLineState *rs, int ch)
     86{
     87    if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE) {
     88        memmove(rs->cmd_buf + rs->cmd_buf_index + 1,
     89                rs->cmd_buf + rs->cmd_buf_index,
     90                rs->cmd_buf_size - rs->cmd_buf_index);
     91        rs->cmd_buf[rs->cmd_buf_index] = ch;
     92        rs->cmd_buf_size++;
     93        rs->cmd_buf_index++;
     94    }
     95}
     96
     97static void readline_backward_char(ReadLineState *rs)
     98{
     99    if (rs->cmd_buf_index > 0) {
    100        rs->cmd_buf_index--;
    101    }
    102}
    103
    104static void readline_forward_char(ReadLineState *rs)
    105{
    106    if (rs->cmd_buf_index < rs->cmd_buf_size) {
    107        rs->cmd_buf_index++;
    108    }
    109}
    110
    111static void readline_delete_char(ReadLineState *rs)
    112{
    113    if (rs->cmd_buf_index < rs->cmd_buf_size) {
    114        memmove(rs->cmd_buf + rs->cmd_buf_index,
    115                rs->cmd_buf + rs->cmd_buf_index + 1,
    116                rs->cmd_buf_size - rs->cmd_buf_index - 1);
    117        rs->cmd_buf_size--;
    118    }
    119}
    120
    121static void readline_backspace(ReadLineState *rs)
    122{
    123    if (rs->cmd_buf_index > 0) {
    124        readline_backward_char(rs);
    125        readline_delete_char(rs);
    126    }
    127}
    128
    129static void readline_backword(ReadLineState *rs)
    130{
    131    int start;
    132
    133    if (rs->cmd_buf_index == 0 || rs->cmd_buf_index > rs->cmd_buf_size) {
    134        return;
    135    }
    136
    137    start = rs->cmd_buf_index - 1;
    138
    139    /* find first word (backwards) */
    140    while (start > 0) {
    141        if (!qemu_isspace(rs->cmd_buf[start])) {
    142            break;
    143        }
    144
    145        --start;
    146    }
    147
    148    /* find first space (backwards) */
    149    while (start > 0) {
    150        if (qemu_isspace(rs->cmd_buf[start])) {
    151            ++start;
    152            break;
    153        }
    154
    155        --start;
    156    }
    157
    158    /* remove word */
    159    if (start < rs->cmd_buf_index) {
    160        memmove(rs->cmd_buf + start,
    161                rs->cmd_buf + rs->cmd_buf_index,
    162                rs->cmd_buf_size - rs->cmd_buf_index);
    163        rs->cmd_buf_size -= rs->cmd_buf_index - start;
    164        rs->cmd_buf_index = start;
    165    }
    166}
    167
    168static void readline_bol(ReadLineState *rs)
    169{
    170    rs->cmd_buf_index = 0;
    171}
    172
    173static void readline_eol(ReadLineState *rs)
    174{
    175    rs->cmd_buf_index = rs->cmd_buf_size;
    176}
    177
    178static void readline_up_char(ReadLineState *rs)
    179{
    180    int idx;
    181
    182    if (rs->hist_entry == 0) {
    183        return;
    184    }
    185    if (rs->hist_entry == -1) {
    186        /* Find latest entry */
    187        for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
    188            if (rs->history[idx] == NULL) {
    189                break;
    190            }
    191        }
    192        rs->hist_entry = idx;
    193    }
    194    rs->hist_entry--;
    195    if (rs->hist_entry >= 0) {
    196        pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
    197                rs->history[rs->hist_entry]);
    198        rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
    199    }
    200}
    201
    202static void readline_down_char(ReadLineState *rs)
    203{
    204    if (rs->hist_entry == -1) {
    205        return;
    206    }
    207    if (rs->hist_entry < READLINE_MAX_CMDS - 1 &&
    208        rs->history[++rs->hist_entry] != NULL) {
    209        pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
    210                rs->history[rs->hist_entry]);
    211    } else {
    212        rs->cmd_buf[0] = 0;
    213        rs->hist_entry = -1;
    214    }
    215    rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
    216}
    217
    218static void readline_hist_add(ReadLineState *rs, const char *cmdline)
    219{
    220    char *hist_entry, *new_entry;
    221    int idx;
    222
    223    if (cmdline[0] == '\0') {
    224        return;
    225    }
    226    new_entry = NULL;
    227    if (rs->hist_entry != -1) {
    228        /* We were editing an existing history entry: replace it */
    229        hist_entry = rs->history[rs->hist_entry];
    230        idx = rs->hist_entry;
    231        if (strcmp(hist_entry, cmdline) == 0) {
    232            goto same_entry;
    233        }
    234    }
    235    /* Search cmdline in history buffers */
    236    for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
    237        hist_entry = rs->history[idx];
    238        if (hist_entry == NULL) {
    239            break;
    240        }
    241        if (strcmp(hist_entry, cmdline) == 0) {
    242        same_entry:
    243            if (idx == READLINE_MAX_CMDS - 1) {
    244                return;
    245            }
    246            new_entry = hist_entry;
    247            /* Put this entry at the end of history */
    248            memmove(&rs->history[idx], &rs->history[idx + 1],
    249                    (READLINE_MAX_CMDS - (idx + 1)) * sizeof(char *));
    250            rs->history[READLINE_MAX_CMDS - 1] = NULL;
    251            for (; idx < READLINE_MAX_CMDS; idx++) {
    252                if (rs->history[idx] == NULL) {
    253                    break;
    254                }
    255            }
    256            break;
    257        }
    258    }
    259    if (idx == READLINE_MAX_CMDS) {
    260        /* Need to get one free slot */
    261        g_free(rs->history[0]);
    262        memmove(rs->history, &rs->history[1],
    263                (READLINE_MAX_CMDS - 1) * sizeof(char *));
    264        rs->history[READLINE_MAX_CMDS - 1] = NULL;
    265        idx = READLINE_MAX_CMDS - 1;
    266    }
    267    if (new_entry == NULL) {
    268        new_entry = g_strdup(cmdline);
    269    }
    270    rs->history[idx] = new_entry;
    271    rs->hist_entry = -1;
    272}
    273
    274/* completion support */
    275
    276void readline_add_completion(ReadLineState *rs, const char *str)
    277{
    278    if (rs->nb_completions < READLINE_MAX_COMPLETIONS) {
    279        int i;
    280        for (i = 0; i < rs->nb_completions; i++) {
    281            if (!strcmp(rs->completions[i], str)) {
    282                return;
    283            }
    284        }
    285        rs->completions[rs->nb_completions++] = g_strdup(str);
    286    }
    287}
    288
    289void readline_set_completion_index(ReadLineState *rs, int index)
    290{
    291    rs->completion_index = index;
    292}
    293
    294static int completion_comp(const void *a, const void *b)
    295{
    296    return strcmp(*(const char **) a, *(const char **) b);
    297}
    298
    299static void readline_completion(ReadLineState *rs)
    300{
    301    int len, i, j, max_width, nb_cols, max_prefix;
    302    char *cmdline;
    303
    304    rs->nb_completions = 0;
    305
    306    cmdline = g_strndup(rs->cmd_buf, rs->cmd_buf_index);
    307    rs->completion_finder(rs->opaque, cmdline);
    308    g_free(cmdline);
    309
    310    /* no completion found */
    311    if (rs->nb_completions <= 0) {
    312        return;
    313    }
    314    if (rs->nb_completions == 1) {
    315        len = strlen(rs->completions[0]);
    316        for (i = rs->completion_index; i < len; i++) {
    317            readline_insert_char(rs, rs->completions[0][i]);
    318        }
    319        /* extra space for next argument. XXX: make it more generic */
    320        if (len > 0 && rs->completions[0][len - 1] != '/') {
    321            readline_insert_char(rs, ' ');
    322        }
    323    } else {
    324        qsort(rs->completions, rs->nb_completions, sizeof(char *),
    325              completion_comp);
    326        rs->printf_func(rs->opaque, "\n");
    327        max_width = 0;
    328        max_prefix = 0;
    329        for (i = 0; i < rs->nb_completions; i++) {
    330            len = strlen(rs->completions[i]);
    331            if (i == 0) {
    332                max_prefix = len;
    333            } else {
    334                if (len < max_prefix) {
    335                    max_prefix = len;
    336                }
    337                for (j = 0; j < max_prefix; j++) {
    338                    if (rs->completions[i][j] != rs->completions[0][j]) {
    339                        max_prefix = j;
    340                    }
    341                }
    342            }
    343            if (len > max_width) {
    344                max_width = len;
    345            }
    346        }
    347        if (max_prefix > 0)
    348            for (i = rs->completion_index; i < max_prefix; i++) {
    349                readline_insert_char(rs, rs->completions[0][i]);
    350            }
    351        max_width += 2;
    352        if (max_width < 10) {
    353            max_width = 10;
    354        } else if (max_width > 80) {
    355            max_width = 80;
    356        }
    357        nb_cols = 80 / max_width;
    358        j = 0;
    359        for (i = 0; i < rs->nb_completions; i++) {
    360            rs->printf_func(rs->opaque, "%-*s", max_width, rs->completions[i]);
    361            if (++j == nb_cols || i == (rs->nb_completions - 1)) {
    362                rs->printf_func(rs->opaque, "\n");
    363                j = 0;
    364            }
    365        }
    366        readline_show_prompt(rs);
    367    }
    368    for (i = 0; i < rs->nb_completions; i++) {
    369        g_free(rs->completions[i]);
    370    }
    371}
    372
    373static void readline_clear_screen(ReadLineState *rs)
    374{
    375    rs->printf_func(rs->opaque, "\033[2J\033[1;1H");
    376    readline_show_prompt(rs);
    377}
    378
    379/* return true if command handled */
    380void readline_handle_byte(ReadLineState *rs, int ch)
    381{
    382    switch (rs->esc_state) {
    383    case IS_NORM:
    384        switch (ch) {
    385        case 1:
    386            readline_bol(rs);
    387            break;
    388        case 4:
    389            readline_delete_char(rs);
    390            break;
    391        case 5:
    392            readline_eol(rs);
    393            break;
    394        case 9:
    395            readline_completion(rs);
    396            break;
    397        case 12:
    398            readline_clear_screen(rs);
    399            break;
    400        case 10:
    401        case 13:
    402            rs->cmd_buf[rs->cmd_buf_size] = '\0';
    403            if (!rs->read_password) {
    404                readline_hist_add(rs, rs->cmd_buf);
    405            }
    406            rs->printf_func(rs->opaque, "\n");
    407            rs->cmd_buf_index = 0;
    408            rs->cmd_buf_size = 0;
    409            rs->last_cmd_buf_index = 0;
    410            rs->last_cmd_buf_size = 0;
    411            rs->readline_func(rs->opaque, rs->cmd_buf, rs->readline_opaque);
    412            break;
    413        case 23:
    414            /* ^W */
    415            readline_backword(rs);
    416            break;
    417        case 27:
    418            rs->esc_state = IS_ESC;
    419            break;
    420        case 127:
    421        case 8:
    422            readline_backspace(rs);
    423            break;
    424        case 155:
    425            rs->esc_state = IS_CSI;
    426            break;
    427        default:
    428            if (ch >= 32) {
    429                readline_insert_char(rs, ch);
    430            }
    431            break;
    432        }
    433        break;
    434    case IS_ESC:
    435        if (ch == '[') {
    436            rs->esc_state = IS_CSI;
    437            rs->esc_param = 0;
    438        } else if (ch == 'O') {
    439            rs->esc_state = IS_SS3;
    440            rs->esc_param = 0;
    441        } else {
    442            rs->esc_state = IS_NORM;
    443        }
    444        break;
    445    case IS_CSI:
    446        switch (ch) {
    447        case 'A':
    448        case 'F':
    449            readline_up_char(rs);
    450            break;
    451        case 'B':
    452        case 'E':
    453            readline_down_char(rs);
    454            break;
    455        case 'D':
    456            readline_backward_char(rs);
    457            break;
    458        case 'C':
    459            readline_forward_char(rs);
    460            break;
    461        case '0' ... '9':
    462            rs->esc_param = rs->esc_param * 10 + (ch - '0');
    463            goto the_end;
    464        case '~':
    465            switch (rs->esc_param) {
    466            case 1:
    467                readline_bol(rs);
    468                break;
    469            case 3:
    470                readline_delete_char(rs);
    471                break;
    472            case 4:
    473                readline_eol(rs);
    474                break;
    475            }
    476            break;
    477        default:
    478            break;
    479        }
    480        rs->esc_state = IS_NORM;
    481    the_end:
    482        break;
    483    case IS_SS3:
    484        switch (ch) {
    485        case 'F':
    486            readline_eol(rs);
    487            break;
    488        case 'H':
    489            readline_bol(rs);
    490            break;
    491        }
    492        rs->esc_state = IS_NORM;
    493        break;
    494    }
    495    readline_update(rs);
    496}
    497
    498void readline_start(ReadLineState *rs, const char *prompt, int read_password,
    499                    ReadLineFunc *readline_func, void *opaque)
    500{
    501    pstrcpy(rs->prompt, sizeof(rs->prompt), prompt);
    502    rs->readline_func = readline_func;
    503    rs->readline_opaque = opaque;
    504    rs->read_password = read_password;
    505    readline_restart(rs);
    506}
    507
    508void readline_restart(ReadLineState *rs)
    509{
    510    rs->cmd_buf_index = 0;
    511    rs->cmd_buf_size = 0;
    512}
    513
    514const char *readline_get_history(ReadLineState *rs, unsigned int index)
    515{
    516    if (index >= READLINE_MAX_CMDS) {
    517        return NULL;
    518    }
    519    return rs->history[index];
    520}
    521
    522void readline_free(ReadLineState *rs)
    523{
    524    int i;
    525
    526    if (!rs) {
    527        return;
    528    }
    529    for (i = 0; i < READLINE_MAX_CMDS; i++) {
    530        g_free(rs->history[i]);
    531    }
    532    g_free(rs);
    533}
    534
    535ReadLineState *readline_init(ReadLinePrintfFunc *printf_func,
    536                             ReadLineFlushFunc *flush_func,
    537                             void *opaque,
    538                             ReadLineCompletionFunc *completion_finder)
    539{
    540    ReadLineState *rs = g_new0(ReadLineState, 1);
    541
    542    rs->hist_entry = -1;
    543    rs->opaque = opaque;
    544    rs->printf_func = printf_func;
    545    rs->flush_func = flush_func;
    546    rs->completion_finder = completion_finder;
    547
    548    return rs;
    549}