6

I currently work on some binary data. In order to check and debug the data previously generated by my application I use hexdump, facing the obstacle of hexdump not appearing to be able to extract a 64-bit integer field. Given the following minimal example:

#include <iostream>
#include <fstream>
#include <cstdint>

int main(int argc, char** argv){
    std::ofstream os("tmp.bin", std::ios::out | std::ios::binary);
    uint64_t x = 7;
    os.write((char*)&x,sizeof(uint64_t));
    os.close();
    return 0;
}

I perform a simple hexdump on my system:

hexdump tmp.bin

> 0000000: 0007 0000 0000 0000
> 0000008:

Now trying to extract the unsigned int of 64 bit width yields:

hexdump -e '/8 "%u"' tmp.bin

> hexdump: bad byte count for conversion character u

According to the well written hexdump-manual by David Mair it should be possible to do it, but I have no success.

What am I missing ?

Lars Hadidi
  • 558
  • 1
  • 5
  • 15
  • Unfortunately not as this only modifies the indentation width of the output. – Lars Hadidi Jun 26 '15 at 20:40
  • In the manpages it says only 4bytes are supported most for x and u. Anyway after a little bashing i found this workaround: hexdump -e '2/4 "%08X" "\n"' FILE | awk '{system("echo \"ibase=16; "$1"\"|bc")}' It basically prints two 4 byte hex pairs and then converts this to decimal with bc. I don't know if the order of the 2 hex pairs may need to swap for the correct value, but you could give it a try. – fassl Jun 27 '15 at 01:00
  • All right, I just tried it out. The values had to be swapped indeed. This is how it works: hexdump -e '2/4 "%08X " "\n"' HEX | awk 'BEGIN{printf "ibase=16; "}{print $2 $1}' | bc Thank you. – Lars Hadidi Jun 29 '15 at 12:34
  • Ok, now I hit signed numbers. As I don't know if they are represented using a sign bit, one's complement, two's complement, offset binary or negative base representation it will be too much for a quick dump. So our solution will only work on unsigned 64 bit integers. – Lars Hadidi Jun 29 '15 at 12:59
  • I think we can check the most significant bit and if it is set, logical and the number with the mask 0x7FFFFFFFFFFFFFFF and subtract the result from the mask we should get the signed result i think. – fassl Jun 29 '15 at 17:20
  • Well, I found a way to do it with the bash inherent calculator on the awk output. Apparently, bash's $(( )) knows how to transform it correctly. – Lars Hadidi Jun 30 '15 at 13:29
  • @fassl You may want to put the workaround as an answer: `x=\`hexdump -n 8 -e '2/4 "%08X " "\n"' $1 | awk 'BEGIN{printf "0x"}{print $2$1}'\`; echo $(($x));` – Lars Hadidi Jul 01 '15 at 14:28
  • 1
    Ultimately you came up with the answer ;) – fassl Jul 01 '15 at 15:26

4 Answers4

3

Our final workaround reads as follows:

x=`hexdump -n 8 -e '2/4 "%08X " "\n"' {FILENAME} | awk 'BEGIN{printf "0x"}{print $2$1}'`
echo $(($x))

Explaination for each part:

  • Extract the eight bytes of the 64-bit integer value from file {FILENAME} as two four byte chunks printed as hexadecimal encoded values.

    hexdump -n 8 -e '2/4 "%08X " "\n"' {FILENAME}
    
  • Reverses the byte order of the two chunks and prints it as a single eight byte chunk representing the binary value. Prepend 0x for the following processing.

    awk 'BEGIN{printf "0x"}{print $2$1}
    
  • Save the hexadecimal representation into x for bash to evaluate.

    x=`....`
    
  • Let the bourne shell interpret and output the hexadecimal encoded value of the 64-bit integer variable (here the previously prepended 0x is needed).

    echo $(($x))
    
Lars Hadidi
  • 558
  • 1
  • 5
  • 15
1

One can use sed also. The following matches 8 byte hex integers and swaps them. Again this only works for unsigned integers.

hexdump ... | sed 's/0x\([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]\)/0x\2\1/'

AFAICT one should be able to write much more clearly

hexdump ... | sed 's/0x\([0-9a-f]{8,8}\)\([0-9a-f]{8,8}\)/0x\2\1/'

typically with some command line option such as -E to enable extended regular expressions, but at least on Mac OS X 10.10 this doesn't work.

Eliot Miranda
  • 291
  • 2
  • 5
1

Try the "od" command instead. od -xL outputs long integer

BCK
  • 11
  • 1
0

I don't understand why this doesn't work out-of-the-box, but I had the same problem printing 64-bit integers and ended up compiling a better version from util-linux found here: https://github.com/karelzak/util-linux. At first I tried installing that package in Ubuntu, but it didn't update hexdump, so I decided to try doing it "manually."

It's a bit of work, but not too bad. Just use git to grab the source, run the autogen.sh script, and then ./configure followed by make hexdump to compile just that program. Compiling only took 4 seconds on my laptop.