From 85a336f81d9cb3b6e75e03031a8ab5d4eb682e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 24 Mar 2023 14:54:34 +0100 Subject: tools: add dump-auxv.py This is a little helper I used when preparing the tests for auxv parsing. Just looking at hexdump output is pretty hard. We could enhance it to display some specific data types better. --- tools/dump-auxv.py | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 tools/dump-auxv.py (limited to 'tools') diff --git a/tools/dump-auxv.py b/tools/dump-auxv.py new file mode 100644 index 0000000000..36f3b37bf4 --- /dev/null +++ b/tools/dump-auxv.py @@ -0,0 +1,137 @@ +#!/usr/bin/python +# SPDX-License-Identifier: LGPL-2.1-or-later + +""" +A program to parse auxv (e.g. /proc/self/auxv). + +By default, current arch is assumed, but options can be used to override the +endianness and word size. +""" + +import struct + +import click + +# From /usr/include/elf.h +AT_AUXV = { + 'AT_NULL' : 0, # End of vector + 'AT_IGNORE' : 1, # Entry should be ignored + 'AT_EXECFD' : 2, # File descriptor of program + 'AT_PHDR' : 3, # Program headers for program + 'AT_PHENT' : 4, # Size of program header entry + 'AT_PHNUM' : 5, # Number of program headers + 'AT_PAGESZ' : 6, # System page size + 'AT_BASE' : 7, # Base address of interpreter + 'AT_FLAGS' : 8, # Flags + 'AT_ENTRY' : 9, # Entry point of program + 'AT_NOTELF' : 10, # Program is not ELF + 'AT_UID' : 11, # Real uid + 'AT_EUID' : 12, # Effective uid + 'AT_GID' : 13, # Real gid + 'AT_EGID' : 14, # Effective gid + 'AT_CLKTCK' : 17, # Frequency of times() + + # Some more special a_type values describing the hardware. + 'AT_PLATFORM' : 15, # String identifying platform. + 'AT_HWCAP' : 16, # Machine-dependent hints about processor capabilities. + + # This entry gives some information about the FPU initialization performed by the kernel. + 'AT_FPUCW' : 18, # Used FPU control word. + + # Cache block sizes. + 'AT_DCACHEBSIZE' : 19, # Data cache block size. + 'AT_ICACHEBSIZE' : 20, # Instruction cache block size. + 'AT_UCACHEBSIZE' : 21, # Unified cache block size. + + # A special ignored value for PPC, used by the kernel to control the + # interpretation of the AUXV. Must be > 16. + 'AT_IGNOREPPC' : 22, # Entry should be ignored. + + 'AT_SECURE' : 23, # Boolean, was exec setuid-like? + + 'AT_BASE_PLATFORM' : 24, # String identifying real platforms. + + 'AT_RANDOM' : 25, # Address of 16 random bytes. + + 'AT_HWCAP2' : 26, # More machine-dependent hints about processor capabilities. + + 'AT_EXECFN' : 31, # Filename of executable. + + # Pointer to the global system page used for system calls and other nice things. + 'AT_SYSINFO' : 32, + 'AT_SYSINFO_EHDR' : 33, + + # Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains + # log2 of line size; mask those to get cache size. + 'AT_L1I_CACHESHAPE' : 34, + 'AT_L1D_CACHESHAPE' : 35, + 'AT_L2_CACHESHAPE' : 36, + 'AT_L3_CACHESHAPE' : 37, + + # Shapes of the caches, with more room to describe them. + # GEOMETRY are comprised of cache line size in bytes in the bottom 16 bits + # and the cache associativity in the next 16 bits. + 'AT_L1I_CACHESIZE' : 40, + 'AT_L1I_CACHEGEOMETRY' : 41, + 'AT_L1D_CACHESIZE' : 42, + 'AT_L1D_CACHEGEOMETRY' : 43, + 'AT_L2_CACHESIZE' : 44, + 'AT_L2_CACHEGEOMETRY' : 45, + 'AT_L3_CACHESIZE' : 46, + 'AT_L3_CACHEGEOMETRY' : 47, + + 'AT_MINSIGSTKSZ' : 51, # Stack needed for signal delivery +} +AT_AUXV_NAMES = {v:k for k,v in AT_AUXV.items()} + +@click.command(help=__doc__) +@click.option('-b', '--big-endian', 'endian', + flag_value='>', + help='Input is big-endian') +@click.option('-l', '--little-endian', 'endian', + flag_value='<', + help='Input is little-endian') +@click.option('-3', '--32', 'field_width', + flag_value=32, + help='Input is 32-bit') +@click.option('-6', '--64', 'field_width', + flag_value=64, + help='Input is 64-bit') +@click.argument('file', + type=click.File(mode='rb')) +def dump(endian, field_width, file): + data = file.read() + + if field_width is None: + field_width = struct.calcsize('P') * 8 + if endian is None: + endian = '@' + + width = {32:'II', 64:'QQ'}[field_width] + + format = f'{endian}{width}' + print(f'# {format=}') + + seen_null = False + + for item in struct.iter_unpack(format, data): + key, val = item + name = AT_AUXV_NAMES.get(key, f'unknown ({key})') + if name.endswith(('UID', 'GID')): + pref, fmt = '', 'd' + else: + pref, fmt = '0x', 'x' + + if seen_null: + print('# trailing garbarbage after AT_NULL') + + print(f'{name:18} = {pref}{val:{fmt}}') + + if name == 'AT_NULL': + seen_null = True + + if not seen_null: + print('# array not terminated with AT_NULL') + +if __name__ == '__main__': + dump() -- cgit v1.2.1