]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tools: add dump-auxv.py
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 24 Mar 2023 13:54:34 +0000 (14:54 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 24 Mar 2023 18:49:34 +0000 (18:49 +0000)
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 [new file with mode: 0644]

diff --git a/tools/dump-auxv.py b/tools/dump-auxv.py
new file mode 100644 (file)
index 0000000..36f3b37
--- /dev/null
@@ -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()