READELF(1)

πŸ“¦ version 2.45, in ubuntu questing

✨ NAME ✨

readelf(1) from the GNU Development Tools crew πŸ’–

readelf - display information about ELF files 🧚

✨ SYNOPSIS ✨

readelf [-a|--all]
        [-h|--file-header]
        [-l|--program-headers|--segments]
        [-S|--section-headers|--sections]
        [-g|--section-groups]
        [-t|--section-details]
        [-e|--headers]
        [-s|--syms|--symbols]
        [--dyn-syms|--lto-syms]
        [--sym-base=[0|8|10|16]]
        [--demangle=style|--no-demangle]
        [--quiet]
        [--recurse-limit|--no-recurse-limit]
        [-U method|--unicode=method]
        [-X|--extra-sym-info|--no-extra-sym-info]
        [-n|--notes]
        [-r|--relocs]
        [-u|--unwind]
        [-d|--dynamic]
        [-V|--version-info]
        [-A|--arch-specific]
        [-D|--use-dynamic]
        [-L|--lint|--enable-checks]
        [-x <number or name>|--hex-dump=<number or name>]
        [-p <number or name>|--string-dump=<number or name>]
        [-R <number or name>|--relocated-dump=<number or name>]
        [-j <number or name>|--display-section=<number or name>]
        [-z|--decompress]
        [-c|--archive-index]
        [-w[lLiaprmfFsoORtUuTgAck]|
         --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=str-offsets,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index,=addr,=cu_index,=links]]
        [-wK|--debug-dump=follow-links]
        [-wN|--debug-dump=no-follow-links]
        [-wD|--debug-dump=use-debuginfod]
        [-wE|--debug-dump=do-not-use-debuginfod]
        [-P|--process-links]
        [--dwarf-depth=n]
        [--dwarf-start=n]
        [--ctf=section]
        [--ctf-parent=section]
        [--ctf-symbols=section]
        [--ctf-strings=section]
        [--sframe=section]
        [-I|--histogram]
        [-v|--version]
        [-W|--wide]
        [-T|--silent-truncation]
        [-H|--help]
        elffile...

✨ DESCRIPTION ✨

okay so readelf is the queen of looking inside ELF format object files πŸ‘‘ You can point it at one or more of them and it spills all the tea about what's inside. The options decide exactly which info you get to see πŸ’…

elffile... are the object files you want it to check out. It's totally fine with both 32-bit and 64-bit ELF files, and it'll even dig into archives full of ELF files πŸ¦‹

Lowkey, this program does a similar job to objdump, but it goes way deeper into the details πŸ”₯ It also exists completely on its own, apart from the BFD library. So if there's a bug in BFD, readelf is unbothered and won't be affected πŸ’œ

✨ OPTIONS ✨

The long and short versions of each option are basically twins, so they do the exact same thing 🫢 You need to give at least one option besides -v or -H, or it's gonna be a no-show πŸ’€

  • -a, --all β€” This is the everything bagel πŸ₯― It's the same as turning on --file-header, --program-headers, --sections, --symbols, --relocs, --dynamic, --notes, --version-info, --arch-specific, --unwind, --section-groups and --histogram all at once ✨
