Imprime um número assinado de byte com hexdump

3

Eu quero ler /dev/input/mice com hexdump. O formato é descrito em aqui no StackOverflow . O que eu preciso é ler um byte (flags), imprimi-lo em formato hexadecimal, depois ler dois bytes (deslocamentos de deslocamento xey) e imprimir cada um em formato decimal com sinal.

Eu uso o hexdump do util-linux 2.28 no Arch Linux.

O melhor que consegui reunir é

 hexdump /dev/input/mice -e '/1 "%03x" 2/1 " %03d" /0 "\n"'

A string de formato:

  1. /1 "%03x" lê um byte e imprime como número hexadecimal
  2. 2/1 " %03d" lê um byte e o imprime como um inteiro decimal com sinal, repete duas vezes
  3. /0 "\n" lê zero bytes e imprime fim de linha

O problema é que, para o valor 0xFF, o especificador %d imprime 255 em vez de -1. O formato é tirado de C, que estende a largura corretamente, então como forçar essa extensão de largura apropriada aqui?

    
por Adam Trhon 19.08.2016 / 13:26

1 resposta

2

Isso parece ser um bug nessa implementação de hexdump .

A função responsável é

print(struct hexdump_pr *pr, unsigned char *bp)

em hexdump-display.c . Ele copia o número correto de bytes em uma variável adequada, para que a extensão de sinal possa acontecer ao passar o valor para printf() . Mas para bytes simples, não incomoda - apenas desreferencia o ponteiro, que era para um caractere não assinado .

case F_INT:
        {
        short sval; /* int16_t */
        int ival;   /* int32_t */
        long long Lval; /* int64_t, int64_t */

        switch(pr->bcnt) {
        case 1:
            printf(pr->fmt, (unsigned long long) *bp);
            break;
        case 2:
            memmove(&sval, bp, sizeof(sval));
            printf(pr->fmt, (unsigned long long) sval);
            break;

Para corrigir, corrija a função para usar a mesma abordagem "copiar para variável local":

--- text-utils/hexdump-display.c.orig   2015-10-05 15:18:43.458759033 +0100
+++ text-utils/hexdump-display.c        2016-08-19 14:58:35.507705329 +0100
@@ -146,13 +146,15 @@
            }
        case F_INT:
            {
+               char cval;      /* int8_t */
                short sval;     /* int16_t */
                int ival;       /* int32_t */
                long long Lval; /* int64_t, int64_t */

                switch(pr->bcnt) {
                case 1:
-                       printf(pr->fmt, (unsigned long long) *bp);
+                       memmove(&cval, bp, sizeof(cval));
+                       printf(pr->fmt, (unsigned long long) cval);
                        break;
                case 2:
                        memmove(&sval, bp, sizeof(sval));
    
por 19.08.2016 / 16:28