איך אוספים crash dump באפליקציית Windows: WER, ProcDump, WinDbg
· עודכן בתאריך: · Go Komura · פיתוח Windows, חקירת תקלות, crash dump, WER, ProcDump, WinDbg
היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 16 Mar 2026)
- פרסום ראשון
לצטט את המאמר הזה(DOI: 10.5281/zenodo.22173564)
מאמר זה מאוחסן בארכיון Zenodo. להלן גם ה-DOI שתמיד מפנה לגרסה האחרונה וגם ה-DOI המקובע לגרסה שאתם קוראים.
Go Komura (2026). איך אוספים crash dump באפליקציית Windows: WER, ProcDump, WinDbg. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22173564 https://comcomponent.com/he/blog/windows-app-crash-dump-collection-introduction/
- DOI (הגרסה האחרונה)
- 10.5281/zenodo.22173564
- DOI (הגרסה הזו)
- 10.5281/zenodo.22173565
כשמתחילים לראות אפליקציית Windows ש”נופלת מדי פעם”, יש הרבה מצבים שאי אפשר לעקוב אחריהם רק עם לוגים.
בפרט קשים המקרים הבאים:
- קורה רק בסביבת הלקוח
- הודעת ה-exception נתפסה, אבל חסר הקשר הקריאה
- מעורבים לא רק ה-managed בצד C# / .NET, אלא גם COM, P/Invoke, native DLL, vendor SDK
- קורס רק אחרי הרצה ארוכה
במקרים כאלה, ה-crash dump יעיל. אם שומרים לקובץ את מצב התהליך ברגע הקריסה, אפשר לקרוא בדיעבד את קוד ה-exception, את ה-call stack של ה-thread שקרס, את המודולים שהיו טעונים, ואת חלק מהזיכרון או כולו.
ב-Windows, קל יותר לחשוב בסדר הזה: קודם LocalDumps של WER, ואם צריך — ProcDump של Sysinternals, ואם רוצים שליטה נוספת — MiniDumpWriteDump. המאמר הזה מסדר את הצעד הראשון באיסוף crash dump, על בסיס אפליקציות שולחן עבודה ל-Windows, אפליקציות שרצות ברקע, Windows Service וכלי חיבור לציוד.
flowchart TB
accTitle: הסדר לחשיבה על אמצעי איסוף
accDescr: באיסוף crash dump ב-Windows, קל יותר לחשוב בסדר הזה: קודם LocalDumps של WER, ואם צריך ProcDump של Sysinternals, ואם רוצים שליטה נוספת MiniDumpWriteDump.
w1["קודם WER LocalDumps"] --> w2["אם צריך, ProcDump"]
w2 --> w3["ואם רוצים שליטה נוספת, MiniDumpWriteDump"]
איור 1: מתחילים מהפיצ’ר המובנה ומוסיפים כלים רק ככל שחסר.
מונחים שחוזרים לאורך המאמר
לפני שממשיכים, נקבע אותם בקצרה. אם הם נשארים מעורפלים, הפרקים הבאים יהיו לא ברורים.
| מונח | משמעות |
|---|---|
| PDB | קובץ מידע ניפוי באגים שנוצר בזמן הבנייה. טבלת המרה שממירה כתובת לשם פונקציה או מספר שורה |
| symbols | מידע התאמה בין כתובת לשם. מסופק מ-PDB או מ-symbol server. בלעדיו, ה-call stack הוא רשימת כתובות בלבד |
| first chance exception | השלב מיד אחרי ש-exception מתרחש, לפני שה-handler של האפליקציה עיבד אותו. אם האפליקציה תופסת אותו ב-catch, העיבוד ממשיך |
| second chance exception | השלב שבו האפליקציה לא הצליחה לטפל ב-exception, והתהליך בדרך לסיום כ-unhandled exception. בדרך כלל זה מה שמכונה “נפל” |
| postmortem debugger | debugger שה-OS מפעיל אוטומטית בזמן קריסה. נרשם כהתנהגות של המחשב כולו בזמן קריסה |
| minidump / full dump | ההבדל בכמות הזיכרון שנכלל ב-dump. מפורט בפרק 7 |
1. המסקנה בקצרה
הנה קודם כל הנקודות החשובות ביותר.
- ראשית, בטוח יותר להגדיר את WER LocalDumps לפי אפליקציה. בלי כלי נוסף, אפשר להשאיר dump מקומי אחרי קריסה.
- בחקירה בשטח עם שיעור שחזור נמוך, או כשרוצים לראות גם first chance exception / hang, משתמשים ב-ProcDump.
- איסוף עצמאי כדאי לשקול אחרון. מספיק לשקול
MiniDumpWriteDumpרק כשמתעורר צורך אמיתי. - חשוב לא פחות מה-dump עצמו הוא שמירת ה-PDB והקבצים הבינאריים המופצים. גם אם יש dump, בלי symbols כמות המידע הקריא קטנה משמעותית.
- full dump חזק, אבל גם הגודל וסיכון דליפת מידע רגיש חזקים. חשוב לקבוע מראש מיקום אחסון, מספר שמורים, הרשאות גישה, ונוהל שיתוף.
ההרכב המומלץ לשלב ההתחלה מתמצה בערך כך.
| סביבה | ההרכב הראשוני |
|---|---|
| מחשב פיתוח / בדיקה | הגדרת WER LocalDumps לפי אפליקציה, בהתחלה DumpType=2 שהוא full dump |
| סביבת לקוח / מחשב בשטח | בחירה בין DumpType=1 ל-2 לפי היקף וצורכי סודיות. הוספת ProcDump רק במקרה הצורך |
| הרצה ארוכה או חקירת hang | בנוסף ל-WER, לשקול -h או -e 1 של ProcDump |
| רוצים לכלול UI ייחודי או לוגים מצורפים | איסוף עצמאי עם MiniDumpWriteDump, בהנחה של תהליך נפרד |
בקיצור: קודם WER, אחר כך ProcDump, ולבסוף איסוף עצמאי. אם מתחילים בסדר הפוך, בדרך כלל התכנון מכביד.
ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 21, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle
2. מה אפשר ללמוד מ-crash dump
crash dump הוא “תצלום סטילס של הרגע ההוא”. יותר קרוב לתצלום זירת תאונה מאשר למצלמת אבטחה.
לכן, המידע הבא בדרך כלל קל למדי להשגה.
- באיזה קוד exception קרס
- איזה thread קרס
- ה-call stack באותו רגע
- אילו מודולים היו טעונים
- בהתאם לכמות הזיכרון שנכלל, מצב ה-heap ותוכן האובייקטים
מצד שני, יש דברים שה-dump לבדו נוטה שלא לספק.
- ציר הזמן שהוביל לשם
- מגמת עלייה מכמה שעות קודם
- מצב חיצוני של תקשורת או ציוד
- הקלט או ההקשר העסקי שקדם לכך
לכן, בפועל, הבסיס הוא לא לנסות להסתפק ב-dump לבדו, אלא לשלב אותו עם לוגים ו-heartbeat.
flowchart TB
accTitle: שילוב dump ולוגים
accDescr: crash dump חזק במיוחד במצב הרגע עצמו, כמו תצלום זירת תאונה, ולוגים ו-heartbeat משלימים את ציר הזמן והמצב החיצוני, ולכן הבסיס הוא לשלב את שניהם בחקירה.
d1["crash dump (תצלום סטילס)"] --> mix["חוקרים בשילוב"]
d2["לוגים ו-heartbeat (ציר זמן)"] --> mix
d1 -.-> s1["חזק בקוד exception וב-call stack"]
d2 -.-> s2["חזק בהתקדמות עד לרגע ההוא"]
איור 2: ה-dump שהוא תצלום סטילס והלוג שהוא ציר זמן חזקים בתחומים שונים לגמרי.
3. מבט כללי על שיטות האיסוף
ב-Windows, ארבע השיטות שכדאי להכיר בשלב ההתחלה לאיסוף dump הן אלה.
| שיטה | מתאימה למקרה | חוזקה | נקודה לתשומת לב |
|---|---|---|---|
| WER LocalDumps | איסוף קריסות שרוצים ראשית להשאיר קבוע | תקן של Windows. נוח להגדרה לפי אפליקציה | בעיקר מתאים לקריסות. חלש ב-hang ובתנאים עדינים |
| ProcDump | חקירה עם שיעור שחזור נמוך, hang, first chance exception | טריגרים רבים. נוח להפעיל בשטח | דורש הפעלת כלי חיצוני |
| יצירת dump מ-Task Manager | רוצים לתפוס ידנית את המצב הנוכחי | ניתן לתפוס באופן מיידי דרך GUI | לא איסוף אוטומטי |
MiniDumpWriteDump |
רוצים לבנות פונקציית אבחון עצמאית | קל לשלב לוגים מצורפים ומטא-דאטה ייחודית | מימוש רשלני עלול לגרום לתקלה נוספת |
מה שהכי חשוב למתחילים הוא לקבוע קודם באילו תנאים, לאן, ובאיזה גודל אוספים — לפני שבוחרים “עם מה” אוספים.
flowchart TB
accTitle: מה שקובעים לפני בחירת הכלי
accDescr: באיסוף crash dump חשוב לקבוע קודם באילו תנאים, לאן, ובאיזה גודל אוספים, ורק אחר כך לעבור לבחירת הכלי.
c1["באילו תנאים אוספים"] --> firstq["3 דברים שקובעים קודם"]
c2["לאן מוציאים"] --> firstq
c3["באיזה גודל"] --> firstq
firstq --> tool["ורק אז בוחרים כלי"]
איור 3: אחרי שקובעים תנאים, יעד וגודל, בחירת הכלי כבר לא מבלבלת.
4. ההמלצה הראשונה — WER LocalDumps
4.1 ערכי הרישום הראשונים לבדיקה
ל-Windows Error Reporting (WER) יש פיצ’ר בשם LocalDumps, ששומר dump ברמת user mode לוקלית אחרי קריסה. מכיוון שלא צריך להפיץ כלי נוסף, זה נוח למדי כצעד ראשון.
המפתח הבסיסי הוא כאן.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps
אפשר להניח כאן הגדרה גלובלית, אבל בפועל נוח יותר לרכז אותה במפתח משנה לפי אפליקציה.
flowchart TB
accTitle: היכן ממקמים את הגדרת LocalDumps
accDescr: מתחת למפתח LocalDumps אפשר להניח הגדרה גלובלית, אבל בפועל נוח יותר לרכז אותה במפתח משנה לפי אפליקציה כמו MyApp.exe.
key1["מפתח LocalDumps"] --> g1["הגדרה גלובלית ישירות תחתיו"]
key1 --> a1["מפתח משנה לפי אפליקציה"]
a1 -.-> a2["נוח יותר בפועל"]
איור 4: אותו מפתח, אבל ריכוז לפי מפתח משנה של שם האפליקציה מצמצם את היקף ההשפעה.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe
שלושת הערכים הראשונים לבדיקה הם:
| ערך | משמעות | המלצה ראשונית |
|---|---|---|
DumpFolder |
יעד פלט ה-dump | להקצות תיקייה ייעודית |
DumpCount |
מספר שמורים | להתחיל מ-5 עד 10 |
DumpType |
0=מותאם אישית, 1=מיני, 2=מלא | בהתחלה 2, ואם הגודל בעייתי — 1 |
4.2 דוגמה להגדרה לפי אפליקציה
לדוגמה, עבור MyApp.exe, אם רוצים להשאיר עד 10 dump מלאים תחת C:\CrashDumps\MyApp, אפשר להגדיר כך בהתחלה.
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpFolder /t REG_EXPAND_SZ /d "C:\CrashDumps\MyApp" /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpCount /t REG_DWORD /d 10 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpType /t REG_DWORD /d 2 /f
הדוגמה הזו כוללת ארבע נקודות חשובות.
- מוגבל ל-
MyApp.exeולא גלובלי - יעד הפלט מופרד לתיקייה ייעודית
- בהתחלה full dump
- מספר השמורים מוגבל ל-10
4.3 בדיקה שההגדרה עובדת
אחרי שמכניסים את ההגדרה, בטוח יותר לוודא לפחות פעם אחת בסביבת בדיקה לפני שממתינים להתרחשות טבעית בייצור.
4 הדברים שכדאי לבדוק:
- האם
.dmpנוצר בתיקייה המצופה - האם הגודל תואם את התכנון התפעולי
- האם ניתן לפתוח ב-WinDbg
- האם ה-crash נראה בלוג ה-Application ב-Event Viewer
flowchart TB
accTitle: זרימת האימות אחרי ההגדרה
accDescr: אחרי הכנסת ההגדרה, לפני ההמתנה להתרחשות טבעית בייצור, בודקים פעם אחת בסביבת בדיקה: מפילים בכוונה, בודקים אם ה-dump וגודלו כמצופה, בודקים פתיחה ב-WinDbg, ובודקים את הלוג ב-Event Viewer.
v1["מכניסים את ההגדרה"] --> v2["מפילים בכוונה בסביבת בדיקה"]
v2 --> v3["בודקים אם ה-dump נוצר ומה גודלו"]
v3 --> v4["בודקים אם ניתן לפתוח ב-WinDbg"]
v4 --> v5["בודקים את הלוג ב-Event Viewer"]
איור 5: לפני ההמתנה להתרחשות טבעית בייצור, מוודאים פעם אחת בסביבת בדיקה.
4.4 קוד מינימלי להפלה מכוונת
גם אם אומרים “לוודא”, אי אפשר לחכות לקריסה אמיתית — זה לא בדיקה ממשית. נוח להכין מראש EXE קטן שמפיל את עצמו בכוונה לצורך הבדיקה.
ב-.NET, מספיקה אפליקציית console שרק זורקת unhandled exception. unhandled exception מ-managed ב-.NET מסיים את התהליך, ולכן הוא הופך אוטומטית ליעד עבור WER.
// CrashTest.csproj: <TargetFramework>net8.0</TargetFramework>
using System;
using System.Threading;
internal static class Program
{
private static void Main()
{
Console.WriteLine($"PID={Environment.ProcessId} / 3 秒後に落とします。");
Thread.Sleep(3000);
throw new InvalidOperationException("intentional crash for dump collection test");
}
}
אם רוצים לבדוק את הצד native, קרוב יותר לגרום ל-access violation (0xC0000005). מוסיפים volatile כדי שהאופטימיזציה לא תמחק את הפעולה.
// crash_test.cpp / C++17 / MSVC
int main()
{
volatile int* p = nullptr;
*p = 1; // כאן מתרחש STATUS_ACCESS_VIOLATION
return 0;
}
יש נקודה אחת שקל לפספס כאן.
שם מפתח המשנה של LocalDumps חייב להיות זהה לשם קובץ ה-EXE שמפילים כעת. אם יוצרים רק את המפתח של MyApp.exe ומפילים את CrashTest.exe, ברור שלא ייווצר dump. בזמן הבדיקה, או יוצרים מפתח זמני עבור CrashTest.exe, או בודקים דרך ההגדרה הגלובלית.
flowchart TB
accTitle: המלכודת של התאמת שם מפתח המשנה
accDescr: שם מפתח המשנה של LocalDumps חייב להתאים לשם קובץ ה-EXE שמפילים בפועל, ולכן אם יוצרים רק את המפתח של MyApp.exe ומפילים CrashTest.exe, לא ייווצר dump, ובזמן הבדיקה יוצרים מפתח זמני או בודקים דרך ההגדרה הגלובלית.
t1["יוצרים רק את המפתח של MyApp.exe"] --> t2["מפילים את CrashTest.exe"]
t2 --> t3["לא נוצר dump"]
t3 -.-> t4["מתאימים את שם המפתח לשם ה-EXE שמפילים"]
איור 6: פער בין שם מפתח המשנה לשם ה-EXE הוא מלכודת נפוצה שגורמת לבדיקה להיכשל בשקט.
גם NotMyFault של Sysinternals עולה לעיתים קרובות ככלי “להפיל בכוונה”, אבל הוא מיועד להפיל או לגרום ל-hang למערכת Windows עצמה כדי ליצור dump של מסך כחול, ודורש הרשאת Administrator. עבור אימות LocalDumps של אפליקציית user mode, EXE קטן עצמאי כמו למעלה בטוח וודאי יותר.
5. מקרים שבהם משתמשים ב-ProcDump
לעיתים קרובות WER מספיק, אבל יש גם מקרים שבהם ProcDump שימושי.
- רוצים להימנע ממצב קבוע ברישום
- רוצים לנטר רק תהליך שכבר רץ
- רוצים לנטר רק מההפעלה הבאה ואילך
- רוצים לראות first chance exception
- רוצים לתפוס hang
- רוצים לאסוף לפי performance counter או תנאי מסוים
5.1 האפשרויות הנפוצות
אם מצמצמים לאלה שנפוצות בשלב ההתחלה, מספיק לזכור את אלה כדי להתמודד עם רוב המצבים ב-ProcDump.
| אפשרות | משמעות |
|---|---|
-ma |
full dump |
-mp |
MiniPlus dump |
-mc <Mask> |
dump מותאם אישית. מציינים bitmask הקסדצימלי של MINIDUMP_TYPE |
-e |
dump ב-unhandled exception |
-e 1 |
dump ב-first chance / second chance exception |
-h |
dump בחלון שנתקע |
-w |
המתנה להפעלת התהליך היעד |
-x |
הפעלת התהליך היעד וניטורו |
-n |
מספר ה-dump המרבי |
-accepteula |
אישור אוטומטי של אישור ה-EULA הראשוני |
5.2 דוגמאות פקודה נפוצות
תהליך שכבר רץ, full dump ב-unhandled exception
procdump -accepteula -ma -e 1234 C:\CrashDumps\MyApp
המתנה להפעלה הבאה, full dump ב-unhandled exception
procdump -accepteula -ma -e -w MyApp.exe C:\CrashDumps\MyApp
מפעילים בעצמנו וממשיכים לנטר
procdump -accepteula -ma -e -x C:\CrashDumps\MyApp MyApp.exe
רוצים לתפוס גם first chance exception
procdump -accepteula -ma -n 3 -e 1 MyApp.exe C:\CrashDumps\MyApp
רוצים לתפוס hang
procdump -accepteula -h MyApp.exe C:\CrashDumps\MyApp
5.3 למה -i הוא לא הצעד הראשון
ל-ProcDump יש גם שימוש שבו רושמים אותו כ-postmortem debugger עם -i. זה חזק, אבל חודר להתנהגות המחשב כולו בזמן קריסה, ולכן זה כבד מדי כצעד ראשון בשלב ההתחלה.
לכן, נוח יותר להתחיל מ-הגדרת WER לפי אפליקציה, או מ--w / -x / ציון PID של ProcDump.
flowchart TB
accTitle: למה -i לא הצעד הראשון
accDescr: ה--i של ProcDump הוא שימוש חזק שרושם postmortem debugger, אבל הוא חודר להתנהגות המחשב כולו בזמן קריסה, ולכן בשלב ההתחלה נוח יותר להתחיל מהגדרת WER לפי אפליקציה או מ-w, x, וציון PID של ProcDump.
i1["רישום עם -i של ProcDump"] --> i2["חודר להתנהגות המחשב כולו"]
i2 -.-> i3["כבד מדי לצעד הראשון בשלב ההתחלה"]
i4["מתחילים בהיקף של אפליקציה בודדת"] --> i5["הגדרת WER לפי אפליקציה"]
i4 --> i6["-w, -x, או ציון PID של ProcDump"]
איור 7: מתחילים מכניסה שהיקף השפעתה מוגבל לאפליקציה בודדת.
6. איך חושבים על שימוש ב-MiniDumpWriteDump לאיסוף עצמאי
איסוף עצמאי מתאים למקרים כמו אלה.
- רוצים כפתור “שמור מידע אבחוני” מה-UI
- רוצים לצרף יחד עם ה-dump גם לוגים, הגדרות ו-trace ID
- רוצים לרכז גם תהליכי בן או תהליכי עזר קשורים
- רוצים להוסיף מיסוך או דחיסה ייחודיים לפני העלאה
ה-API המרכזי כאן הוא MiniDumpWriteDump.
עם זאת, יש כאן קצת אופי מיוחד. שתי הנקודות שהכי חשוב לא לפספס בהתחלה הן:
- אם אפשר, לקרוא מתהליך נפרד מזה שנוצר ממנו ה-dump
- להתייחס למשפחת ה-API של DbgHelp כמניחה single-thread
flowchart TB
accTitle: שתי הנקודות שלא כדאי לפספס באיסוף עצמאי
accDescr: באיסוף עצמאי עם MiniDumpWriteDump, שתי הנקודות שחשוב לא לפספס הן לקרוא אם אפשר מתהליך נפרד, ולהתייחס למשפחת DbgHelp כמניחה single-thread.
md1["איסוף עצמאי עם MiniDumpWriteDump"] --> md2["קוראים מתהליך נפרד"]
md1 --> md3["DbgHelp מניח single-thread"]
md2 -.-> md4["מימוש רשלני גורם לתקלה"]
md3 -.-> md4
איור 8: האופי המיוחד של איסוף עצמאי מתרכז בשתי נקודות — מאיפה קוראים ואיזה thread.
7. איך בוחרים בין minidump, full dump וגודל ביניים
זו נקודה שהרבה אנשים מתלבטים בה. הנה טבלה לבחירה מעשית.
| סוג | מתאים למקרה | יתרון | נקודה לתשומת לב |
|---|---|---|---|
| minidump | רוצים להטמיע קודם באופן רחב, רוצים לשתף בקלות | קטן, קל להעברה | חלש בשחזור עומק המצב |
| full dump | רוצים לתת עדיפות לחקירת הסיבה, חשד בגבול native או ב-heap | הרבה מידע נגיש | גדול, סיכון דליפת מידע רגיש גבוה |
| MiniPlus / Custom | mini לא מספיק, full כבד מדי | איזון בין השניים | דורש ידע לכוונון |
ההמלצה למתחילים די פשוטה.
- במחשב פיתוח / בדיקה — full dump
- בסביבת הלקוח — בוחרים בין mini ל-full לפי תנאי התפעול
- כשיש חשד ל-memory corruption, native DLL, COM, P/Invoke, או תקלת מצב אחרי הרצה ארוכה, עדיף לנטות לכיוון full
flowchart TB
accTitle: הבחירה הראשונית בסוג ה-dump
accDescr: במחשב פיתוח או בדיקה בוחרים full dump, בסביבת הלקוח בוחרים בין mini ל-full לפי תנאי התפעול, וכשיש חשד ל-memory corruption, גבול native או תקלת מצב אחרי הרצה ארוכה — נוטים לכיוון full.
e1{"באיזו סביבה אוספים"}
e1 -->|"מחשב פיתוח / בדיקה"| f1["full dump"]
e1 -->|"סביבת לקוח"| f2["mini או full לפי תנאי תפעול"]
f2 -.->|"חשד ל-corruption או גבול native"| f1
איור 9: כשמתלבטים, קובעים לפי הסביבה, וככל שהחשד חזק יותר — נוטים ל-full.
7.1 איך בפועל מציינים MiniPlus / Custom
רק לגבי השורה השלישית בטבלה, אופן הציון קצת פחות ברור, ולכן נוסיף הבהרה.
במקרה של WER LocalDumps, קובעים את DumpType ל-0 (מותאם אישית), ומכניסים ל-CustomDumpFlags שילוב סיביות של MINIDUMP_TYPE. CustomDumpFlags נבדק רק כש-DumpType=0, וברירת המחדל היא 0x00000121 (שילוב של MiniDumpWithDataSegs, MiniDumpWithUnloadedModules ו-MiniDumpWithProcessThreadData).
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpType /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v CustomDumpFlags /t REG_DWORD /d 0x121 /f
במקרה של ProcDump, -mp הוא MiniPlus, ו--mc <Mask> הוא מותאם אישית.
procdump -accepteula -mp -e MyApp.exe C:\CrashDumps\MyApp
MiniPlus, למרות שמו, בתוכן שלו קרוב למדי ל-full. לפי התיעוד, הוא כולל את כל הזיכרון הפרטי (private), וגם את כל ה-image / mapped memory שהוא read/write, ומעליהם מוציא רק את שטח הזיכרון הפרטי המקסימלי אם הוא עולה על 512MB, כדי לצמצם את הגודל. התוצאה היא מצב שבו “מפורט כמו full dump, אבל בגודל של 10%-75% ממנו”.
עם זאת, יש שתי הערות.
- בתהליכי CLR, בגלל מגבלות בניפוי באגים, גם ציון
-mpיגרום לאיסוף כ-full (-ma). לצפות לצמצום גודל דרך MiniPlus באפליקציית .NET לרוב לא יתממש - אם המניע לצמצום הגודל הוא “רוצים להפחית דליפת מידע רגיש”, עדיף לחשוב לכיוון minidump ולא לכיוון MiniPlus — זה ישיר יותר
flowchart TB
accTitle: המיקום והמגבלה של MiniPlus
accDescr: MiniPlus כולל כמעט את כל הזיכרון הפרטי, מוציא רק אזורי זיכרון פרטי ענקיים, ולכן קטן ומפורט יותר מ-full, אבל בתהליכי CLR הוא נאסף כ-full בכל זאת.
mp1["איסוף עם MiniPlus"] --> mp2["כולל כמעט את כל הזיכרון הפרטי"]
mp2 --> mp3["מוציא רק אזורי זיכרון פרטי ענקיים"]
mp3 --> mp4["קטן יותר ומפורט יותר מ-full"]
mp1 -.->|"במקרה של תהליך CLR"| mp5["נאסף בפועל כ-full"]
איור 10: תוכן MiniPlus קרוב ל-full, ובאפליקציית .NET לא מקבלים את צמצום הגודל.
8. דברים שכדאי לקבוע מראש בתפעול
איסוף dump נוטה להיכשל בגלל תפעול הרבה יותר מאשר בגלל המימוש. הנה הדברים שכדאי לקבוע מראש.
8.1 איך שומרים PDB וקבצים בינאריים
זו הנקודה הכי חשובה.
- הגרסה המדויקת של ה-EXE / DLL שהופצו
- ה-PDB התואם לגרסה הזו
- ה-commit / pipeline של הבנייה שממנו נוצר
- מידע גרסה של המתקין וקבצי ההפצה
8.2 לאן מוציאים וכמה שומרים
full dump יכול להיות גדול למדי. בטוח יותר לקבוע מראש את יעד הפלט ואת מדיניות השמירה.
- לא להשאיר אחסון ישירות תחת כונן המערכת
- להפריד לתיקייה ייעודית
- להגביל עם
DumpCountאו-n - להפריד בין אחסון ראשוני לאחסון ארוך טווח
8.3 מי רשאי לצפות
ל-full dump יש סיכוי שיתערבב בו מידע רגיש או מידע אישי.
- הגדרות ב-plaintext
- connection string
- token או credentials
- מידע עסקי שטופל ממש לפני כן
- נתיבי קבצים או שמות משתמשים
לכן, יש צורך לקבוע גם “מי רשאי לגעת” יחד עם תכנון “האיסוף” עצמו.
flowchart TB
accTitle: 3 דברים שקובעים מראש בתפעול
accDescr: באיסוף crash dump, שנוטה להיכשל בגלל תפעול יותר מאשר בגלל מימוש, קובעים מראש את שמירת ה-PDB והקבצים הבינאריים, את יעד הפלט ומספר השמורים, ואת מדיניות הגישה של מי רשאי לצפות.
op1["שמירת PDB וקבצים בינאריים"] --> op4["קובעים מראש"]
op2["יעד פלט ומספר שמורים"] --> op4
op3["מי רשאי לצפות"] --> op4
op4 -.-> op5["נוטה להיכשל יותר בתפעול מאשר במימוש"]
איור 11: כישלון באיסוף dump נובע לרוב מהיעדר החלטות תפעוליות מראש.
9. מסלול הניתוח המהיר ביותר אחרי שהתקבל dump
אחרי שמקבלים dump, מה שעושים ראשית פשוט למדי.
9.1 מתקינים את WinDbg
היום קל להתקין את WinDbg דרך Microsoft Store או winget.
winget install Microsoft.WinDbg
9.2 פותחים את ה-dump
windbg -z C:\CrashDumps\MyApp\MyApp_YYMMDD_HHMMSS.dmp
שם הקובץ כאן הוא השם שברירת המחדל של ProcDump נותנת. שם ברירת המחדל של ProcDump הוא PROCESSNAME_YYMMDD_HHMMSS.dmp, ואפשר להשתמש כמציין החלפה ב-PROCESSNAME, PID, EXCEPTIONCODE, YYMMDD, HHMMSS.
מצד שני, WER LocalDumps יוצר קבצים עם שם שונה מ-ProcDump. כללי השם לא מפורטים ב-Microsoft Learn, ולכן במקום לנחש את השם, ודאי יותר להסתכל על תיקיית הפלט ממוינת לפי תאריך עדכון.
dir /o-d "C:\CrashDumps\MyApp\*.dmp"
אם לא הגדרתם DumpFolder, יעד ברירת המחדל הוא %LOCALAPPDATA%\CrashDumps. עם זאת, קריסה של שירות יוצאת לתיקיית הפרופיל של חשבון ההרצה. עבור שירות System, זה %WINDIR%\System32\Config\SystemProfile, ועבור Network Service / Local Service, זה תחת %WINDIR%\ServiceProfiles. אם נדמה ש”ה-dump לא נוצר”, זה המקום הראשון לחשוד בו.
flowchart TB
accTitle: איפה מחפשים כשה-dump לא נמצא
accDescr: כשלא הגדירו DumpFolder, ברירת המחדל היא CrashDumps תחת LOCALAPPDATA, וקריסה של שירות יוצאת לתיקיית הפרופיל של חשבון ההרצה, ולכן כשה-dump לא נמצא, שם הוא המקום הראשון לחשוד בו.
fq1["ה-dump לא נמצא"] --> fq2{"באיזו צורה זה רץ"}
fq2 -->|"אפליקציה רגילה"| fp1["CrashDumps תחת LOCALAPPDATA"]
fq2 -->|"שירות"| fp2["תיקיית הפרופיל של חשבון ההרצה"]
fp2 -.-> fp3["SystemProfile או ServiceProfiles"]
איור 12: יעד ברירת המחדל שונה לפי החשבון, ולכן חושדים קודם בהיכן מחפשים.
9.3 מגדירים symbols
קודם מפעילים גישה ל-symbols הציבוריים של Microsoft, ואז מוסיפים את מיקום ה-PDB שלכם.
.symfix C:\Symbols\Microsoft
.sympath+ C:\Symbols\MyApp
.reload
9.4 קודם רואים את הניתוח האוטומטי
!analyze -v
ואז, בודקים לפי הסדר:
- מה קוד ה-exception
- מהו ה-faulting module
- עד כמה הקוד שלכם נראה ב-call stack
- האם יש המתנה או חסימה חשודה בשרשורים אחרים חוץ מה-thread של ה-exception
flowchart TB
accTitle: מסלול הניתוח המהיר ביותר אחרי שהתקבל dump
accDescr: מתקינים WinDbg, פותחים את ה-dump, מגדירים symbols ציבוריים ואת ה-PDB שלכם, ואז רואים ראשית את הניתוח האוטומטי של analyze -v, ואחר כך בודקים בסדר את קוד ה-exception, את ה-faulting module, את הופעת הקוד שלכם ואת החסימות ב-threads אחרים.
an1["מתקינים WinDbg"] --> an2["פותחים את ה-dump"]
an2 --> an3["מגדירים symbols ו-PDB"]
an3 --> an4["קודם רואים ניתוח אוטומטי"]
an4 --> an5["קוראים בסדר את קוד ה-exception ואת ה-call stack"]
איור 13: פתיחה, מעבר דרך ה-symbols, והתחלה בקריאת הניתוח האוטומטי — זהו המסלול המהיר ביותר.
10. מוקשים נפוצים
10.1 ה-dump התקבל, אבל אין PDB
זה קורה למדי הרבה. גם אם איסוף ה-dump הצליח, חומר הקריאה חסר. עדיף להכניס את תכנון שמירת ה-PDB באותו זמן שמכניסים את הגדרת האיסוף.
10.2 לא בודקים את ה-ACL של DumpFolder
בשירותים ותהליכים עם הפרדת הרשאות, קל שכאן ייכשל בשקט. קודם מוודאים אם “התהליך הזה באמת יכול לכתוב”. גם Microsoft Learn כותב שאם משתמשים בנתיב שאינו ברירת המחדל, יש לוודא ש”ל-ACL יש הרשאה שהתהליך שקרס יכול לכתוב אליה”.
את ה-ACL הנוכחי אפשר לראות עם icacls.
icacls C:\CrashDumps\MyApp
אם חסרה הרשאת כתיבה, מוסיפים M (שינוי) לחשבון ההרצה. תיקיית ה-dump זקוקה לאותה הרשאה גם עבור הקבצים תחתיה, ולכן מוסיפים (OI) ו-(CI) כדי שההרשאה תעבור בירושה.
rem לדוגמה: שירות שרץ תחת Network Service
icacls C:\CrashDumps\MyApp /grant "NT AUTHORITY\NETWORK SERVICE:(OI)(CI)M"
(OI) הוא ציון להעביר את ה-ACE בירושה לקבצים תחתיה, ו-(CI) להעביר בירושה לתיקיות תחתיה. היקף הירושה הוא בעצם “מי יכול לקרוא את ה-dump”, ולכן לפני שמוסיפים אותה כדאי לוודא שוב שהיא לא סותרת את המדיניות שנקבעה בפרק 8.3.
flowchart TB
accTitle: זרימת בדיקת ה-ACL של DumpFolder
accDescr: בשירותים ותהליכים עם הפרדת הרשאות קל שהכתיבה תיכשל בשקט, ולכן בודקים את ה-ACL הנוכחי עם icacls, ואם צריך מוסיפים לחשבון ההרצה הרשאת שינוי עם ירושה, ומתאימים את היקף הירושה למדיניות הצפייה.
ac1["בודקים את ה-ACL הנוכחי עם icacls"] --> ac2{"חשבון ההרצה יכול לכתוב?"}
ac2 -->|"לא יכול"| ac3["מוסיפים הרשאת שינוי עם ירושה"]
ac2 -->|"יכול"| ac4["ממשיכים כמו שהוא"]
ac3 -.-> ac5["מתאימים את היקף הירושה למדיניות הצפייה"]
איור 14: בדיקת יכולת הכתיבה ובדיקת מי יכול לקרוא נעשות באותו מקום.
10.3 להמשיך להוציא full dump ישירות לכונן המערכת בייצור
זו תקלת נפח קלאסית. מגבילים מראש מספר שמורים ומפרידים את יעד הפלט.
10.4 לנסות לראות גם hang רק עם WER
WER LocalDumps חזק בעיקר לקריסות. יש מצבים שבהם hang ו-first chance exception מתאימים יותר ל-ProcDump.
10.5 להשאיר -e 1 פעיל תמיד ולהיגרר לסופת exceptions
first chance exception נוח, אבל בדרך כלל יש הרבה מהם. מציאותי להגביל את הכמות, להשאיר פעיל לזמן קצר, ולהגביל את היעד.
11. סיכום
crash dump הוא נקודת תצפית חזקה מאוד עבור תקלות עם שיעור שחזור נמוך. בפרט באפליקציית Windows שבה מעורבים COM, P/Invoke, native DLL או הרצה ארוכה, יש ערך בכך שקובעים מראש “מה נשאר כשזה נופל”.
הסדר המומלץ פשוט.
- קודם מכניסים WER LocalDumps לפי אפליקציה
- מוסיפים ProcDump אם צריך
- אם רוצים שליטה נוספת, משתמשים ב-
MiniDumpWriteDumpבהנחה של תהליך נפרד
אם מתקדמים בסדר הזה, קשה לטעות בגדול.
12. מקורות
-
[ユーザーモード ダンプの収集 - Win32 apps Microsoft Learn](https://learn.microsoft.com/ja-jp/windows/win32/wer/collecting-user-mode-dumps) -
[ProcDump v11.1 - Sysinternals Microsoft Learn](https://learn.microsoft.com/en-us/sysinternals/downloads/procdump) -
[MiniDumpWriteDump function (minidumpapiset.h) - Win32 Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump) -
[User-mode dump files - Windows drivers Microsoft Learn](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/user-mode-dump-files) -
[ユーザー モード ダンプ ファイルの分析 - Windows drivers Microsoft Learn](https://learn.microsoft.com/ja-jp/windows-hardware/drivers/debugger/analyzing-a-user-mode-dump-file) -
[Windows デバッガーをインストールする - Windows drivers Microsoft Learn](https://learn.microsoft.com/ja-jp/windows-hardware/drivers/debugger/) -
[Symbol path for Windows debuggers - Windows drivers Microsoft Learn](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/symbol-path) -
[!analyze (WinDbg) - Windows drivers Microsoft Learn](https://learn.microsoft.com/en-us/windows-hardware/drivers/debuggercmds/-analyze) -
[Troubleshoot processes by using Task Manager - Windows Server Microsoft Learn](https://learn.microsoft.com/en-us/troubleshoot/windows-server/support-tools/support-tools-task-manager) -
[Enabling Postmortem Debugging - Windows drivers Microsoft Learn](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/enabling-postmortem-debugging) -
[MINIDUMP_TYPE enumeration (minidumpapiset.h) - Win32 Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ne-minidumpapiset-minidump_type) -
[icacls - Windows commands Microsoft Learn](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/icacls) -
[NotMyFault - Sysinternals Microsoft Learn](https://learn.microsoft.com/en-us/sysinternals/downloads/notmyfault)
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
איך משאירים לוגים ו-crash dump כשאפליקציית Windows קורסת
איך משלבים לוג רגיל, fatal crash marker, WER LocalDumps ותהליך watchdog, כדי שאפילו כשאפליקציית Windows קורסת מ-exception לא צפוי או מ-bu...
Time Travel Debugging — להקליט ולהריץ אחורה באגים שלא משתחררים באפליקציות ארוכות-ריצה
באג פעם בחודש משאיר ב-crash dump רק את התוצאה. מקליטים ומריצים אחורה את הביצוע עם WinDbg Time Travel Debugging (TTD): TTD.exe, ring buffe...
מה Not Responding באמת אומר — איך Windows מחליט שיש hang, ואיך לתכנן אפליקציות שלא נתקעות
Windows מסמן window כ-Not Responding אחרי 5 שניות בלי שליפת message ומציג ghost window: השיפוט, סיבות ה-hang, תכנון ה-UI thread, והחקירה.
WPR/WPA בפועל — מבוא לחקירת "כל ה-PC איטי" על פני כל המערכת
חוקרים PC איטי או startup איטי ש-Task Manager לא מסביר עם ETW trace ברמת ה-OS: מצלמים ב-wpr.exe, ואז קוראים CPU, המתנות ו-I/O דיסק ב-WPA.
Handle leak באפליקציית מצלמה תעשייתית שקורסת אחרי ריצה ארוכה
איך בוחנים אפליקציית Windows שקורסת פתאום אחרי ריצה ארוכה, דרך מקרה של אפליקציית בקרת מצלמה תעשייתית: איך מוצאים handle leak ואיך מתכננים...
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
חקירת תקלות ואיתור גורמים
איתור שורש הבעיה בעזרת שילוב של crash dump, לוגים ותנאי שחזור מתאים לחקירת תקלות. בפרט בקריסות שקורות רק בשטח או תקלות אחרי הרצה ארוכה, עצם תכנון התצפית הוא קריטי.
ייעוץ טכני וסקירת תכנון
אם רוצים ליישר קו מה אוספים בסביבת ייצור, איך משלבים dump ולוגים בתכנון, ועד מדיניות הרשאות ואחסון, זה נושא שקל להתקדם בו כייעוץ טכני ו-design review.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- מה זה crash dump? מה אפשר ללמוד ממנו?
- זהו שמירה לקובץ של מצב התהליך ברגע הקריסה — כמו תצלום סטילס מזירת תאונה. אפשר לבדוק בדיעבד את קוד ה-exception, את ה-thread שקרס ואת ה-call stack שלו, את המודולים שהיו טעונים, ובהתאם לכמות הזיכרון שנכלל אף את תוכן האובייקטים ב-heap. מצד שני, ציר הזמן שהוביל לשם, והמצב החיצוני של תקשורת וציוד, נוטים להיות חסרים — ולכן בפועל משלבים dump עם לוגים ו-heartbeat.
- איפה מגדירים את LocalDumps של WER?
- מגדירים תחת מפתח הרישום HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps. בפועל נוח יותר לרכז את ההגדרה במפתח משנה לפי אפליקציה, כמו MyApp.exe, ולא בהגדרה גלובלית. שלושת הערכים שכדאי לבדוק ראשונים הם DumpFolder ליעד הפלט, DumpCount למספר השמורים, ו-DumpType לסוג ה-dump — כך אפשר להשאיר dump מקומי אחרי קריסה בלי להפיץ כלי נוסף.
- כדאי לבחור minidump או full dump?
- קו מנחה: במחשבי פיתוח ובדיקה — full dump (DumpType=2), ובסביבת הלקוח — בוחרים minidump (DumpType=1) או full dump לפי היקף וצרכי סודיות. כשיש חשד ל-memory corruption, native DLL, COM, P/Invoke, או תקלת מצב אחרי הרצה ארוכה, עדיף לנטות לכיוון full. עם זאת, ה-full dump גדול בגודלו, ויש בו סיכון שמידע רגיש כמו connection string או token יתערב, ולכן צריך לקבוע מראש מיקום אחסון, מספר שמורים והרשאות גישה.
- מתי משתמשים ב-ProcDump?
- מכיוון ש-WER LocalDumps מיועד בעיקרו לקריסות, ProcDump מתאים כשרוצים לראות גם hang או first chance exception, כשרוצים להימנע ממצב קבוע ברישום, או כשרוצים לנטר רק תהליך שכבר רץ. האפשרויות האופייניות הן -ma ל-full dump, -e לאיסוף ב-unhandled exception, -h לזיהוי hang, ו-w להמתנה להפעלה. -e 1 שמכוון ל-first chance exception נוטה לייצר כמות גדולה, ולכן מציאותי להשתמש בו לזמן קצר ומוגבל, עם הגבלת -n.