fix: PCI summary JSON parser to match real QEMU info pci output

The awk patterns in hw_gen_pci_json() targeted a hypothetical output format
that never matched QEMU's actual HMP 'info pci' response:

- /^Bus / anchored to line start, but QEMU outputs '  Bus  ' (2 leading spaces)
- /vendor_id = / expected 'vendor_id = 0x8086', but QEMU prints 'PCI device 8086:2922'
- /device_id = / expected separate line, but vendor:device are on the same line
- /class = / expected 'class = 0x010601', but QEMU prints 'SATA controller:' or 'Class 0106:'
- IRQ field expected 'IRQ 0.' but QEMU prints 'IRQ 5, pin A'

Result: pci_summary.json was always invalid JSON with orphaned key-value pairs.

Fix verified against QEMU source (pci-hmp-cmds.c:31-51) and tested with
realistic 4-device output: all devices correctly parsed with bus/dev/fn,
vendor_id, device_id, and IRQ fields.

Found by: 5-agent parallel review (QA execution agent)
This commit is contained in:
2026-06-30 14:51:06 +03:00
parent 522bba45c7
commit acc2d93307
+20 -12
View File
@@ -444,29 +444,37 @@ hw_gen_pci_json() {
printf ' "devices": [\n'
awk '
/^Bus / {
# Device header: " Bus 0, device 1, function 0:"
# (QEMU outputs 2 leading spaces — no ^ anchor)
/Bus .*device .*function/ {
if (found) printf " },\n"
found = 1
bus = $2; gsub(/,/, "", bus)
dev = $4; gsub(/,/, "", dev)
fn = $6; gsub(/:/, "", fn)
printf " {\"bus\": %s, \"device\": %s, \"function\": %s", bus, dev, fn
next
}
/vendor_id = / {
gsub(/.*= /, "", $0)
printf ", \"vendor_id\": \"%s\"", $NF
# Vendor/device line: " SATA controller: PCI device 8086:2922"
# or: " Class 0106: PCI device 8086:2922"
/PCI device/ {
for (i = 1; i <= NF; i++) {
if (index($i, ":") > 0) {
split($i, vd, ":")
if (length(vd[1]) == 4 && length(vd[2]) == 4 && \
vd[1] ~ /^[0-9a-fA-F]+$/ && vd[2] ~ /^[0-9a-fA-F]+$/) {
printf ", \"vendor_id\": \"0x%s\", \"device_id\": \"0x%s\"", vd[1], vd[2]
break
}
/device_id = / {
gsub(/.*= /, "", $0)
printf ", \"device_id\": \"%s\"", $NF
}
/class = / {
gsub(/.*= /, "", $0)
printf ", \"class\": \"%s\"", $NF
}
/IRQ / {
_irq = $2; gsub(/\./, "", _irq)
next
}
# IRQ line: " IRQ 5, pin A"
/IRQ [0-9]/ {
_irq = $2; gsub(/,/, "", _irq)
printf ", \"irq\": \"%s\"", _irq
next
}
END { if (found) printf " }"; printf "\n" }
' "$_pci" 2>/dev/null