* MinGW上でデバックするときのためのメモ
-(by [[K]], 2022.12.19)
** (8) まとまってない情報
*** (8-1) win32-apiのSetUnhandledExceptionFilter
--以下のようにすれば例外が拾えるようになる。
--[参考] https://learn.microsoft.com/ja-jp/windows/win32/api/winnt/ns-winnt-exception_record
#include <windows.h>
#include <stdio.h>
#include <string.h>
LONG WINAPI aExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
char *s = "unknown";
DWORD c = ExceptionInfo->ExceptionRecord->ExceptionCode;
if (c == EXCEPTION_ACCESS_VIOLATION) s = "EXCEPTION_ACCESS_VIOLATION"; // NULL pointer など.
if (c == EXCEPTION_GUARD_PAGE) s = "EXCEPTION_GUARD_PAGE";
if (c == EXCEPTION_ILLEGAL_INSTRUCTION) s = "EXCEPTION_ILLEGAL_INSTRUCTION";
if (c == EXCEPTION_IN_PAGE_ERROR) s = "EXCEPTION_IN_PAGE_ERROR";
if (c == EXCEPTION_INT_DIVIDE_BY_ZERO) s = "EXCEPTION_INT_DIVIDE_BY_ZERO";
if (c == EXCEPTION_PRIV_INSTRUCTION) s = "EXCEPTION_PRIV_INSTRUCTION";
fprintf(stderr, "aExceptionHandler: addr=%08x, code=%s(%08x), flags=%08x\n",
(int) ExceptionInfo->ExceptionRecord->ExceptionAddress,
s,
(int) ExceptionInfo->ExceptionRecord->ExceptionCode,
(int) ExceptionInfo->ExceptionRecord->ExceptionFlags
);
int i, n = ExceptionInfo->ExceptionRecord->NumberParameters;
fprintf(stderr, " ExceptionInformation: n=%d", n);
for (i = 0; i < n; i++)
fprintf(stderr, ", %08x", (int) ExceptionInfo->ExceptionRecord->ExceptionInformation[i]);
fprintf(stderr, "\n");
return EXCEPTION_EXECUTE_HANDLER; // これを返せばすぐに終了してくれる.
}
int main()
{
SetUnhandledExceptionFilter(aExceptionHandler);
int *p = (int *) 32; printf("%d", *p); // code=EXCEPTION_ACCESS_VIOLATION, info=[0, 00000020].
// int *p = (int *) 0x00401000; p[0] = 123; // code=EXCEPTION_ACCESS_VIOLATION, info=[1, 00401000].
return 0;
}
***(8-2) マップファイルの取得と簡単な解析
--以下のようなバッチファイルを作れば、ビルド時にmapファイルを作ってくれるようになる(-O2や-O3でももちろん問題ない)。
c:\mingw\bin\gcc -m32 -Wall -Wextra -Wl,-s,-Map,%1_map.txt -Wno-unused-function -Os %1.c -o %1.exe %2 %3 %4 %5 %6 %7 %8 %9
--そのマップファイルがあれば、以下のような簡単なプログラムで、上記のaddrがどの関数内にあるのかを探し出せる。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char **argv)
{
if (argc < 3) {
printf("usage>srchadr0 map-file addr\n");
return 1;
}
FILE *fp = fopen(argv[1], "rb");
if (fp == 0) {
printf("fopen error: %s\n", argv[1]);
return 1;
}
char *b = malloc(65536); // 65536は1行の最大の長さ.
char *bb = malloc(65536);
bb[0] = 0;
int adr, i;
sscanf(argv[2], "%i", &adr);
printf("addr=0x%08x\n", adr);
for (;;) {
if (fgets(b, 65536, fp) == 0) {
printf("not found: .text\n");
return 1;
}
if (strncmp(b, ".text ", 6) == 0) break;
}
for (;;) {
if (fgets(b, 65536, fp) == 0) break;
if (strncmp(b, ".data ", 6) == 0) break;
if (strncmp(b, ".rdata ", 7) == 0) break;
if (strncmp(b, ".pdata ", 7) == 0) break;
if (strncmp(b, ".bss ", 5) == 0) break;
if (strncmp(b, ".idata ", 7) == 0) break;
if (strncmp(b, " ", 4) != 0) continue;
sscanf(b, "%i", &i);
if (i > adr) {
printf("%s%s", bb, b);
return 0;
}
strcpy(bb, b);
}
printf("addr not found\n");
return 0;
}
***(8-3) 使えそうなマクロ
__LINE__ : 行番号
__FILE__ : ソースファイル名
--[参考] https://www.hiroom2.com/2015/09/07/c%E8%A8%80%E8%AA%9E%E3%81%AE-line-%E3%83%9E%E3%82%AF%E3%83%AD%E3%82%92%E3%83%97%E3%83%AA%E3%83%97%E3%83%AD%E3%82%BB%E3%83%83%E3%82%B5%E3%81%AE%E6%AE%B5%E9%9A%8E%E3%81%A7%E6%96%87%E5%AD%97%E5%88%97%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B/
***(8-4) スレッドID関係
-GetCurrentThreadId : https://learn.microsoft.com/ja-jp/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadid
--[Q] マルチスレッドでプログラムが動いているとき、もし一般保護例外などが発生したら、それはそのスレッドで登録しておいたUnhandledExceptionFilterが呼ばれるのだろうか?・・・うん、たぶんきっとそうだろう。わざわざ他のスレッドで呼び出さなければいけない理由を思いつけない。
--[Q] マルチスレッドでプログラムが動いているとき、もし一般保護例外などが発生したら、それはそのスレッドで登録しておいたUnhandledExceptionFilterが呼ばれるのだろうか?
---・・・うん、たぶんきっとそうだろう。わざわざ他のスレッドで呼び出さなければいけない理由を思いつけない。
* コメント欄
#comment