3.9 - דיבוג עם GDB - פתרון
דבגו מה שלא דיבגתם¶
תרגיל זה הוא תרגול חופשי - אין פתרון יחיד. הנה דוגמה לתהליך דיבוג שמכסה את מה שנדרש:
דוגמה לדיבוג קוד C קיים¶
נניח שיש לכם את הקוד הבא שכתבתם בעבר:
#include <stdio.h>
int sum_array(int arr[], int size) {
int total = 0;
for (int i = 0; i < size; i++) {
total += arr[i];
}
return total;
}
int main() {
int numbers[] = {10, 20, 30, 40, 50};
int result = sum_array(numbers, 5);
printf("sum = %d\n", result);
return 0;
}
שלב 1: קומפילציה עם debug symbols¶
שלב 2: הרצה בתוך GDB עם pwndbg¶
שלב 3: שימוש בפקודות שלמדנו¶
(gdb) break main
(gdb) run
(gdb) next
(gdb) next
(gdb) print numbers
(gdb) x/5dw &numbers # display 5 decimal values from the array
(gdb) step # step into sum_array
(gdb) info locals # see total and i
(gdb) next
(gdb) next
(gdb) print total # see intermediate value
(gdb) info registers # see all the registers
(gdb) x/20xb $rbp # looking at the stack frame
(gdb) disass sum_array # see the assembly
(gdb) finish # exit the function
(gdb) print result # see the result
(gdb) continue
הרעיון הוא לתרגל את כל הפקודות: break, run, next, step, finish, continue, print, x, info locals, info registers, disass, ולהבין את הקשר בין קוד ה-C לקוד האסמבלי שנוצר.
מצאו ת'באג¶
הקוד:
// bug_simple.c
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
int index = 10;
numbers[index] = 42;
return 0;
}
תהליך הדיבוג:¶
(gdb) break main
(gdb) run
(gdb) next # int numbers[5] = {1, 2, 3, 4, 5};
(gdb) next # int index = 10;
(gdb) print index
$1 = 10
(gdb) next # numbers[index] = 42; -> the crash happens here
אם התוכנית קרסה:
(gdb) backtrace # see where it crashed
(gdb) print index # see that it's 10
(gdb) x/5dw &numbers # see that the array only has 5 elements
הבאג:¶
המערך numbers מוגדר עם 5 איברים (אינדקסים 0 עד 4), אבל הקוד ניגש לאינדקס 10 - שנמצא מחוץ לגבולות המערך. זו גישה לזיכרון שלא שייך למערך, מה שגורם לכתיבה למקום לא מורשה בזיכרון (דריסה של ערכים אחרים על ה-stack או קריסה).
התיקון - להשתמש באינדקס שנמצא בטווח התקין (0 עד 4):
מצאו ת'באג 2¶
הקוד:
// logic_bug.c
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
int sum = 0;
for (int i = 0; i <= 5; i++) {
sum = sum + numbers[i];
}
return 0;
}
תהליך הדיבוג:¶
(gdb) break main
(gdb) run
(gdb) display i
(gdb) display sum
(gdb) next # stepping through variable definitions
(gdb) next
(gdb) next # entering the loop
(gdb) next # i = 0, sum = 1
(gdb) next # i = 1, sum = 3
(gdb) next # i = 2, sum = 6
(gdb) next # i = 3, sum = 10
(gdb) next # i = 4, sum = 15
(gdb) next # i = 5, sum = ??? garbage value!
(gdb) print numbers[5] # undefined value - out of bounds of the array
הבאג:¶
התנאי בלולאה הוא i <= 5 במקום i < 5. המערך מכיל 5 איברים (אינדקסים 0 עד 4), אבל הלולאה רצה גם עם i = 5 - מה שגורם לגישה ל-numbers[5] שנמצא מחוץ לגבולות המערך. זוהי שגיאת off-by-one קלאסית.
הערך ש-numbers[5] מחזיר הוא ערך זבל - מה שנמצא בזיכרון אחרי המערך (סביר שזה חלק מה-stack frame, אולי הערך של sum עצמו או i או כתובת חזרה).
התיקון: