לדלג לתוכן

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

gcc -g example.c -o example

שלב 2: הרצה בתוך GDB עם pwndbg

gdb ./example

שלב 3: שימוש בפקודות שלמדנו

(gdb) break main
(gdb) run
(gdb) next
(gdb) next
(gdb) print numbers
(gdb) x/5dw &numbers       # הצגת 5 ערכים עשרוניים מהמערך
(gdb) step                  # נכנסים לתוך sum_array
(gdb) info locals           # רואים את total ו-i
(gdb) next
(gdb) next
(gdb) print total           # רואים ערך ביניים
(gdb) info registers        # רואים את כל האוגרים
(gdb) x/20xb $rbp           # מסתכלים על ה-stack frame
(gdb) disass sum_array      # רואים את האסמבלי
(gdb) finish                # יוצאים מהפונקציה
(gdb) print 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;
}

תהליך הדיבוג:

gcc -g bug_simple.c -o bug_simple
gdb ./bug_simple
(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;  -> כאן הקריסה

אם התוכנית קרסה:

(gdb) backtrace             # רואים איפה קרסה
(gdb) print index           # רואים שהוא 10
(gdb) x/5dw &numbers       # רואים שהמערך הוא רק 5 איברים

הבאג:

המערך numbers מוגדר עם 5 איברים (אינדקסים 0 עד 4), אבל הקוד ניגש לאינדקס 10 - שנמצא מחוץ לגבולות המערך. זו גישה לזיכרון שלא שייך למערך, מה שגורם לכתיבה למקום לא מורשה בזיכרון (דריסה של ערכים אחרים על ה-stack או קריסה).

התיקון - להשתמש באינדקס שנמצא בטווח התקין (0 עד 4):

int index = 3;  // אינדקס תקין
numbers[index] = 42;

מצאו ת'באג 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;
}

תהליך הדיבוג:

gcc -g logic_bug.c -o logic_bug
gdb ./logic_bug
(gdb) break main
(gdb) run
(gdb) display i
(gdb) display sum
(gdb) next                  # עוברים על הגדרות המשתנים
(gdb) next
(gdb) next                  # נכנסים ללולאה
(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 = ??? ערך זבל!
(gdb) print numbers[5]      # ערך לא מוגדר - מחוץ למערך

הבאג:

התנאי בלולאה הוא i <= 5 במקום i < 5. המערך מכיל 5 איברים (אינדקסים 0 עד 4), אבל הלולאה רצה גם עם i = 5 - מה שגורם לגישה ל-numbers[5] שנמצא מחוץ לגבולות המערך. זוהי שגיאת off-by-one קלאסית.

הערך ש-numbers[5] מחזיר הוא ערך זבל - מה שנמצא בזיכרון אחרי המערך (סביר שזה חלק מה-stack frame, אולי הערך של sum עצמו או i או כתובת חזרה).

התיקון:

for (int i = 0; i < 5; i++) {  // שינוי <= ל-<