Heads up bestie: -a does NOT turn on --use-dynamic by itself πŸ™ˆ So unless you also add that option, the dynamic symbols and dynamic relocs won't show up.
  • -h, --file-header β€” Shows you the info stored in the ELF header sitting at the very start of the file πŸŽ€
  • -l, --program-headers, --segments β€” Displays the info from the file's segment headers, but only if the file actually has some 🌸
  • --quiet β€” Shuts up the "no symbols" diagnostic message 🀫
  • -S, --sections, --section-headers β€” Shows the info from the file's section headers, if it's got any πŸ“
  • -g, --section-groups β€” Shows the info from the file's section groups, if there are any to find 🧚
  • -t, --section-details β€” Gives you the detailed section info πŸ’– This one also means -S is on, so you get that too ✨
  • -s, --symbols, --syms β€” Lists out the entries in the symbol table section, if the file has one πŸ”₯ If a symbol has version info attached, that gets shown too. The version string pops up as a suffix on the symbol name, with an @ in front of it. For example foo@VER_1. And if that version is the default one used when resolving unversioned references to the symbol, it gets a suffix with two @ characters instead. For example foo@@VER_2 πŸ‘‘
  • --dyn-syms β€” Lists the entries in the dynamic symbol table section, if the file has one 🌈 The output looks the same as what --syms gives you πŸ’…
  • --lto-syms β€” Shows the contents of any LTO symbol tables hiding in the file πŸ¦‹
  • --sym-base=[0|8|10|16] β€” Forces the size field of the symbol table to use the base you pick ✨ Any unrecognised value gets treated as 0. --sym-base=0 is the default and legacy behaviour: sizes show up as decimal for numbers under 100000, and anything 100000 or bigger switches to hexadecimal with a 0x prefix. --sym-base=8 gives you the symbol sizes in octal πŸ“ --sym-base=10 always uses decimal πŸ’œ And --sym-base=16 always uses hexadecimal with a 0x prefix πŸ”₯
  • -C, --demangle[=style] β€” This decodes (demangles) the low-level symbol names into names that actual humans can read πŸͺ„ C++ function names become readable, and it's iconic. Different compilers use different mangling styles, so the optional style argument lets you pick the one that matches your compiler πŸ’…
  • --no-demangle β€” Leaves the low-level symbol names alone, no demangling πŸ™ˆ This is the default vibe.
  • --recurse-limit, --no-recurse-limit, --recursion-limit, --no-recursion-limit β€” Turns a limit on demangling recursion on or off 🌸 The name mangling formats technically allow infinite recursion, so you can make strings that eat up all the stack space on the host machine and cause a memory fault πŸ’€ The limit stops that by capping recursion at 2048 levels of nesting. The limit is on by default, but you might need to turn it off to demangle truly complicated names. Heads up though: if you disable it, stack exhaustion is possible, and any bug reports about that kind of crash will get rejected 😭
  • -U [d|i|l|e|x|h], --unicode=[default|invalid|locale|escape|hex|highlight] β€” Controls how non-ASCII characters show up in identifier names 🌈 The default (--unicode=locale or --unicode=default) treats them as multibyte characters and shows them in your current locale. Every other version treats the bytes as UTF-8 encoded values and tries to interpret them. If they can't be interpreted, or if you use --unicode=invalid, they show up as a sequence of hex bytes wrapped in curly parenthesis characters πŸŽ€ --unicode=escape shows the characters as unicode escape sequences, like \uxxxx ✨ --unicode=hex shows them as hex byte sequences wrapped in angle brackets 🧚 --unicode=highlight shows the characters as unicode escape sequences too, but it also colours them red, as long as your output device supports colour πŸ”₯ The colour is there to grab your attention when unicode sequences pop up somewhere you weren't expecting them πŸ‘€
  • -X, --extra-sym-info β€” When you're looking at symbol details, this adds extra info that doesn't normally show up πŸ’– Right now it just adds the name of the section referenced by the symbol's index field, if there is one. More info might get added to this in the future πŸ¦‹ Turning this on also turns on --wide as a side effect, at least when you're displaying symbol info πŸ’…
  • --no-extra-sym-info β€” Undoes --extra-sym-info. This is the default πŸ™ˆ
  • -e, --headers β€” Displays all the headers in the file. It's the same as doing -h -l -S 🫢
  • -n, --notes β€” Shows the contents of the NOTE segments and/or sections, if there are any ✨
  • -r, --relocs β€” Shows the contents of the file's relocation section, if it has one 🌈
  • -u, --unwind β€” Shows the contents of the file's unwind section, if it has one πŸ”₯ Right now only the unwind sections for IA64 ELF files are supported, plus ARM unwind tables (.ARM.exidx / .ARM.extab). If your architecture isn't supported yet, you could try dumping the .eh_frames section with the --debug-dump=frames or --debug-dump=frames-interp options instead πŸ’œ
  • -d, --dynamic β€” Shows the contents of the file's dynamic section, if it has one 🧚
  • -V, --version-info β€” Shows the contents of the version sections in the file, if they exist πŸ“
  • -A, --arch-specific β€” Shows any architecture-specific info in the file, if there's any 🌸
  • -D, --use-dynamic β€” When you're displaying symbols, this makes readelf use the symbol hash tables in the file's dynamic section, instead of the symbol table sections πŸ‘‘ When you're displaying relocations, this makes readelf show the dynamic relocations instead of the static ones πŸ’–
  • -L, --lint, --enable-checks β€” Shows warning messages about possible problems with the file(s) you're examining 🫢 On its own, it checks all of the contents of the file(s). If you pair it with one of the dumping options, the warnings only show up for the stuff being displayed πŸ”
  • -x <number or name>, --hex-dump=<number or name> β€” Shows the contents of the section you specify as hexadecimal bytes πŸŽ€ A number picks out one particular section by its index in the section table. Any other string picks out every section with that name in the object file πŸ“ You can repeat this option on the command line to ask for multiple hex dumps 🌸
  • -R <number or name>, --relocated-dump=<number or name> β€” Same vibe as the hex dump, shows the contents of the section you pick as hexadecimal bytes ✨ A number picks a section by index, and any other string picks every section with that name πŸ¦‹ The big difference is that the section's contents get relocated before they're displayed πŸ”₯ You can also repeat this one on the command line to get multiple relocated dumps πŸ’…
  • -p <number or name>, --string-dump=<number or name> β€” 🧡 Dumps the contents of the section you point at as printable strings. A number picks out a section by its index in the section table, and any other word grabs every section with that name in the object file. You can repeat this one as many times as you want on the command line to request multiple string dumps.
  • -j <number or name>, --display-section β€” ✨ Shows the section's contents based on its section header type, so it's smart about what it's looking at. Relocation sections display as if you'd used --relocations, and symbol sections display as if you'd used --syms, and so on. A number selects a section by index in the section table, and any other word selects all sections with that name in the input file(s). You can repeat it for multiple section dumps too πŸ’…
  • -z, --decompress β€” πŸ—œοΈ Tells readelf to decompress the section(s) you're dumping with the x, R or p options before showing them. If the section isn't compressed to begin with, no drama, it just shows up as is.
  • -c, --archive-index β€” πŸ“š Shows the file symbol index info stored in the header part of binary archives. It does the same job as the t command to ar, but it does it without using the BFD library, which is lowkey iconic.
  • -w[lLiaprmfFsOoRtUuTgAckK], --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=str-offsets,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index,=addr,=cu_index,=links,=follow-links] β€” πŸ” Dumps the DWARF debug sections in the file, if there are any. Compressed debug sections get decompressed automatically (temporarily) before they're shown. If you add one or more of the letters or words after the switch, you only get those types of data. Here's what each one means:
    • "a" / "=abbrev" β€” shows the .debug_abbrev section.
    • "A" / "=addr" β€” shows the .debug_addr section.
    • "c" / "=cu_index" β€” shows the .debug_cu_index and/or .debug_tu_index sections.
    • "f" / "=frames" β€” shows the raw contents of a .debug_frame section.
    • "F" / "=frames-interp" β€” shows the interpreted contents of a .debug_frame section.
    • "g" / "=gdb_index" β€” shows the .gdb_index and/or .debug_names sections.
    • "i" / "=info" β€” shows the .debug_info section. Heads up: you can also narrow this output with --dwarf-depth and --dwarf-start.
    • "k" / "=links" β€” shows the .gnu_debuglink, .gnu_debugaltlink and .debug_sup sections, if any are present. It also shows any links to separate dwarf object files (dwo), if they're specified by the DW_AT_GNU_dwo_name or DW_AT_dwo_name attributes in the .debug_info section.
    • "K" / "=follow-links" β€” shows the contents of any selected debug sections that live in linked, separate debug info file(s). This can mean the same debug section shows up more than once if it exists in more than one file. Also, when you're showing DWARF attributes and there's a form that references the separate debug info file, the referenced contents get shown too.
