как работает google breakpad

Тема в разделе "WASM.X64", создана пользователем VaVa, 29 янв 2019.

  1. VaVa

    VaVa Member

    Публикаций:
    0
    Регистрация:
    21 авг 2018
    Сообщения:
    34
    можно ли как нибудь при исключении узнать какие были значения регистров? Может есть стандартные API? Было бы интересно аналогичное и под линух. (google breakpad такое может)

    А перед корахом программы всегда ли вызывается исключение если оно установлено, или возможны особые случаи?
     
  2. Коцит

    Коцит Active Member

    Публикаций:
    0
    Регистрация:
    31 янв 2017
    Сообщения:
    130
    Ошибки прикладных программ прекрасно контролирует встроенный вин/отладчик "Dr.Watson". Для этого достаточно запустить его с ключом "-i", т.е. [Win+R-->drwtsn32 -i]. C этого момента, ошибки прикладного уровня будут сохранятся в логе, который найдёшь по адресу: [C:\Documents and Settings\All Users\Application Data\Microsoft\Dr Watson]. Там и регистры и стек на момент краха.
     
  3. VaVa

    VaVa Member

    Публикаций:
    0
    Регистрация:
    21 авг 2018
    Сообщения:
    34
    я думал без вывода ошибок можно :dntknw:
     
  4. Коцит

    Коцит Active Member

    Публикаций:
    0
    Регистрация:
    31 янв 2017
    Сообщения:
    130
  5. q2e74

    q2e74 Active Member

    Публикаций:
    0
    Регистрация:
    18 окт 2018
    Сообщения:
    988
    может тогда посмотреть в сторону PyDBG?
     
  6. VaVa

    VaVa Member

    Публикаций:
    0
    Регистрация:
    21 авг 2018
    Сообщения:
    34
    переведите с С на fasm пожалуйста (в ep значения регисртров)
    компилятор даже в дебуг версии оптимизирует и ничего не понять...
    Код (C):
    1. #include <Windows.h>
    2. #include <exception>
    3. int t=0;
    4. int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
    5. {
    6. t=4;
    7.         return EXCEPTION_EXECUTE_HANDLER;
    8. }
    9. int _tmain(int argc, _TCHAR* argv[])
    10. {
    11. __try
    12.     {
    13. t=3/t;
    14.     }
    15.     __except(filter(GetExceptionCode(), GetExceptionInformation()))
    16.     {
    17.  
    18.     }
    19. return 0;
    20. }
     
    Последнее редактирование модератором: 1 фев 2019
  7. Коцит

    Коцит Active Member

    Публикаций:
    0
    Регистрация:
    31 янв 2017
    Сообщения:
    130
    используй SetUnhandledExceptionFilter()..
    эта функция устанавливает юзерский SEH-обработчик,
    и при возникновении исключения возвращает в стек 2-указателя на структуры "EXCEPTION_RECORD" и "CONTEXT". Вот их содержимое, которое так-же ложится в стек, сразу за указателями (см.скрин ниже):
    Код (ASM):
    1. struc EXCEPTION_RECORD {         ; описание есть по ссылке выше
    2.   .ExceptionCode        dd ?
    3.   .ExceptionFlags       dd ?
    4.   .ExceptionRecord      dd ?
    5.   .ExceptionAddress     dd ?
    6.   .NumberParameters     dd ?
    7.   .ExceptionInformation dd 15 dup (?)
    8. }
    9.  
    10. struc CONTEXT {
    11.   .ContextFlags    dd    ?
    12.   .iDr0        dd    ?
    13.   .iDr1        dd    ?
    14.   .iDr2        dd    ?
    15.   .iDr3        dd    ?
    16.   .iDr6        dd    ?
    17.   .iDr7        dd    ?
    18.   .FloatSave    FLOATING_SAVE_AREA
    19.   .regGs     dd    ?
    20.   .regFs     dd    ?
    21.   .regEs     dd    ?
    22.   .regDs     dd    ?
    23.   .regEdi    dd    ?
    24.   .regEsi    dd    ?
    25.   .regEbx    dd    ?
    26.   .regEdx    dd    ?
    27.   .regEcx    dd    ?
    28.   .regEax    dd    ?
    29.   .regEbp    dd    ?
    30.   .regEip    dd    ?
    31.   .regCs     dd    ?
    32.   .regFlag    dd    ?
    33.   .regEsp    dd    ?
    34.   .regSs     dd    ?
    35.   .ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
    36. }
    37.  
    Пример на фасме, который подминает SEH под свой обработчик "mySeh", и генерит исключение. Остаётся распарсить стек и получишь весь контекст на момент ошибки (я просто вывел из обработчика мессагу):
    Код (ASM):
    1. include  'win32ax.inc'
    2. .data
    3. mess     db  'Ошибка!!! Обнаружена недопустимая операция!',0
    4. .code
    5. start:   invoke  SetUnhandledExceptionFilter, mySeh    ; указатель на обработчик
    6.  
    7.          xor    eax,eax            ; генерим исключение..
    8.          div    eax
    9.  
    10.          invoke  ExitProcess,0
    11. ;------------------------------
    12. mySeh:   invoke  MessageBox,0,mess,0,10h
    13.          mov     eax,1
    14.          ret
    15. .end start
    16. ;------------------------------
    17. ; Возвращаемые значения из "mySeh" и их описание:
    18.     ;eax=-1 перезагрузить контекст и продолжить выполнение программы.
    19.     ;eax= 1 не показывать сообщение о предстоящем закрытии программы.
    20.     ;eax= 0 показывать сообщение о предстоящем закрытии программы.
    21.  
    seh_00.png
     
    Последнее редактирование модератором: 3 фев 2019
  8. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Коцит,

    > эта функция устанавливает юзерский SEH-обработчик,

    Не совсем так. Регистрируется финальный обработчик, он вызывается после любой другой обработки перед аварийным завершением приложения. В отличие от структурной/векторной обработки это простой стаб, он не синхронный(те нет межпоточных блокировок).
     
  9. Коцит

    Коцит Active Member

    Публикаций:
    0
    Регистрация:
    31 янв 2017
    Сообщения:
    130
    Вообще-то "финальный" с маркером(-1) и прихлопывает процесс аварийно, тихо/мирно отправляя его в небытие по ExitProcess, даже без посмертной надписи. Но поскольку эта функция фильтра позволяет установить свой/юзерский обработчик, значит это не финальный (хотя в доках его и называют именно так)? То-есть после него управление принимает последний в цепочке?
    Ещё непонятен сл.момент..
    ..где он регистрируется?
    После этой функции TEB остаётся не тронутым, как и содержимое стека. Я так и не нашёл нигде указателей на свой обработчик. В доках есть упоминание, что SEH-фреймы могут находиться где-угодно (не обязательно в стеке), но в любом случае на начало цепочки должен указывать FS:[0] в ТЕВ, однако там - полный штиль и ничего не меняется. Выходит функция просто модифицирует (где-то в ядре) финальный чтоли, тупо добавляя к нему юзерский обработчик? Хрень какая-то..

    Другое дело, когда устанавливаешь для треда свой SEH вручную - всё как на ладони, и система от тебя ничего уже не скрывает. Плюс есть бонусы в виде 'Safe-Place' (безопасная область) в возвращаемых значениях, и возможность обернуть в обработчик отдельный участок кода или весь тред целиком.
    Кстати тут есть SEH для асматиков: https://wasm.in/blogs/obrabotka-iskljuchenij-win32-dlja-programmistov-na-assemblere.381/
     
  10. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Коцит,

    Код (Text):
    1. LPTOP_LEVEL_EXCEPTION_FILTER BasepCurrentTopLevelFilter;
    2.  
    3. LPTOP_LEVEL_EXCEPTION_FILTER
    4. WINAPI
    5. SetUnhandledExceptionFilter(
    6.     LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
    7.     )
    8.  
    9. /*++
    10.  
    11. Routine Description:
    12.  
    13.     This function allows an application to supersede the top level
    14.     exception handler that Win32 places at the top of each thread and
    15.     process.
    16.  
    17.     If an exception occurs, and it makes it to the Win32 unhandled
    18.     exception filter, and the process is not being debugged, the Win32
    19.     filter will call the unhandled exception filter specified by
    20.     lpTopLevelExceptionFilter.
    21.  
    22.     This filter may return:
    23.  
    24.         EXCEPTION_EXECUTE_HANDLER - Return from the Win32
    25.             UnhandledExceptionFilter and execute the associated
    26.             exception handler.  This will usually result in process
    27.             termination
    28.  
    29.         EXCEPTION_CONTINUE_EXECUTION - Return from the Win32
    30.             UnhandledExceptionFilter and continue execution from the
    31.             point of the exception.  The filter is of course free to
    32.             modify the continuation state my modifying the passed
    33.             exception information.
    34.  
    35.         EXCEPTION_CONTINUE_SEARCH - Proceed with normal execution of the
    36.             Win32 UnhandledExceptionFilter.  e.g.  obey the SetErrorMode
    37.             flags, or invoke the Application Error popup.
    38.  
    39.     This function is not a general vectored exception handling
    40.     mechanism.  It is intended to be used to establish a per-process
    41.     exception filter that can monitor unhandled exceptions at the
    42.     process level and respond to these exceptions appropriately.
    43.  
    44. Arguments:
    45.  
    46.     lpTopLevelExceptionFilter - Supplies the address of a top level
    47.         filter function that will be called whenever the Win32
    48.         UnhandledExceptionFilter gets control, and the process is NOT
    49.         being debugged.  A value of NULL specifies default handling
    50.         within the Win32 UnhandledExceptionFilter.
    51.  
    52.  
    53. Return Value:
    54.  
    55.     This function returns the address of the previous exception filter
    56.     established with this API.  A value of NULL means that there is no
    57.     current top level handler.
    58.  
    59. --*/
    60.  
    61. {
    62.     LPTOP_LEVEL_EXCEPTION_FILTER PreviousTopLevelFilter;
    63.  
    64.     PreviousTopLevelFilter = BasepCurrentTopLevelFilter;
    65.     BasepCurrentTopLevelFilter = lpTopLevelExceptionFilter;
    66.  
    67.     return PreviousTopLevelFilter;
    68. }
    --- Сообщение объединено, 2 фев 2019 ---
    Разбирайся.

    Код (Text):
    1. LONG
    2. UnhandledExceptionFilter(
    3.     struct _EXCEPTION_POINTERS *ExceptionInfo
    4.     )
    5. {
    6.     NTSTATUS Status;
    7.     ULONG_PTR Parameters[ 4 ];
    8.     ULONG Response;
    9.     HANDLE DebugPort;
    10.     CHAR AeDebuggerCmdLine[256];
    11.     CHAR AeAutoDebugString[8];
    12.     BOOLEAN AeAutoDebug;
    13.     ULONG ResponseFlag;
    14.     LONG FilterReturn;
    15.     PRTL_CRITICAL_SECTION PebLockPointer;
    16.     JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimit;
    17.  
    18.     //
    19.     // If we take a write fault, then attampt to make the memory writable. If this
    20.     // succeeds, then silently proceed
    21.     //
    22.  
    23.     if ( ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION
    24.         && ExceptionInfo->ExceptionRecord->ExceptionInformation[0] ) {
    25.  
    26.         FilterReturn = BasepCheckForReadOnlyResource((PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
    27.  
    28.         if ( FilterReturn == EXCEPTION_CONTINUE_EXECUTION ) {
    29.             return FilterReturn;
    30.             }
    31.         }
    32.  
    33.     //
    34.     // If the process is being debugged, just let the exception happen
    35.     // so that the debugger can see it. This way the debugger can ignore
    36.     // all first chance exceptions.
    37.     //
    38.  
    39.     DebugPort = (HANDLE)NULL;
    40.     Status = NtQueryInformationProcess(
    41.                 GetCurrentProcess(),
    42.                 ProcessDebugPort,
    43.                 (PVOID)&DebugPort,
    44.                 sizeof(DebugPort),
    45.                 NULL
    46.                 );
    47.  
    48.     if ( NT_SUCCESS(Status) && DebugPort ) {
    49.  
    50.         //
    51.         // Process is being debugged.
    52.         // Return a code that specifies that the exception
    53.         // processing is to continue
    54.         //
    55.         return EXCEPTION_CONTINUE_SEARCH;
    56.         }
    57.  
    58.     if ( BasepCurrentTopLevelFilter ) {
    59.         FilterReturn = (BasepCurrentTopLevelFilter)(ExceptionInfo);
    60.         if ( FilterReturn == EXCEPTION_EXECUTE_HANDLER ||
    61.              FilterReturn == EXCEPTION_CONTINUE_EXECUTION ) {
    62.             return FilterReturn;
    63.             }
    64.         }
    65.  
    66.     if ( GetErrorMode() & SEM_NOGPFAULTERRORBOX ) {
    67.         return EXCEPTION_EXECUTE_HANDLER;
    68.         }
    69.  
    70.     //
    71.     // See if the process's job has been programmed to NOGPFAULTERRORBOX
    72.     //
    73.     Status = NtQueryInformationJobObject(
    74.                 NULL,
    75.                 JobObjectBasicLimitInformation,
    76.                 &BasicLimit,
    77.                 sizeof(BasicLimit),
    78.                 NULL
    79.                 );
    80.     if ( NT_SUCCESS(Status) && (BasicLimit.LimitFlags & JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION) ) {
    81.         return EXCEPTION_EXECUTE_HANDLER;
    82.         }
    83.  
    84.     //
    85.     // The process is not being debugged, so do the hard error
    86.     // popup.
    87.     //
    88.  
    89.     Parameters[ 0 ] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionCode;
    90.     Parameters[ 1 ] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
    91.  
    92.     //
    93.     // For inpage i/o errors, juggle the real status code to overwrite the
    94.     // read/write field
    95.     //
    96.  
    97.     if ( ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR ) {
    98.         Parameters[ 2 ] = ExceptionInfo->ExceptionRecord->ExceptionInformation[ 2 ];
    99.         }
    100.     else {
    101.         Parameters[ 2 ] = ExceptionInfo->ExceptionRecord->ExceptionInformation[ 0 ];
    102.         }
    103.  
    104.     Parameters[ 3 ] = ExceptionInfo->ExceptionRecord->ExceptionInformation[ 1 ];
    105.  
    106.     //
    107.     // See if a debugger has been programmed in. If so, use the
    108.     // debugger specified. If not then there is no AE Cancel support
    109.     // DEVL systems will default the debugger command line. Retail
    110.     // systems will not.
    111.     //
    112.  
    113.     ResponseFlag = OptionOk;
    114.     AeAutoDebug = FALSE;
    115.  
    116.     //
    117.     // If we are holding the PebLock, then the createprocess will fail
    118.     // because a new thread will also need this lock. Avoid this by peeking
    119.     // inside the PebLock and looking to see if we own it. If we do, then just allow
    120.     // a regular popup.
    121.     //
    122.  
    123.     PebLockPointer = NtCurrentPeb()->FastPebLock;
    124.  
    125.     if ( PebLockPointer->OwningThread != NtCurrentTeb()->ClientId.UniqueThread ) {
    126.  
    127.         try {
    128.             if ( GetProfileString(
    129.                     "AeDebug",
    130.                     "Debugger",
    131.                     NULL,
    132.                     AeDebuggerCmdLine,
    133.                     sizeof(AeDebuggerCmdLine)-1
    134.                     ) ) {
    135.                 ResponseFlag = OptionOkCancel;
    136.                 }
    137.  
    138.             if ( GetProfileString(
    139.                     "AeDebug",
    140.                     "Auto",
    141.                     "0",
    142.                     AeAutoDebugString,
    143.                     sizeof(AeAutoDebugString)-1
    144.                     ) ) {
    145.  
    146.                 if ( !strcmp(AeAutoDebugString,"1") ) {
    147.                     if ( ResponseFlag == OptionOkCancel ) {
    148.                         AeAutoDebug = TRUE;
    149.                         }
    150.                     }
    151.                 }
    152.             }
    153.         except (EXCEPTION_EXECUTE_HANDLER) {
    154.             ResponseFlag = OptionOk;
    155.             AeAutoDebug = FALSE;
    156.             }
    157.         }
    158.     if ( !AeAutoDebug ) {
    159.         Status =NtRaiseHardError( STATUS_UNHANDLED_EXCEPTION | HARDERROR_OVERRIDE_ERRORMODE,
    160.                                   4,
    161.                                   0,
    162.                                   Parameters,
    163.                                   BasepAlreadyHadHardError ? OptionOk : ResponseFlag,
    164.                                   &Response
    165.                                 );
    166.  
    167.         }
    168.     else {
    169.         Status = STATUS_SUCCESS;
    170.         Response = ResponseCancel;
    171.         }
    172.  
    173.     //
    174.     // Internally, send OkCancel. If we get back Ok then die.
    175.     // If we get back Cancel, then enter the debugger
    176.     //
    177.  
    178.     if ( NT_SUCCESS(Status) && Response == ResponseCancel && BasepAlreadyHadHardError == FALSE) {
    179.         if ( !BaseRunningInServerProcess ) {
    180.             BOOL b;
    181.             STARTUPINFO StartupInfo;
    182.             PROCESS_INFORMATION ProcessInformation;
    183.             CHAR CmdLine[256];
    184.             NTSTATUS Status;
    185.             HANDLE EventHandle;
    186.             SECURITY_ATTRIBUTES sa;
    187.  
    188.             BasepAlreadyHadHardError = TRUE;
    189.             sa.nLength = sizeof(sa);
    190.             sa.lpSecurityDescriptor = NULL;
    191.             sa.bInheritHandle = TRUE;
    192.             EventHandle = CreateEvent(&sa,TRUE,FALSE,NULL);
    193.             RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
    194.             sprintf(CmdLine,AeDebuggerCmdLine,GetCurrentProcessId(),EventHandle);
    195.             StartupInfo.cb = sizeof(StartupInfo);
    196.             StartupInfo.lpDesktop = "Winsta0\\Default";
    197.             CsrIdentifyAlertableThread();
    198.             b =  CreateProcess(
    199.                     NULL,
    200.                     CmdLine,
    201.                     NULL,
    202.                     NULL,
    203.                     TRUE,
    204.                     0,
    205.                     NULL,
    206.                     NULL,
    207.                     &StartupInfo,
    208.                     &ProcessInformation
    209.                     );
    210.  
    211.             if ( b && EventHandle) {
    212.  
    213.                 //
    214.                 // Do an alertable wait on the event
    215.                 //
    216.  
    217.                 do {
    218.                     Status = NtWaitForSingleObject(
    219.                                 EventHandle,
    220.                                 TRUE,
    221.                                 NULL
    222.                                 );
    223.                     } while (Status == STATUS_USER_APC || Status == STATUS_ALERTED);
    224.                 return EXCEPTION_CONTINUE_SEARCH;
    225.                 }
    226.  
    227.             }
    228.         }
    229.  
    230. #if DBG
    231.     if (!NT_SUCCESS( Status )) {
    232.         DbgPrint( "BASEDLL: Unhandled exception: %lx  IP: %x\n",
    233.                   ExceptionInfo->ExceptionRecord->ExceptionCode,
    234.                   ExceptionInfo->ExceptionRecord->ExceptionAddress
    235.                 );
    236.         }
    237. #endif
    238.     if ( BasepAlreadyHadHardError ) {
    239.         NtTerminateProcess(NtCurrentProcess(),ExceptionInfo->ExceptionRecord->ExceptionCode);
    240.         }
    241.     return EXCEPTION_EXECUTE_HANDLER;
    242. }