לדלג לתוכן

דיבוג קרנל - מדריך בסיס למי שרוצה להבין למה זה כל כך שונה

דיבוג תוכנית רגילה במרחב המשתמש מרגיש טבעי - מריצים דיבאגר, שמים נקודת עצירה, והתוכנית עוצרת בדיוק שם. דיבוג קרנל שובר את ההנחה הבסיסית הזאת. אי אפשר פשוט "לעצור" את הקרנל באמצע ולחכות, כי הקרנל הוא בדיוק מה שמריץ את כל השאר, כולל את הדיבאגר עצמו. בגלל זה, דיבוג קרנל דורש כלים וגישה שונים לגמרי מדיבוג רגיל.

printk - ההדפסה הכי בסיסית ועדיין הכי שימושית

הכלי הכי פשוט לדיבוג קרנל הוא printk, המקבילה הישירה של printf בתוך קוד קרנל. ההבדל המרכזי הוא שהודעות printk לא נכתבות למסך רגיל, אלא לבאפר פנימי בקרנל, שאפשר לקרוא אותו עם הפקודה dmesg. לכל הודעת printk יש גם רמת חומרה - מהודעת דיבוג רגילה ועד הודעת חירום, מה שמאפשר לסנן ולראות רק את מה שרלוונטי.

זה נשמע פרימיטיבי, אבל זה בדיוק היתרון שלו - printk עובד כמעט בכל מצב, כולל מצבים שבהם רוב כלי הדיבוג המתקדמים יותר לא יכולים לפעול, למשל בשלב מוקדם מאוד של האתחול, לפני שרוב הקרנל בכלל הוקם.

Oops ו-panic - כשהקרנל עצמו נתקל בבעיה

כשהקרנל נתקל בשגיאה חמורה, כמו גישה לא חוקית לזיכרון בתוך קוד קרנל, הוא מדפיס הודעת "Oops" - דוח מפורט שכולל את מצב הרגיסטרים, ואת ה-stack trace, רצף הפונקציות שהובילו לבעיה. במקרים רבים, הקרנל מנסה להמשיך לרוץ אחרי Oops, כי הבעיה הייתה מוגבלת לחלק ספציפי. אבל אם הבעיה חמורה מספיק, הקרנל נכנס למצב panic - הוא עוצר את עצמו לגמרי, כי המשך ריצה עלול לגרום לנזק חמור יותר, כמו כתיבה לא נכונה לדיסק.

קריאה נכונה של הודעת Oops דורשת לפעמים לפענח כתובות בחזרה לשמות פונקציות, בעזרת קובץ שנקרא System.map או דרך /proc/kallsyms, שממפים כתובות זיכרון לשמות סמלים בקרנל.

ftrace - מעקב אחר מה שהקרנל בפועל עושה

מעבר להדפסות ידניות, לינוקס כולל מערכת מעקב מובנית שנקראת ftrace, שמאפשרת לראות בזמן אמת אילו פונקציות בקרנל נקראות, כמה זמן כל אחת לוקחת, ואיזה רצף קריאות מוביל לאן. במקום להוסיף printk בכל מקום חשוד ולקמפל מחדש, ftrace מאפשרת להפעיל מעקב מדויק על פונקציות ספציפיות, בזמן ריצה, בלי לשנות את הקוד בכלל. זה כלי חזק במיוחד לאיתור בעיות ביצועים, לא רק קריסות.

דיבוג מרוחק - כשצריך לעצור את הקרנל באמת

לפעמים אין ברירה, וצריך לעצור את הקרנל באמצע ריצה ולבדוק את מצבו בדיוק כמו דיבאגר רגיל. הפתרון הוא kgdb, מנגנון שמאפשר לחבר דיבאגר חיצוני, gdb, לקרנל שרץ - אבל בדרך כלל לא על אותה מכונה. השיטה הנפוצה ביותר כיום היא להריץ את הקרנל הנבדק בתוך מכונה וירטואלית, למשל QEMU, ולחבר אליה דיבאגר מהמכונה המארחת. כך אפשר לעצור את הקרנל לגמרי, לשים נקודות עצירה, ולבדוק מבני נתונים פנימיים, בלי לסכן את המערכת האמיתית שבה עובדים.

למה זה שונה כל כך מדיבוג רגיל

ההבדל המרכזי הוא שאין "מעליו" אף אחד שיכול לעצור את הקרנל ולתת לכם לבדוק אותו בבטחה, מלבד שכבת וירטואליזציה או חומרה חיצונית. זו הסיבה שדיבוג קרנל אמיתי, בניגוד לדיבוג תוכנית רגילה, כמעט תמיד מתבצע בסביבה מבודדת - מכונה וירטואלית או מכשיר פיתוח נפרד, לא ישירות על המערכת שבה עובדים ביום יום.

זה בדיוק סוג המיומנות שאנחנו בונים בקורס ליבת המחשב - איך לגשת ולהבין קוד שרץ ברמה שאין מעליה שום דבר אחר.

ואם הודעת Oops הראשונה שלכם נראית כמו חומה של טקסט לא מובן, יש קהילה שכבר פענחה כמה כאלה.

הצטרפו לקהילה בדיסקורד

לסיכום

דיבוג קרנל דורש חשיבה שונה מדיבוג רגיל, כי אין אפשרות פשוט לעצור את מה שמריץ את כל המערכת. printk ו-dmesg נותנים נקודת התחלה בסיסית, הודעות Oops ו-panic חושפות מה קרה כשמשהו נשבר, ftrace מאפשר מעקב חי אחר התנהגות בלי לשנות קוד, וכשצריך עצירה אמיתית, kgdb מול מכונה וירטואלית הוא הכלי שמאפשר את זה בבטחה.