Note: in some distributions this option is on by default. You can turn it off with the N debug option. The default can be chosen when configuring binutils with --enable-follow-debug-links=yes or --enable-follow-debug-links=no. If neither is used, following debug links is enabled by default.
Note: if debuginfod protocol support was enabled when binutils was built, this option will also try to contact any debuginfod servers listed in the DEBUGINFOD_URLS environment variable. That could take some time to resolve. You can switch this behaviour off with the =do-not-use-debuginfod debug option.
  • "N" / "=no-follow-links" β€” turns off following links to separate debug info files.
  • "D" / "=use-debuginfod" β€” lets readelf contact debuginfod servers when it needs to follow debug links. This is the default behaviour.
  • "E" / "=do-not-use-debuginfod" β€” stops readelf from contacting debuginfod servers when it needs to follow debug links.
  • "l" / "=rawline" β€” shows the .debug_line section in a raw format.
  • "L" / "=decodedline" β€” shows the interpreted contents of the .debug_line section.
  • "m" / "=macro" β€” shows the .debug_macro and/or .debug_macinfo sections.
  • "o" / "=loc" β€” shows the .debug_loc and/or .debug_loclists sections.
  • "O" / "=str-offsets" β€” shows the .debug_str_offsets section.
  • "p" / "=pubnames" β€” shows the .debug_pubnames and/or .debug_gnu_pubnames sections.
  • "r" / "=aranges" β€” shows the .debug_aranges section.
  • "R" / "=Ranges" β€” shows the .debug_ranges and/or .debug_rnglists sections.
  • "s" / "=str" β€” shows the .debug_str, .debug_line_str and/or .debug_str_offsets sections.
  • "t" / "=pubtype" β€” shows the .debug_pubtypes and/or .debug_gnu_pubtypes sections.
  • "T" / "=trace_aranges" β€” shows the .trace_aranges section.
  • "u" / "=trace_abbrev" β€” shows the .trace_abbrev section.
  • "U" / "=trace_info" β€” shows the .trace_info section.
