How to Read a HLDS Core Dump with gdb

September 24, 2025 Daemon666 9 min read 194 преглеждания

When HLDS segfaults it can leave a core dump — a snapshot of the process memory at the instant it died. Loaded into gdb, that core gives you a backtrace: the exact chain of function calls that led to the crash, usually pointing straight at the module or plugin responsible. This is how you move from "the server keeps crashing on map change" to "Metamod plugin X faulted in this function." You need shell access to the box; you do not need to be a C programmer to read the result.

1. Make the server actually produce a core

By default the shell limits core dumps to zero bytes, so nothing is written. Raise the limit in the same shell that launches the server, before starting it:

ulimit -c unlimited

Confirm it took with ulimit -c (it should print unlimited). Now when HLDS crashes it writes a core or core.<pid> file into its working directory — the same folder as hlds_run. If you launch through a wrapper or systemd, the limit and the core pattern are set differently; check /proc/sys/kernel/core_pattern, which shows where the kernel sends cores (a bare core means the working directory; a piped value means a handler like systemd-coredump or apport is intercepting them).

2. Install gdb and locate the core

Install the debugger and find the dump:

sudo apt-get install gdb
ls -la core*

You should see a core file with a recent timestamp matching the crash. If there is none after a confirmed crash, the ulimit was not applied to the process that died, or a handler captured it — see the troubleshooting section.

3. Load the core against the right binary

gdb needs both the executable that crashed and the core. For GoldSrc the crashing process is the 32-bit engine launcher:

gdb ./hlds_linux core

gdb loads, prints the signal that killed it (typically Program terminated with signal SIGSEGV, Segmentation fault.), and drops you at a prompt. The binary must match the one that produced the core; loading a core against a different build gives you nonsense addresses.

4. Read the backtrace

At the gdb prompt, ask for the call stack:

bt

You get a numbered list of stack frames, most-recent first:

#0  0xf5a01b2c in ?? () from .../addons/metamod/dlls/some_plugin.so
#1  0xf5a03f10 in ?? () from .../addons/metamod/dlls/some_plugin.so
#2  0xf7c12abc in ?? () from .../cstrike/dlls/cs.so
#3  0x0804a1d0 in ?? () from ./hlds_linux

Read frame #0 first: the file it names in the from ... path is where execution was when the process died. If that path points at a Metamod plugin .so or an AMX Mod X module, that add-on is your prime suspect — the crash happened in its code. If #0 is inside engine_i486.so or cs.so but the frames above it come from a plugin, the plugin fed the engine something bad. The lower frames show the path that got there. Use bt full for local variables if the symbols are present.

5. Turn the stack into a culprit

You now have a filename. Correlate it with the crash conditions: if the top frame is zombie_plague.so and the server dies on map change, disable that plugin and see whether the crash stops. Cross-reference the timestamp with the AMXX error log and the HLDS console log — a run-time error logged one second before the core often names the same plugin. This backtrace-plus-log pairing is the fast path; the broader elimination method for a server that crashes with no obvious cause is in debugging a server crash with no error and finding a crashing plugin.

Common errors

  • No core file after a crashulimit -c unlimited was not set for the process that died, or core_pattern pipes cores to a handler. Check both.
  • Backtrace is all ?? () with no names — symbols are stripped; the from ...so path is still the useful part. That filename is your suspect.
  • 'core' is truncated / gdb complains it is incomplete — the disk filled or the limit capped it. Free space and set the limit to unlimited.
  • Loaded core against the wrong binary — addresses look random. Use the exact hlds_linux that crashed.
  • Crash is inside the engine, not a plugin — if no add-on appears anywhere in the stack, suspect the engine build itself and consider ReHLDS, which fixes many stock-engine faults.

Verification

Once the stack points at a plugin or module, remove it (comment its line in plugins.ini or modules.ini), restart, and reproduce the exact action that caused the crash. If the server survives, the backtrace was correct. Keep the core file and your bt output until the fix is confirmed — if the crash returns, load the next core the same way and compare frame #0; a moving top frame points at memory corruption, a stable one confirms the single guilty add-on.

Сътрудници: Daemon666 ✦
Сподели: