Получение трассировки стека виртуальной машины QEMU во время mmio - PullRequest
0 голосов
/ 18 июня 2020

Я имитирую некоторое оборудование в 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);
}

1 Ответ

1 голос
/ 19 июня 2020

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

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

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

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

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

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

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

...