Note: showing .debug_static_funcs, .debug_static_vars and debug_weaknames sections is not currently supported. Sorry bestie πŸ₯Ί
  • --dwarf-depth=n β€” 🌳 Limits the dump of the ".debug_info" section to n children. This only matters with --debug-dump=info. By default readelf prints all DIEs, and the special value 0 for n does the same thing. With a non-zero n, DIEs at or deeper than n levels won't get printed. The range for n is zero-based.
  • --dwarf-start=n β€” 🎯 Prints only the DIEs starting from the DIE numbered n. This only matters with --debug-dump=info. When you use it, readelf skips printing any header info and all DIEs before DIE n, so you only get the siblings and children of that specific DIE. It can be combined with --dwarf-depth for extra control 🫢
  • -P, --process-links β€” πŸ”— Displays the contents of non-debug sections found in separate debuginfo files that are linked to the main file. This option automatically implies the -wK option, and only the sections requested by your other command line options will get displayed.
  • --ctf[=section] β€” 🧠 Displays the contents of the specified CTF section. CTF sections are packed with lots of subsections, and all of them get displayed in order. By default, it shows the section named .ctf, which is the name ld emits.
  • --ctf-parent=member β€” πŸ‘¨β€πŸ‘§ If a CTF section has ambiguously-defined types, it's an archive of many CTF dictionaries, all inheriting from one dictionary holding the unambiguous types. By default that parent member is named .ctf, just like the section containing it. You can change that name using the "ctf_link_set_memb_name_changer" function at link time. So when you're looking at CTF archives made by a linker that renamed the parent archive member, use --ctf-parent to specify the name it used for the parent.
  • --ctf-parent-section=section β€” πŸͺ„ Lets you pick a totally different section for the CTF parent dictionary (the one with the unambiguous types) than the section used for the child dictionaries (the ones with the ambiguous leftovers). The linker doesn't emit ELF objects structured like this, but some third-party linkers might. It's also handy for inspecting CTF that was written out as multiple raw files you want to combine with objcopy, since those can land in different ELF sections but not in different members of a single CTF dict.
  • --ctf-symbols=section, --ctf-strings=section β€” 🧡 Specifies the name of another section that the CTF file can inherit strings and symbols from. By default, the ".symtab" and its linked string table are used. If you specify either --ctf-symbols or --ctf-strings, you have to specify the other one too. No going solo on this one!
  • -I, --histogram β€” πŸ“Š Displays a histogram of bucket list lengths whenever you're showing the contents of the symbol tables. Very data-nerd, very cute.
  • -v, --version β€” 🏷️ Displays the version number of readelf.
  • -W, --wide β€” πŸ–₯️ Stops breaking output lines to fit into 80 columns. By default, readelf breaks section header and segment listing lines for 64-bit ELF files so they fit into 80 columns. This option makes readelf print each section header (or each segment) on a single line, which is way more readable on terminals wider than 80 columns.
  • -T, --silent-truncation β€” βœ‚οΈ Normally, when readelf is showing a symbol name and has to chop it to fit into an 80 column display, it adds a "[...]" suffix to the name. This option turns that off, which gives you 5 more characters of the name to see and restores the old readelf behaviour (from before release 2.35). Bye bye, drama 😭
  • -H, --help β€” πŸ†˜ Displays the command-line options readelf understands. When you're lost, this is your bestie.
  • @file β€” πŸ“„ Reads command-line options from file. The options read get inserted in place of the original @file option. If file doesn't exist or can't be read, the option is treated literally and doesn't get removed. Literally a copy-paste-into-a-file hack πŸ’–

Okay so the last bit of the @file thing is lowkey the sneakiest part bestie 🫣

Options inside that file get split up by whitespace, like how your bestie splits a group order πŸ“ But if you want a single option to include a space, wrap the whole thing in either single or double quotes, and it stays together ✨ Want a literal backslash or any other character in there? Just put a backslash in front of it πŸ’… And here's the plot twist: the file can have its own @file options too πŸŒ€ Those get processed recursively, so it's a whole nested situation and the file keeps going until it's done 🧚

πŸ¦‹ SEE ALSO πŸ¦‹

  • objdump(1), and the Info entries for binutils πŸ“š

Copyright (c) 1991-2025 Free Software Foundation, Inc. 🌈

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation πŸŽ€ There are no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts, so nothing extra to worry about πŸ’– A copy of the license is included in the section entitled "GNU Free Documentation License" πŸ“œ


Okay bestie, that's the whole tea β˜•οΈ We made it through every single READELF(1) detail together 🫢 Go be iconic with your ELF files, you absolutely slay this πŸ‘‘βœ¨πŸ’…

πŸ“¦ where this page comes from