GDB examine command shows different value than value loaded from the same address

2026-04-25

Stack Overflow: View Question

Tags: debugging, assembly, operating-system, gdb, x86-64

Score: 2 | Views: 72

The asker is writing a bare-metal OS that enumerates PCIe devices by walking the ECAM (Enhanced Configuration Access Mechanism) memory space. Their function reads the vendor ID at each possible bus/device/function address and saves valid ones. The problem: GDB's x (examine) command shows a different value at the same memory address than what the CPU actually loaded into a register. This is deeply confusing and suggests something fundamental is going on beneath the debugger.

This is a genuinely interesting problem because it sits at the intersection of several tricky x86 concepts:

The debugging approach should be:

  1. Verify the ECAM base address from the MCFG ACPI table — an off-by-one in the bus/device/function calculation shifts all reads.
  2. Confirm the ECAM region is mapped as UC in your page tables. Any cacheable mapping of MMIO space will produce bizarre inconsistencies.
  3. Check the exact access width in both your assembly and what GDB is issuing. Use x/1hx (halfword) to match a 16-bit vendor ID read.
  4. Compare register values immediately after the load (info registers) with the examine output — if the register is correct but x disagrees, it's almost certainly a GDB stub vs. MMIO semantics issue.

A common gotcha: for non-existent PCIe functions, the hardware returns 0xFFFF for the vendor ID. If you're seeing valid-looking values where there should be none, your address calculation is likely hitting a real device's config space repeatedly rather than walking to empty slots.

The challenge: GDB's memory examine command bypasses the guest MMU and MMIO transaction semantics, so it can show fundamentally different values than what the CPU actually loaded — a subtle trap that strikes anyone debugging bare-metal code against memory-mapped hardware.

All newsletters