MiniDumpWriteDump с обратным вызовом в Go

Я пытаюсь реализовать MiniDumpWriteDump с обратным вызовом в Go.

Вызов MiniDumpWriteDump:

    callback := syscall.NewCallback(miniDumpCallback)
    var newCallbackRoutine MINIDUMP_CALLBACK_INFORMATION
    newCallbackRoutine.CallbackParam = 0
    newCallbackRoutine.CallbackRoutine = callback
    ret, _, err := miniDumpWriteDump.Call(
        uintptr(processHandle),
        uintptr(processId),
        uintptr(dumpFile),
        uintptr(options),
        0,
        0,
        uintptr(unsafe.Pointer(&newCallbackRoutine)),
    )

Сама функция обратного вызова:

func miniDumpCallback(_ uintptr, CallbackInput *MINIDUMP_CALLBACK_INPUT, _ uintptr) uintptr {
    fmt.Println(CallbackInput.ProcessId, CallbackInput.CallbackType)
    return 1
}

Определения типов:

type MINIDUMP_CALLBACK_INPUT struct {
    ProcessId     win32.ULONG
    ProcessHandle win32.HANDLE
    CallbackType  win32.ULONG
    CallbackInfo  uintptr
}

type MINIDUMP_CALLBACK_INFORMATION struct {
    CallbackRoutine uintptr
    CallbackParam   uintptr
}

Вызывается обратный вызов, и некоторые поля получают правильные данные, но некоторые получают бессмысленные значения.

Например, обратный вызов выше правильно получает поле ProcessId CallbackInput, но получает случайные целые числа в качестве CallbackType, тогда как он должен получать перечисление MINIDUMP_CALLBACK_TYPE.

Выход:

12544 0
12544 1133445120
12544 12548
12544 13028
12544 1114112
12544 1023344640
12544 999620608
12544 990117888
12544 992542720
12544 1005518848
12544 1994850304
12544 1114112
12544 1994915840

Почему вы решили удалить свой предыдущий вопрос (включая полученные полезные комментарии)?

IInspectable 20.08.2023 17:45

На этот вопрос не было получено ни одного правильного ответа. Я попробовал решение, предложенное в комментарии, на который вы ссылаетесь, но оно не сработало. Эта версия кода более чистая и предлагает относительно более правильный способ регистрации обратного вызова. Я удалил предыдущий вопрос, потому что он не имел никакой ценности для сообщества и, кроме того, показывал неправильное использование функций обратного вызова. Я разместил это, новое с тем же названием, чтобы другие разработчики нашли более правильный и понятный код, когда попытаются изучить эту тему.

pepperoni 20.08.2023 17:56

Я ничего не знаю о Go, но предполагаю, что проблема в выравнивании структуры MINIDUMP_CALLBACK_INPUT. Предполагая, что вы работаете на x64, выравнивание будет составлять 8 байт.

Luke 20.08.2023 19:27

Итак, если я правильно понимаю, что-то вроде этого надо сделать, да? @Люк type MINIDUMP_CALLBACK_INPUT struct { ProcessId uint32 _ [8]byte ProcessHandle windows.Handle _ [8]byte CallbackType uint32 _ [8]byte CallbackInfo uintptr _ [8]byte }

pepperoni 20.08.2023 20:02

Структуры в minidumpapiset.h имеют выравнивание по 4 байта (на всех платформах). Для 32-битных архитектур все должно работать, поскольку это естественное выравнивание для всех используемых здесь типов. Для 64-битных архитектур вам придется принудительно ограничить размещение памяти 4-байтовыми границами, и вы не сможете полагаться на естественную структуру памяти Go для структур.

IInspectable 21.08.2023 02:59

Чтобы убедиться в этом, вы можете прочитать поле ProcessHandle, извлечь старшие 32 бита и посмотреть, соответствует ли это 32-битное значение ожидаемому значению MINIDUMP_CALLBACK_TYPE. Если да, то проблема в упаковке структуры. Насколько я понимаю, Go не поддерживает упаковку неестественных структур, поэтому вместо этого вашему обратному вызову придется получить срез байта и проанализировать отдельные поля.

IInspectable 21.08.2023 12:18
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как следует из комментариев, проблема заключалась в выравнивании структуры.

Как объяснил @IInspectable, minidumpapiset.h, который экспортирует функцию MiniDumpWriteDump и структуру MINIDUMP_CALLBACK_INPUT, использует 4-байтовое выравнивание как для 32-битной, так и для 64-битной архитектуры, в то время как Go по умолчанию использует 8-байтовое выравнивание для 64-битной архитектуры и не предлагает автоматического способа его изменения.

Решение состоит в том, чтобы вручную прочитать структуру. Вот рабочий пример:

type MINIDUMP_CALLBACK_INPUT struct {
ProcessId     uint32
ProcessHandle uintptr
CallbackType  uint32
CallbackInfo uintptr}

func ptrToMinidumpCallbackInput(ptrCallbackInput uintptr) MINIDUMP_CALLBACK_INPUT{
    var input MINIDUMP_CALLBACK_INPUT
    input.ProcessId = *(*uint32)(unsafe.Pointer(ptrCallbackInput))
    input.ProcessHandle = *(*uintptr)(unsafe.Pointer(ptrCallbackInput + unsafe.Sizeof(uint32(0))))
    input.CallbackType = *(*uint32)(unsafe.Pointer(ptrCallbackInput + unsafe.Sizeof(uint32(0)) + unsafe.Sizeof(uintptr(0))))
    input.CallbackInfo = *(*uintptr)(unsafe.Pointer(ptrCallbackInput + unsafe.Sizeof(uint32(0)) + unsafe.Sizeof(uintptr(0)) + unsafe.Sizeof(uint32(0))))
    return input}

Исходный код должен нормально работать на 32-битных архитектурах, поскольку его заполнение (4 байта) совпадает с заполнением, которое использует minidumpapiset.h.

Другие вопросы по теме