Trace MinGW-W64 Addresses Back to Source with addr2line
You will turn an address from a MinGW-W64 crash report into a source file and line number, or establish that the executable does not contain enough debugging information. The same workflow also accepts symbol plus offset, reads addresses from standard input, and can show demangled function names.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes for a first investigation. You need the exact executable or relocatable object that produced the address, a shell, and the binutils-mingw-w64-x86-64 package. No elevated privileges are normally needed: addr2line only reads the object and writes to standard output.
This guide uses GNU Binutils 2.41.90.20240122, installed here as package version 2.41.90.20240122-1ubuntu1+11.4. The x86_64-w64-mingw32ucrt-addr2line alias has the same installed manual page and purpose.
1. Check the installed command
Confirm the binary and its version before interpreting output. These are ordinary, read-only commands:
$ command -v x86_64-w64-mingw32-addr2line
/usr/bin/x86_64-w64-mingw32-addr2line
$ x86_64-w64-mingw32-addr2line --version
GNU addr2line (GNU Binutils) 2.41.90.20240122
$ x86_64-w64-mingw32-addr2line --help
Usage: x86_64-w64-mingw32-addr2line [option(s)] [addr(s)]
Checkpoint: keep the command name and version beside the crash report. If the report came from a different toolchain or build, matching the executable matters more than matching the utility version.
2. Resolve one address against the executable
Pass the executable with -e, then give a hexadecimal address. Use the address exactly as reported by the debugger, apart from any notation that the tool does not accept:
$ x86_64-w64-mingw32-addr2line -e /path/to/program.exe 0x401234
src/worker.c:87
The normal output shape is FILENAME:LINENO. The example location is representative, not a promised result. Your executable must contain matching debugging information for a useful path and line.
If you omit -e, the installed command looks for a.out. That default is easy to miss when a command is copied from a generic Unix example, so specify the executable in scripts and incident notes.
Checkpoint: on an object without a matching location, the installed command reports question marks and line zero:
$ x86_64-w64-mingw32-addr2line -e /usr/bin/x86_64-w64-mingw32-addr2line 0x0
??:0
This result is not a source location. It usually means the address is wrong for that file, the symbols or debug data are absent, or the address needs to be interpreted relative to a loaded image rather than used as a file address.
3. Add the function name and keep output on one line
For crash logs, function names make a result easier to scan. Use -f for the containing function and -C to demangle C++ names. Add -p when another program will consume one location per line:
$ x86_64-w64-mingw32-addr2line -f -C -p -e /path/to/program.exe 0x401234
process_item at src/worker.c:87
With an unknown location, the installed formatting is still predictable:
$ x86_64-w64-mingw32-addr2line -f -C -p -e /usr/bin/x86_64-w64-mingw32-addr2line 0x0
?? ??:0
Do not treat a readable function name as proof that the line number is trustworthy. Check that the executable and build correspond to the crash, and that the reported address has been adjusted correctly for the loader's relocation.
4. Process addresses from a pipe
With no addresses on the command line, addr2line reads hexadecimal addresses or symbol plus offset from standard input. This is useful for a debugger export or a list of return addresses:
$ printf '%s\n' '0x401234' '0x4012a0' |
> x86_64-w64-mingw32-addr2line -f -C -p -e /path/to/program.exe
process_item at src/worker.c:87
flush_queue at src/queue.c:142
Each input address produces output in the same order. Add -a when you need the original address echoed before the decoded location:
$ printf '%s\n' '0x0' | x86_64-w64-mingw32-addr2line -a -f -C -p -e /usr/bin/x86_64-w64-mingw32-addr2line
0x0000000000000000: ?? ??:0
Keep the pipe input controlled. This command treats each line as data, but shell expansions that build the input can still execute before addr2line starts.
5. Account for sections and inlined calls
Addresses in a relocatable object may be offsets within a section rather than absolute addresses. Supply the section name with -j:
$ x86_64-w64-mingw32-addr2line -j .text -e /path/to/object.o 0x120
src/worker.c:87
Use -i when compiler inlining may hide the call chain. It prints the location for the containing inline scopes after the main location. Combine it with -f if you need each function name. Without suitable inline debug data, there may be no extra lines.
Use -s to strip directory names when a report must be portable between build machines. That makes output shorter, but removes context that may be needed to identify the correct source tree.
6. Handle missing data without damaging the evidence
Do not overwrite the executable or its separate debug file while investigating. The address-to-line result depends on the exact build. Copy the files to a working directory if you need to experiment, and record their checksums before analysis:
$ sha256sum /path/to/program.exe
$ x86_64-w64-mingw32-addr2line -e /path/to/program.exe -f -C -p 0x401234
If every address gives ??:0, first verify the path and format, then check whether the executable was stripped or built without debug information. The command can identify supported object formats with --help; this installed build lists PE, PEI, ELF and several other targets. Use -b only when automatic format detection is unsuitable, and pass the BFD target name that matches the file.
Do not add -r casually. Demangling has a recursion limit enabled by default to reduce the risk of stack exhaustion from hostile or unusually complex names. -r disables that limit; -R explicitly enables it. These options matter only with -C.
Done means
- The utility version and the exact executable were recorded.
- Addresses were interpreted in the correct address or section context.
-f -C -pproduced readable function-aware output where the data allowed it.- Unknown results such as
??:0were treated as missing or mismatched evidence, not as source locations. - The executable and debug evidence remain unchanged and can be rechecked from their recorded checksums.