Получить трассировку стека виртуальной машины QEMU во время mmio

Я эмулирую некоторое оборудование в QEMU, которое соответствует некоторым драйверам в ядре гостевой Linux.

Прямо сейчас я могу использовать memory_region_init_io для настройки областей mmio, чтобы всякий раз, когда драйвер ядра читает / записывает на адрес mmio, я получал обратный вызов.

Как я могу получить трассировку стека ядра, которое запускает доступ mmio в обратном вызове? Я хочу знать, какая строка в драйвере ядра запускает какой доступ через mmio.

Я знаю, что mmiotrace может быть вариантом, но эта трассировка происходит в гостевом ядре. Могу ли я добиться этого с помощью qemu-kvm.

static uint64_t mmio_read(void *opaque, hwaddr addr,
                              unsigned size) {
    /* Here, I want to get the stacktrace inside VM 
     * that caused this mmio read */
    printf("mmio_read: %lx[%u] returns %lx\n", addr, size, ret);
    return 0;
}
static void stream_dma_write(void *opaque, hwaddr addr,
                           uint64_t val, unsigned size) {
    /* Here, I want to get the stacktrace inside VM 
     * that caused this mmio write */
    printf("mmio_write: %lx[%u]=%lx \n", addr, size, val);
}

static const MemoryRegionOps mmio_ops {
    .read = mmio_read,
    .write = mmio_write,
}

void init_region(uintptr_t addr, size_t size) {
MemoryRegion *subregion = malloc(sizeof(MemoryRegion));
    memory_region_init_io(subregion, OBJECT(opaque), 
                &mmio_ops, NULL, "mmio-region", size);
    memory_region_add_subregion_overlap(get_system_memory(),
                addr, subregion, 100);
}

person Bruce Shen    schedule 18.06.2020    source источник


Ответы (1)


К сожалению, QEMU не предоставляет ничего, что могло бы сделать это за вас как API, который вы можете вызывать из кода QEMU C. Есть пара проблем:

  1. QEMU не обновляет все состояние ЦП для каждой инструкции, и, в частности, не обновляет значение ПК до тех пор, пока это не будет абсолютно необходимо, потому что постоянная запись «добавить 4 в поле ПК в структуре состояния ЦП» является дорогостоящим. Таким образом, текущий ПК не очень удобно доступен с помощью функции чтения / записи MMIO устройства.

  2. QEMU не имеет кода, который знает, как выполнять обратную трассировку гостевого стека. Это сравнительно сложно сделать правильно (вы, конечно, найдете код для этого в отладчиках).

Я думаю, что если бы я разрабатывал что-то для этой цели, я бы, вероятно, попытался предоставить устройству способ инициировать остановку гостя, чтобы gdb целевой архитектуры, подключенный к gdbstub QEMU, мог проверять регистры и выполнять обратную трассировку. Затем вы можете написать сценарий отладчика, если хотите «напечатать обратную трассировку и продолжить гостевое выполнение».

Тем не менее, вот несколько предложений, которые вы можете попробовать:

  1. Если вам повезет, то установка точек наблюдения из gdb целевой архитектуры в gdbstub QEMU для адресов регистров устройства позволит вам получить контроль в gdb, когда гость выполняет доступ к устройству, чтобы вы могли выполнить обратную трассировку. Я даю этому примерно 50% шанс сработать, потому что я не уверен, насколько надежной будет поддержка точек наблюдения большой площади; также вам нужно будет установить точки наблюдения на виртуальном адресе, на который ядро ​​сопоставило устройство, что может быть сложно определить.

  2. Мой опыт написания моделей устройств показал, что обычно достаточно просто взглянуть на исходный код драйвера устройства, что он делал, когда делал MMIO-доступ к устройству. Вы знаете, в какой регистр была записана запись и с каким значением, чего часто бывает достаточно, чтобы сузить круг, какой бит драйвера сделал доступ. Конечно, это зависит от сложности аппаратного обеспечения и драйвера.

  3. Использование параметров QEMU -d и -D для регистрации комбинации событий трассировки для конкретного устройства и общей информации о выполнении / потоке управления гостевым процессором - еще одна уловка, которую я нашел полезной при попытке выяснить, что гость делал с устройством.

person Peter Maydell    schedule 19.06.2020
comment
К сожалению, в настоящее время я имею дело с большими драйверами, такими как Wi-Fi и Nic. По поводу некоторых комментариев к вашим предложениям. 1) точки наблюдения за памятью отладчика ограничены аппаратными средствами. Я думаю, что обычно получается около 5. 2) это хорошо работает для небольших проектов. Я изучу ваш вариант 3, чтобы увидеть, на что он способен. - person Bruce Shen; 20.06.2020
comment
Прямо сейчас мне нужно изменить модуль ядра, например добавив printk и просмотрите журнал отладки драйвера, чтобы определить строку доступа mmio и dma. Также очень сложно определить доступ к dma. - person Bruce Shen; 20.06.2020
comment
Ах да, я не заметил, что вы используете KVM. (Для TCG точки наблюдения эмулируются в QEMU, поэтому h / w ограничения не имеют значения.) - person Peter Maydell; 21.06.2020
comment
Исследовательская работа, которую я прочитал, реализовала трассировку стека гостя под ускорением tcg. Я не вникал в их код. Но я думаю, что в этом вопросе KVM был бы совсем другим. - person Bruce Shen; 22.06.2020