• اشکال زدایی با GDB اصول استفاده از دستورات دیباگر WinDbg Debugger gdb

    هدف از اشکال زدایی یک برنامه حذف خطاهای کد آن است. برای انجام این کار، به احتمال زیاد باید وضعیت متغیرهای موجود را بررسی کنید زمان بین شروع و اتمام فرآیند تولید، و همچنین خود فرآیند اجرا (به عنوان مثال، ردیابی شاخه های شرطی). در اینجا دیباگر اولین دستیار ما است. البته، C بدون توقف مستقیم برنامه، گزینه های اشکال زدایی زیادی دارد: از printf ساده (3) گرفته تا سیستم های ثبت شبکه ویژه و syslog. در اسمبلر، چنین روش هایی نیز قابل اجرا هستند، اما ممکن است لازم باشد وضعیت رجیسترها، تصاویر RAM و سایر مواردی را که انجام آنها در یک اشکال زدا تعاملی راحت تر است، نظارت کنید. به طور کلی، اگر به زبان اسمبلی بنویسید، بعید است که بدون دیباگر کار کنید.

    اگر از قبل می‌دانید تقریباً چه بخشی از کد را باید بررسی کنید، می‌توانید با شناسایی یک نقطه شکست، اشکال زدایی را شروع کنید. این روش بیشتر مورد استفاده قرار می گیرد: ما یک نقطه شکست تنظیم می کنیم، برنامه را اجرا می کنیم و مرحله به مرحله اجرای آن را طی می کنیم و همزمان متغیرها و رجیسترهای لازم را مشاهده می کنیم. همچنین می‌توانید به سادگی برنامه را تحت یک دیباگر اجرا کنید و لحظه‌ای را که به دلیل نقص تقسیم‌بندی از کار می‌افتد، بگیرید - به این ترتیب می‌توانید متوجه شوید که کدام دستورالعمل سعی در دسترسی به حافظه دارد، به متغیری که باعث خطا می‌شود نگاهی دقیق‌تر بیندازید، و غیره بر. حالا می توانید دوباره این کد را بررسی کنید، مرحله به مرحله آن را مرور کنید و کمی قبل از لحظه خرابی یک نقطه شکست تعیین کنید.

    بیایید با یک چیز ساده شروع کنیم. بیایید برنامه Hello world را بگیریم و با استفاده از سوئیچ کامپایلر -g آن را با اطلاعات اشکال زدایی کامپایل کنیم:

    $ gcc -g hello.s -o سلام $

    gdb را راه اندازی کنید:

    $ gdb ./hello GNU gdb 6.4.90-debian حق چاپ (C) 2006 Free Software Foundation, Inc. GDB یک نرم افزار رایگان است که تحت پوشش مجوز عمومی عمومی گنو است و شما می توانید آن را تغییر دهید و/یا نسخه هایی از آن را تحت شرایط خاص توزیع کنید. برای مشاهده شرایط عبارت "show copying" را تایپ کنید. مطلقاً هیچ ضمانتی برای GDB وجود ندارد. برای جزئیات، عبارت "نمایش گارانتی" را تایپ کنید. این GDB به عنوان "i486-linux-gnu" پیکربندی شده است... با استفاده از کتابخانه میزبان libthread_db "/lib/tls/libthread_db.so.1". (gdb)

    GDB شروع به کار کرده است، برنامه مورد مطالعه را بارگذاری کرده، یک اعلان (gdb) نمایش می دهد و منتظر دستورات است. می خواهیم برنامه را «گام به گام» (حالت تک مرحله ای) طی کنیم. برای این کار باید دستوری را که برنامه باید در آن متوقف شود را مشخص کنید. می توانید یک زیربرنامه را مشخص کنید - سپس توقف قبل از شروع اجرای دستورالعمل های این زیربرنامه انجام می شود. همچنین می توانید نام فایل و شماره خط را مشخص کنید.

    (gdb) b نقطه شکست اصلی 1 در 0x8048324: فایل hello.s، خط 17. (gdb)

    b کوتاه برای استراحت است. همه دستورات در GDB را می توان به اختصار تا زمانی که ابهام ایجاد نمی کند. برنامه را با دستور run اجرا می کنیم. از همین دستور برای راه اندازی مجدد برنامه ای که قبلا در حال اجرا بود استفاده می شود.

    (gdb) r شروع برنامه: /tmp/hello Breakpoint 1, main () at hello.s:17 17 movl $4, %eax /* put system call number write = 4 زبان فعلی: auto; در حال حاضر asm (gdb)

    GDB برنامه را متوقف کرده و منتظر دستورات است. شما دستوری را در برنامه خود می بینید که در مرحله بعدی اجرا می شود، نام تابعی که در حال اجرا است، نام فایل و شماره خط. برای اجرای گام به گام دو دستور step (به اختصار s) و next (به اختصار n) داریم. دستور step با وارد کردن بدنه زیر روال ها برنامه را اجرا می کند. دستور بعدی فقط دستورالعمل های زیربرنامه فعلی را انجام می دهد.

    (gdb) n 20 movl $1، %ebx /* اولین پارامتر به ثبت %ebx می رود */ (gdb)

    بنابراین دستور خط 17 اجرا می شود و انتظار داریم عدد 4 در ثبات %eax باشد و برای چاپ عبارات مختلف روی صفحه از دستور print (به اختصار p ) استفاده می کنیم. برخلاف دستورات اسمبلر، GDB هنگام نوشتن ثبات از علامت $ به جای % استفاده می کند. بیایید ببینیم در ثبت %eax چه چیزی وجود دارد:

    (gdb) p $eax $1 = 4 (gdb)

    در واقع 4! GDB تمام عبارات خروجی را شماره گذاری می کند. اکنون اولین عبارت ($1) را می بینیم که برابر با 4 است. اکنون این عبارت با نام قابل دسترسی است. شما همچنین می توانید محاسبات ساده انجام دهید:

    (gdb) p $1 $2 = 4 (gdb) p $1 + 10 $3 = 14 (gdb) p 0x10 + 0x1f $4 = 47 (gdb)

    در حالی که با دستور print بازی می کردیم، قبلاً فراموش کرده بودیم که کدام دستور بعدی اجرا می شود. دستور info line اطلاعات مربوط به خط مشخص شده کد را نمایش می دهد. بدون آرگومان، اطلاعات مربوط به خط فعلی را چاپ می کند.

    (gdb) خط اطلاعات خط 20 "hello.s" از آدرس 0x8048329 شروع می شود و به 0x804832e ختم می شود . (gdb)

    دستور list (به اختصار l ) کد منبع برنامه شما را نمایش می دهد. می توانید آن را به عنوان آرگومان منتقل کنید:

    • شماره خط- شماره خط در فایل فعلی؛
    • file:line_number- شماره خط در فایل مشخص شده؛
    • function_name- نام تابع، در صورت عدم وجود ابهام؛
    • فایل:function_name- نام تابع در فایل مشخص شده؛
    • *نشانی- آدرس موجود در حافظه که دستورالعمل مورد نیاز در آن قرار دارد.

    اگر یک آرگومان را ارسال کنید، دستور list 10 خط کد منبع را در اطراف آن مکان چاپ می کند. با ارسال دو آرگومان، خط شروع و خط پایان لیست را مشخص می کنید.

    (gdb) l main 12 خارج از این فایل */ 13 .type main, @function /* main - function (نه داده) */ 14 15 16 main: 17 movl $4, %eax /* put system call number 18 write = 4 در ثبات %eax */ 19 20 movl $1، %ebx /* اولین پارامتر را در ثبات 21 %ebx قرار دهید. شرح فایل شماره 22 stdout = 1 */ (gdb) l *$eip 0x8048329 در hello.s:20 است. 15 16 main: 17 movl $4, %eax /* قرار دادن شماره تماس سیستم 18 write = 4 در ثبات %eax */ 19 20 movl $1, %ebx /* اولین پارامتر را در ثبات 21 %ebx قرار دهید. توصیفگر فایل شماره 22 stdout = 1 */ 23 movl $hello_str, %ecx /* پارامتر دوم را در ثبات 24 %ecx قرار دهید. اشاره گر به یک رشته */ (gdb) l 20, 25 20 movl $1, %ebx /* اولین پارامتر را در ثبات 21 %ebx قرار دهید. توصیفگر فایل شماره 22 stdout = 1 */ 23 movl $hello_str, %ecx /* پارامتر دوم را در ثبات 24 %ecx قرار دهید. اشاره گر به رشته */ 25 (gdb)

    این دستور را به خاطر بسپارید: لیست *$eip . با کمک آن، شما همیشه می توانید کد منبع را در اطراف دستورالعمل در حال اجرا مشاهده کنید. بیایید برنامه خود را بیشتر اجرا کنیم:

    (gdb) n 23 movl $hello_str، %ecx /* پارامتر دوم را در ثبات %ecx (gdb) n 26 movl $hello_str_length، %edx /* پارامتر سوم را در ثبات %edx قرار دهید (gdb)

    آیا فشار دادن n هر بار خسته کننده نیست؟ اگر فقط Enter را فشار دهید، GDB آخرین دستور را تکرار می کند:

    (gdb) 29 int $0x80 /* قطع تماس 0x80 */ (gdb) سلام، دنیا! 31 movl $1، %eax /* خروجی شماره تماس سیستم = 1 */ (gdb)

    یکی دیگر از دستورات مفید، ثبت اطلاعات است. البته می توان آن را به i r کوتاه کرد. شما می توانید آن را یک پارامتر ارسال کنید - لیستی از ثبات هایی که باید چاپ شوند. به عنوان مثال، زمانی که اجرا در حالت محافظت شده رخ می دهد، بعید است که به مقادیر ثبات های بخش علاقه مند باشیم.

    (gdb) اطلاعات ثبت می‌کند eax 0xe 14 ecx 0x804955c 134518108 edx 0xe 14 ebx 0x1 1 esp 0xbfabb55c 0xbfabb55c ebp 0xbfabb5a8 0xbsfabb60 -80bfabbx0 08566592 eip 0x804833a 0x804833a eflags 0x246 [ PF ZF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) info registered eax eebipax ecxes e 14 ecx 0x804955c 134518108 edx 0xe 14 ebx 0x1 1 esp 0xbfabb55c 0xbfabb55c ebp 0xbfabb5a8 0xbfabb5a8 esi 0x0 0 edi 0xb7f6bcc0 -1208566592 eip 0x804833a 0x38 flags 0x246 [PF ZF IF] (gdb)

    بنابراین، علاوه بر ثبت نام، ما نیز داریم

    G.D.B.به برنامه‌های دیباگر «هوشمند» اشاره دارد، یعنی برنامه‌هایی که کد را «درک» می‌کنند و می‌توانند آن را خط به خط اجرا کنند، مقادیر متغیرها را تغییر دهند، نقاط شکست و شرایط توقف را تنظیم کنند... در یک کلام، همه چیز را انجام دهند. تا توسعه دهنده بتواند عملکرد صحیح برنامه خود را بررسی کند.

    G.D.B.در بسیاری ساخته شده است یونیکسمانند سیستم ها و می تواند چندین زبان برنامه نویسی را اشکال زدایی کند. شی در میان آنهاست.

    تماس گرفتن G.D.B.دستور را در ترمینال وارد کنید

    Gdb [نام برنامه ای که می خواهید اشکال زدایی کنید]

    برای خروج از G.D.B.: دستور را وارد کنید

    ترک یا C–d

    سایر دستورات مهم GDB

    run [program command line arguments] برنامه را برای اجرا اجرا کنید. شکست [شماره خط/نام تابع] نقطه توقف برنامه را در یک خط یا تابع خاص تنظیم کنید. next بدون رفتن به داخل توابع به خط بعدی بروید. مرحله برو به خط بعدی اگر یک تابع در خط وجود دارد، به داخل آن بروید. list چاپ بخشی از کد برنامه (چند خط در اطراف مکانی که نقطه در حال حاضر تنظیم شده است) چاپ [ متغیر] مقدار متغیر را روی صفحه چاپ کنید. info locals مقادیر فعلی همه متغیرهای محلی را در داخل یک حلقه، تابع و غیره چاپ کنید. display [متغیر] نمایش مقدار یک متغیر در هر مرحله اشکال زدایی. کمک نمایش لیستی از تمام دستورات GDB.

    بیایید نحوه کار با GDB با استفاده از برنامه caesar.c را که به احتمال زیاد هفته گذشته نوشتید، بررسی کنیم. ما آن را روی نسخه خودمان آزمایش خواهیم کرد، بنابراین نتایج شما ممکن است بسته به اجرا کمی متفاوت باشد.

    بنابراین، به پوشه pset2 بروید (ما فکر می کنیم قبلاً به یاد دارید که چگونه این کار را انجام دهید) در "Cs50 Virtual Laboratory" یا CS50 IDE. دستور را وارد کنید:

    Gdb /سزار

    برنامه سزار یک عملکرد دارد، اصلی. بیایید نقطه شکست برنامه را در تابع اصلی تنظیم کنیم:

    اصلی شکستن

    بیایید برنامه سزار را با آرگومان "3" اجرا کنیم:

    اجرا 13

    فرض کنید باید مقدار argc را بررسی کنیم:

    چاپ argc

    این چیزی است که باید در پنجره ترمینال به نظر برسد:

    حال با استفاده از دستور بعدی برنامه را مرحله به مرحله اجرا می کنیم. بیایید چندین بار این کار را انجام دهیم.

    در اینجا به متغیر کلید یک مقدار اختصاص داده می شود. بیایید بررسی کنیم که چه معنایی برای این خط دارد:

    اولین باری که بعد فراخوانی می شود، متغیر کلید روی "0" تنظیم می شود. اگر عدد 3 را وارد کنیم چرا اینطور است؟ نکته اینجاست که دستور هنوز اجرا نشده است. وقتی چند بار بعدی را وارد می کنید، برنامه از شما می خواهد متن را وارد کنید.

    با اجرای مجدد دستور بعدی با یک شرط به داخل حلقه می رویم.

    بیایید در مورد دیباگرهای مایکروسافت ویندوز صحبت کنیم. تعداد زیادی از آنها وجود دارد، فقط OllyDbg مورد علاقه همه را به یاد بیاورید، SoftIce زمانی محبوب اما اکنون تقریباً مرده، و همچنین Sycer، Immunity Debugger، x64dbg و تعداد بی شماری از دیباگرهای تعبیه شده در IDE. طبق مشاهدات من، همه WinDbg را دوست ندارند. من فکر می کنم این عمدتا به دلیل رابط دستور دیباگر است. طرفداران لینوکس و FreeBSD بدون شک آن را دوست دارند. اما کاربران هاردکور ویندوز آن را عجیب و ناخوشایند می دانند. در همین حال، از نظر عملکرد، WinDbg به هیچ وجه کمتر از سایر دیباگرها نیست. حداقل، قطعا بدتر از GDB یا LLDB کلاسیک نیست. این چیزی است که امروز خواهیم دید.

    در دنیای ویندوز، همه چیز، طبق معمول، کمی به هم ریخته است. نصب کننده رسمی WinDbg را می توان از وب سایت MS دانلود کرد. علاوه بر WinDbg، این نصب کننده آخرین نسخه دات نت فریم ورک را نیز نصب می کند و بدون درخواست، سیستم را راه اندازی مجدد می کند. پس از نصب، این واقعیت نیست که دیباگر اصلاً کار می کند، به خصوص در نسخه های قدیمی ویندوز. بنابراین بهتر است یک بیلد غیر رسمی WinDbg یا . فوریمن به شما توصیه می کنم از یکی از این نسخه ها استفاده کنید - این ساده ترین و سریع ترین راه برای نصب WinDbg است.

    دو نسخه از WinDbg، x86 و x64 وجود دارد. برای جلوگیری از هر گونه مشکل، برنامه های x86 را با استفاده از دیباگر x86 و برنامه های x64 را با استفاده از دیباگر x64 اشکال زدایی کنید. پس از اولین راه اندازی، WinDbg بسیار بد به نظر می رسد. اما در مورد آن نگران نباشید. پس از چند دقیقه کار با WinDbg، آن را برای خود شخصی سازی می کنید و ظاهر بسیار زیبایی خواهد داشت. به عنوان مثال، چیزی شبیه به این (قابل کلیک، 51 کیلوبایت، 1156 ایکس 785):

    این اسکرین شات اشکال زدایی برنامه را از یادداشت دریافت لیستی از فرآیندهای در حال اجرا در API ویندوز نشان می دهد. همانطور که می بینید، WinDbg کد منبع برنامه را انتخاب کرد. مقادیر متغیرهای محلی در سمت راست نمایش داده می شود. در پایین پنجره ای برای وارد کردن دستورات وجود دارد که پشته تماس با استفاده از دستور kn نمایش داده می شود. در بالای دیباگر دکمه‌هایی وجود دارد که به شما امکان می‌دهند کارهای ساده‌ای مانند "گام به جلو" و همچنین باز کردن پنجره‌های اضافی را انجام دهید. با استفاده از این پنجره ها می توانید محتویات RAM، ثبت مقادیر، لیست disassembler برنامه و بسیاری موارد جالب دیگر را مشاهده کنید.

    به طور کلی، بسیاری از کارها در WinDbg را می توان از طریق رابط کاربری گرافیکی انجام داد. به عنوان مثال، در پنجره کد منبع، می توانید مکان نما را در محل مورد نظر قرار دهید و روی نماد کف دست کلیک کنید تا نقطه شکست در آنجا ایجاد شود. یا اجرا به مکان نما. همچنین می توانید اجرای دستور را در هر زمان با استفاده از دکمه Break در پنل بالا متوقف کنید. ما در مورد همه اینها با جزئیات صحبت نخواهیم کرد. اما به خاطر داشته باشید که چنین فرصت هایی وجود دارند و ارزش کاوش را دارند!

    قبل از شروع اشکال زدایی با استفاده از WinDbg، باید چند مرحله ساده را انجام دهید. File → Symbol File Path را باز کرده و وارد کنید:

    SRV*C:\symbols*http://msdl.microsoft.com/download/symbols

    سپس بر روی Browse کلیک کنید و مسیر فایل های اطلاعات اشکال زدایی (pdb.) پروژه خود را مشخص کنید. به طور مشابه، در File → Source File Path، مسیر دایرکتوری منبع را مشخص کنید. اگر شک دارید، مسیری که فایل پروژه ویژوال استودیو در آن قرار دارد را مشخص کنید، نمی توانید اشتباه کنید. سپس بگویید File → Save Workspace تا مجبور نباشید هر بار که WinDbg را شروع می کنید همه این مسیرها دوباره مشخص شوند.

    اکنون که همه چیز تنظیم شده است، راه های مختلفی برای شروع اشکال زدایی وجود دارد. می‌توانید یک فرآیند جدید را در زیر اشکال‌زدا راه‌اندازی کنید، می‌توانید به یک موجود متصل شوید، می‌توانید یک خرابی باز کنید. همه این کارها از طریق منوی File انجام می شود. امکان اشکال زدایی از راه دور شایسته توجه ویژه است. به عنوان مثال، اگر درایورها را با استفاده از WinDbg اشکال زدایی کنید، انتخاب زیادی جز استفاده از اشکال زدایی از راه دور ندارید. تعجب آور نیست، زیرا کوچکترین خطا در کد راننده می تواند منجر به BSOD شود.

    اگر قبلاً این فرآیند را اشکال‌زدایی می‌کنید، اما می‌خواهید آن را از راه دور شروع کنید، می‌گوییم:

    سرور tcp:port=3003

    باید بررسی کنید که پورت باز باشد، که به ویژه در سرور ویندوز مهم است. در کلاینت، File → Connect to a Remote Session را انجام دهید، وارد کنید:

    tcp:Port=3003,Server=10.110.0.10

    علاوه بر این، می توانید سروری را راه اندازی کنید که به شما امکان می دهد هر فرآیندی را در سیستم اشکال زدایی کنید:

    dbgsrv.exe -t tcp:port=3003

    در کلاینت ما از طریق File → Connect to Remote Stub متصل می شویم. پس از این، از طریق اینترفیس می توانید طبق معمول یک فرآیند را از لیست انتخاب کنید یا یک فرآیند جدید را شروع کنید. فقط فرآیندها در دستگاه راه دور اجرا می شوند.

    اکنون، در نهایت، اجازه دهید به دستورات اساسی WinDbg نگاه کنیم.

    مهم!گاهی اوقات تکمیل دستورات ممکن است زمان بسیار زیادی طول بکشد، برای مثال اگر تصمیم دارید همه نمادهای اشکال زدایی را یکجا بارگیری کنید. اگر از انتظار خسته شدید، کافی است Ctr+C را در قسمت ورودی فرمان فشار دهید و WinDbg فوراً کاری را که در حال حاضر انجام می دهد متوقف می کند.

    کمک
    دستور hh

    خروجی را در پنجره Command پاک کنید:

    مسیری را اضافه کنید که در آن WinDbg نمادهای اشکال زدایی را جستجو می کند (همان دستور بدون علامت مثبت همه مسیرهای وارد شده قبلی را بازنویسی می کند):

    Sympath+ c:\pdbs

    بارگذاری مجدد نمادها:

    نمایش لیست ماژول:

    ما به دنبال نمادها هستیم:

    x *!Ololo::My::Namespace::*

    نمادهای بارگذاری برای ماژول:

    ld module_name

    اگر WinDbg به دلایلی فایل‌های .pdb را پیدا نکرد و در stacktraces به جای نام فایل‌های .c/.cpp با شماره خطوط چیزی شبیه module+0x19bc مشاهده کردید، دنباله دستورات زیر را اجرا کنید - این دستورات بیشتری را به شما می‌دهد. اطلاعات در مورد علل احتمالی مشکل:

    Sym پر سر و صدا
    MyModule.dll را دوباره بارگیری کنید

    مسیر دایرکتوری منبع را مشخص کنید:

    یک نقطه شکست تعیین کنید:

    bp kernel32!CreateProcessA
    bp `mysorucefile.cpp:123`
    bp «MyModule!mysorucefile.cpp:123».
    bp @@(کامل::کلاس:نام::روش)

    نقطه شکستی را تنظیم کنید که فقط یک بار کار کند:

    نقطه شکستی را تنظیم کنید که برای بار پنجم، پس از 4 پاس، کار کند:

    می‌توانید هر بار که نقطه‌ی انفصال ضربه می‌خورد، دستورات را به‌طور خودکار اجرا کنید:

    bp kernel32!LoadLibraryA ".echo \"Variables:\n\"; dv"

    U سخت افزارنحو نقطه شکست:

    ba

    در جایی که حالت e، r یا w است - اجرا، خواندن، نوشتن. وقتی mode = e پارامتر اندازه فقط می تواند 1 باشد. به عنوان مثال:

    ba e 1 kernel32!LoadLibraryA

    لیست نقاط شکست:

    غیرفعال کردن نقطه شکست:

    یک نقطه شکست را فعال کنید:

    حذف کامل نقاط شکست:

    شماره bc
    قبل از میلاد مسیح*

    دستوراتی را که برای بازیابی نقاط شکست فعلی باید وارد کنید نشان دهید:

    نوشتن گزارش در فایل:

    لوگو c:\1.txt را باز کنید

    توقف نوشتن گزارش در فایل:

    اجرای دستورات از فایل:

    برای ذخیره نقاط شکست در یک فایل، می توانید دستورات زیر را (الزاماً در یک خط!) اجرا کنید:

    لوگو باز کردن c:\1.txt; bpcmds. .logclose

    نمایش لیست جداکننده ها:

    نمایش مقادیر ثبت نام:

    نمایش پشته تماس:

    همین مورد در مورد اعداد فریم:

    انتقال به قاب:

    شماره قاب

    نمایش متغیرهای محلی:

    نمایش ساختار:

    dt variable_name

    نمایش ساختار به صورت بازگشتی:

    dt -r variable_name

    تخلیه حافظه در:

    تخلیه حافظه به شکل word/dword/qword:

    آدرس dw
    آدرس dd
    آدرس dq

    تخلیه به صورت بیت:

    Dump string ascii:

    حذف رشته یونیکد:

    ویرایش حافظه.

    امروز گام دیگری در تجارت بر خواهید داشت
    مطالعه سیستم های لینوکس من در مورد موارد اصلی به شما می گویم
    تکنیک های کار با gdb با تسلط بر آنها، می توانید نحوه عملکرد هر برنامه را درک کنید و اکسپلویت های خود را بنویسید.

    احتمالاً همه شما در مورد چیزی به نام دیباگر شنیده اید؛ gdb یک دیباگر است. GDB-GNU
    اشکال زدا. این یک نوع SoftICE برای ویندوز است (برای کسانی که نمی دانند، محبوب ترین و به نظر من به طور کلی بهترین دیباگر است)، فقط در زیر
    سیستم های لینوکس واقعیت این است که اسناد زیادی در شبکه وجود ندارد که عملکرد این چیز را نشان دهد و زمانی من خودم بر آن مسلط بودم. بنابراین،
    این سند دستورات اساسی gdb را پوشش می دهد. همه اینها با یک مثال نشان داده خواهد شد. و به عنوان مثال، تصمیم گرفتم برنامه غیر ضروری بله را انتخاب کنم. برای کسانی که نمی دانند، این برنامه به سادگی کاراکتر "y" را به صورت بی نهایت چاپ می کند. برای شروع، تصمیم گرفتم به آن آموزش دهم که نه این کاراکتر، بلکه رشته "XAKEP" را چاپ کند، حداقل سرگرم کننده تر خواهد بود.

    خوب حالا همه چیز مرتب است. خود دیباگر اینگونه شروع می شود:

    اما شما می توانید پارامترهای مختلفی را وارد کنید، برای ما این مسیر به برنامه مورد مطالعه خواهد بود:

    # gdb /usr/bin/yes

    شما می توانید فایل های اصلی را بررسی کنید، برای انجام این کار باید موارد زیر را وارد کنید:

    # gdb /usr/bin/yes core

    همچنین ممکن است برای مشاهده محتویات رجیسترها به دستور نیاز داشته باشید:

    (gdb) اطلاعات ثبت می شود

    یا مانند این (نسخه کوتاه)

    حال بیایید نحوه ایجاد رهگیری را بررسی کنیم. وجود داشته باشد
    نقاط شکست، نقاط رهگیری و نقاط مراقبت. به طور خاص تر، من می خواهم در مورد نقاط شکست صحبت کنم. آنها را می توان در موارد زیر نصب کرد:

    (gdb) تابع شکست - قبل از وارد کردن یک تابع متوقف شود
    (gdb) break *adress - قبل از اجرای دستور آدرس توقف کنید.

    پس از انجام تنظیمات، می توانید تمام نقاط را مشاهده کنید، از دستور استفاده کنید:

    (gdb) شکست اطلاعات

    و سپس می توانید این نکات را حذف کنید:

    (gdb) نقطه شکست روشن - جایی که شکست نام نقطه شکست است
    (به عنوان مثال تابع یا آدرس)

    یک چیز بسیار ضروری امکان نمایش خودکار مقادیر مختلف در حین اجرای یک برنامه است. یک دستور نمایش برای این وجود دارد:

    (gdb) display/format value، که در آن فرمت قالب نمایش است و مقدار خود عبارتی است که باید نمایش داده شود.

    دستورات زیر برای کار با نمایشگر ارائه شده است:

    نمایش اطلاعات (gdb) - اطلاعات مربوط به نمایشگرها را نمایش می دهد
    (gdb) حذف num - جایی که num - عناصر را با شاخص حذف کنید
    تعداد

    این یک اشاره کوتاه به دستورات برای دریافت ایده اولیه بود.
    در مرحله بعد، من می خواهم این و کمی بیشتر را با یک مثال نشان دهم. و به یاد داشته باشید - در اینجا من فقط بخش بسیار کوچکی از همه قابلیت های gdb را آورده ام، در واقع صدها برابر بیشتر است، پس بخوانید و یاد بگیرید.
    همانطور که قول داده بودم، برنامه بله غیر ضروری را می گیریم. مسیر روی دستگاه شما ممکن است با مسیر من مطابقت نداشته باشد، همه چیز به سیستم عاملی که استفاده می کنید بستگی دارد، اگر موردی بود، از جستجو (فرمان) استفاده کنید
    پیدا کردن).

    # gdb /usr/bin/yes

    هنگامی که راه اندازی می شود پیام خوش آمدگویی می گوید.

    گنو gdb 19991004




    مطلقاً هیچ ضمانتی برای GDB وجود ندارد. برای جزئیات، عبارت "نمایش گارانتی" را تایپ کنید.
    این GDB به عنوان "i386-redhat-linux" پیکربندی شده است...
    (هیچ علامت اشکال زدایی یافت نشد)...

    از آنجایی که yes تعداد بی نهایت نماد را خروجی می دهد، بهتر است آنها را در اشکال زدا نبینیم، بلکه خروجی را مشاهده کنیم.
    برنامه ها را می توان به کنسول دیگری هدایت کرد. یک ترمینال جدید باز کنید، who is i را تایپ کنید و نام کنسول را دریافت خواهید کرد. باید بیرون بیاید
    یه چیزی شبیه اون:

    حالا فقط آن را به آن گره می زنیم.

    (gdb) tty /dev/pts/1

    اکنون یک نقطه شکست بر روی تابع puts() قرار می دهیم، و برای روشن تر شدن آن، در اینجا یک راهنمای man در مورد تابع (فرمان man) وجود دارد.
    قرار می دهد)

    #عبارتند از
    int puts(const char *s);
    puts() رشته s و یک خط جدید انتهایی را در std می نویسد
    بیرون

    همانطور که می بینید، تابع رشته s را به جریان خروجی می فرستد. این چیزی است که ما نیاز داریم. فعلاً در آنجا توقف می کنیم.

    (gdb) شکستن قرار می دهد
    نقطه شکست 1 در 0x8048698

    و ما خود برنامه را اجرا می کنیم تا منتظر بمانیم تا gdb اجرای آن را در فراخوانی تابع متوقف کند.

    (gdb)r
    شروع برنامه: /usr/bin/yes
    نقطه شکست 1 در 0x4006d585: فایل ioputs.c، خط 32.

    نقطه شکست 1، 0x4006d585 در _IO_puts (str=0x8048e59 "y") در ioputs.c:32
    32 ioputs.c: چنین فایل یا دایرکتوری وجود ندارد.
    1: x/i $eip 0x4006d585<_IO_puts+21>: mov 0x8(%ebp)،%esi

    اوه، یک معجزه اتفاق افتاد، نقطه شکست کار کرد. آنچه می بینیم - و چیزی بیش از یک پارامتر تابع، یا بهتر است بگوییم آدرسی که در آن قرار دارد، نمی بینیم. الان به چی نیاز داری؟
    انجام دادن؟ درست است، داده ها را در این آدرس تصحیح کنید. در همان زمان، چند نماد دیگر را با نمادهای خودمان بازنویسی می کنیم.

    (gdb) set (char)0x8048e59="X"
    (gdb) set (char)0x8048e5a="A"
    (gdb) set (char)0x8048e5b="K"
    (gdb) set (char)0x8048e5c="E"
    (gdb) set (char)0x8048e5d="P"

    خوب، حالا بیایید به خلقت خود نگاه کنیم. آنچه در حافظه نهفته است:

    (gdb) x/3sw 0x8048e59
    0x8048e59<_IO_stdin_used+437>: "XAKEP\004\b"
    0x8048e61<_IO_stdin_used+445>: ""
    0x8048e62<_IO_stdin_used+446>: ""

    حالا بیایید نقطه شکست خود را حذف کنیم:

    (gdb) شکست اطلاعات
    نوع شماره Disp Enb Address What
    1 نقطه شکست y 0x4006d585 را در _IO_puts در ioputs.c:32 نگه دارید
    نقطه شکست قبلاً 1 بار زده شده است
    (gdb) روشن قرار می دهد
    نقطه شکست 1 حذف شد

    و بیایید اجرا را ادامه دهیم تا از نتیجه لذت ببریم:

    همین. بزن بریم بیرون.

    (gdb)q
    برنامه در حال اجراست. به هر حال خروج؟ (y یا n)y

    این جایی است که تمرین به پایان می رسد، بقیه را خودتان مطالعه کنید و به یاد داشته باشید که مهمترین چیز در این زندگی یادگیری است.
    در اینجا چند نمونه کار دیگر آورده شده است:

    پیوست کردن به یک فرآیند در حال اجرا:

    // gdb را راه اندازی کنید
    hack@exploit:~ > gdb
    گنو gdb 4.18
    حق چاپ 1998 Free Software Foundation, Inc.
    GDB یک نرم افزار رایگان است که تحت پوشش مجوز عمومی عمومی گنو است و شما هم هستید
    از تغییر آن و/یا توزیع کپی از آن تحت شرایط خاص خوش آمدید.
    برای مشاهده شرایط عبارت "show copying" را تایپ کنید.
    مطلقاً هیچ ضمانتی برای GDB وجود ندارد. "نمایش ضمانت" را برای
    جزئیات.
    این GDB به عنوان "i386-suse-linux" پیکربندی شده است.
    (gdb) ضمیمه "pid"
    (gdb) 1127 // پیوست مثال

    جستجو در حافظه:

    (gdb) x/d یا x "آدرس" اعشاری را نشان می دهد
    (gdb) x/100s "آدرس" 100 اعشار بعدی را نشان می دهد
    (gdb) x 0x0804846c نمایش دهدهی در 0x0804846c
    (gdb) x/s "آدرس" رشته ها را در آدرس نشان می دهد
    (gdb) x/105 0x0804846c نشان دادن 105 رشته در 0x0804846c
    (gdb) x/x "آدرس" نشانی هگزادسیمال را نشان می دهد
    (gdb) x/10x 0x0804846c نشان دادن 10 آدرس در 0x0804846c
    (gdb) x/b 0x0804846c نمایش بایت در 0x0804846c
    (gdb) x/10b 0x0804846c-10 نمایش بایت در 0x0804846c-10
    (gdb) x/10b 0x0804846c+20 نمایش بایت در 0x0804846c+20
    (gdb) x/20i 0x0804846c نشان دادن 20 دستورالعمل اسمبلر در آدرس

    لیست تمام بخش های فایل اجرایی:

    (gdb) بخش های اطلاعات نگهداری // یا
    (gdb) mai i s

    فایل اجرایی:
    "/home/hack/homepage/challenge/buf/basic"، نوع فایل
    elf32-i386.
    0x080480f4->0x08048107 در 0x000000f4: .interp ALLOC

    0x08048108->0x08048128 در 0x00000108: .note.ABI-tag
    ALLOC LOAD DATA فقط خواندنی HAS_CONTENTS
    0x08048128->0x08048158 در 0x00000128: .هش ALLOC
    LOAD ONLY DATA HAS_CONTENTS
    0x08048158->0x080481c8 در 0x00000158: .dynsym ALLOC
    LOAD ONLY DATA HAS_CONTENTS
    0x080481c8->0x08048242 در 0x000001c8: .dynstr ALLOC
    LOAD ONLY DATA HAS_CONTENTS
    0x08048242->0x08048250 در 0x00000242: .gnu.version
    ALLOC LOAD DATA فقط خواندنی
    HAS_CONTENTS

    نقطه گسست به آدرس:

    (gdb) جداسازی اصلی
    تخلیه کد اسمبلر برای تابع main:
    0x8048400

    : %ebp را فشار دهید
    0x8048401 : حرکت %esp،%ebp
    0x8048403 : زیر $0x408،%esp
    0x8048409 : $0xfffffff8،%esp اضافه کنید
    0x804840c : mov 0xc(%ebp)،%eax
    0x804840f : $0x4،%eax اضافه کنید
    0x8048412 : mov (%eax)،%edx
    0x8048414 : %edx را فشار دهید
    0x8048415 : lea 0xfffffc00(%ebp)،%eax
    ...

    (gdb) شکست *0x8048414 // مثال
    نقطه شکست 1 در 0x8048414
    (gdb) break main // مثال
    نقطه شکست 2 در 0x8048409
    (gdb)

    ترجمه مقاله Allan O'Donnell Learning C with GDB.

    با توجه به ماهیت زبان های سطح بالا مانند Ruby، Scheme یا Haskell، یادگیری C می تواند چالش برانگیز باشد. علاوه بر غلبه بر ویژگی های سطح پایین C مانند مدیریت دستی حافظه و اشاره گرها، باید بدون REPL نیز از پس آن برآیید. هنگامی که به برنامه نویسی اکتشافی در REPL عادت کردید، برخورد با چرخه نوشتن-کامپایل-اجرا می تواند کمی خسته کننده باشد.

    اخیراً به ذهنم رسید که می‌توانم از GDB به‌عنوان یک شبه REPL برای C استفاده کنم. استفاده از GDB را به‌عنوان ابزاری برای یادگیری زبان به جای اشکال‌زدایی، آزمایش کردم، و معلوم شد که بسیار سرگرم‌کننده بود.

    هدف از این پست این است که به شما نشان دهیم GDB ابزاری عالی برای یادگیری زبان C است. من شما را با تعدادی از دستورات مورد علاقه خود از GDB آشنا می کنم و نشان می دهم که چگونه می توانید از GDB برای درک یکی از بخش های دشوار برنامه استفاده کنید. زبان C: تفاوت بین آرایه ها و اشاره گرها.

    مقدمه ای بر GDB

    بیایید با ایجاد برنامه کوچک C زیر شروع کنیم - حداقل.ج:

    Int main() (int i = 1337; return 0; )
    لطفاً توجه داشته باشید که برنامه مطلقاً هیچ کاری انجام نمی دهد و حتی یک دستور ندارد printf. حالا بیایید وارد دنیای جدید یادگیری زبان C با استفاده از GBD شویم.

    بیایید این برنامه را با پرچم کامپایل کنیم -gبرای تولید اطلاعات اشکال زدایی که GDB با آن کار خواهد کرد، و این اطلاعات را به آن بدهید:

    $ gcc -g minimal.c -o حداقل $ gdb حداقل
    اکنون باید در یک لحظه در خط فرمان GDB باشید. من به شما قول REPL را داده بودم، بنابراین آنچه را که دریافت می کنید این است:

    (gdb) چاپ 1 + 2 $ 1 = 3
    شگفت انگیز! چاپیک دستور GDB داخلی است که نتیجه یک عبارت C را ارزیابی می کند. اگر نمی دانید دستور GDB دقیقا چه کاری انجام می دهد، فقط کمک بگیرید - تایپ کنید کمک نام-از-فرماندر خط فرمان GDB

    در اینجا یک مثال جالب تر است:

    (gbd) چاپ (int) 2147483648 $2 = -2147483648
    من از توضیح دادن چرا 2147483648 == -2147483648 . نکته اصلی در اینجا این است که حتی محاسبات در C می تواند مشکل باشد و GDB حساب C را کاملاً درک می کند.

    حالا بیایید یک نقطه شکست در تابع قرار دهیم اصلیو برنامه را اجرا کنید:

    (gdb) break main (gdb) run
    برنامه در خط سوم، درست در جایی که متغیر مقدار دهی اولیه شده است، متوقف شد من. نکته جالب این است که اگرچه متغیر هنوز مقداردهی اولیه نشده است، اما می توانیم مقدار آن را با استفاده از دستور مشاهده کنیم چاپ:

    (gdb) من 3 دلار = 32767 چاپ کنید
    در C، مقدار یک متغیر محلی بدون مقدار اولیه تعریف نشده است، بنابراین نتیجه ای که به دست می آورید ممکن است متفاوت باشد.

    ما می توانیم خط فعلی کد را با استفاده از دستور اجرا کنیم بعد:

    (gdb) بعدی (gdb) چاپ i $4 = 1337

    ما حافظه را با استفاده از دستور کاوش می کنیم ایکس

    متغیرها در C بلوک های پیوسته حافظه هستند. در این مورد، بلوک هر متغیر با دو عدد مشخص می شود:

    1. آدرس عددی اولین بایت در بلوک.
    2. اندازه بلوک در بایت. این اندازه با توجه به نوع متغیر تعیین می شود.

    یکی از ویژگی های متمایز زبان C این است که شما به بلوک حافظه یک متغیر دسترسی مستقیم دارید. اپراتور & آدرس متغیر موجود در حافظه را به ما می دهد و اندازهاندازه اشغال شده توسط یک متغیر حافظه را محاسبه می کند.

    شما می توانید با هر دو احتمال در GDB بازی کنید:

    (gdb) print &i $5 = (int *) 0x7fff5fbff584 (gdb) اندازه چاپ(i) $6 = 4
    در زبان عادی، این به این معنی است که متغیر منواقع شده در 0x7fff5fbff5b4و 4 بایت حافظه را اشغال می کند.

    قبلاً در بالا ذکر کردم که اندازه یک متغیر در حافظه به نوع آن و به طور کلی عملگر بستگی دارد اندازهمی تواند با انواع داده ها کار کند:

    (gdb) اندازه چاپ (int) 7 دلار = 4 (gdb) اندازه چاپ (دو برابر) 8 دلار = 8
    این بدان معناست که حداقل در دستگاه من، متغیرهایی مانند بین المللیچهار بایت را اشغال کنید و تایپ کنید دو برابر- هشت بایت

    GDB یک ابزار قدرتمند برای بررسی مستقیم حافظه دارد - فرمان ایکس. این دستور حافظه را با شروع از یک آدرس خاص آزمایش می کند. همچنین دارای تعدادی دستورات قالب بندی است که به شما کنترل دقیقی بر روی تعداد بایت هایی که می خواهید بررسی کنید و نحوه نمایش آنها را می دهد. در صورت بروز هر گونه مشکل شماره گیری نمایید کمک xدر خط فرمان GDB

    همانطور که می دانید اپراتور & آدرس یک متغیر را محاسبه می کند، به این معنی که می توان آن را به دستور ارسال کرد ایکسمعنی &منو بنابراین فرصتی برای مشاهده تک تک بایت های پنهان شده در پشت متغیر بدست آورید من:

    (gdb) x/4xb &i 0x7fff5fbff584: 0x39 0x05 0x00 0x00
    پرچم های قالب بندی نشان می دهد که من چهار ( 4 ) خروجی را به صورت هگزادسیمال (he ایکس) به صورت یک بایت ( ب yte). من بررسی فقط چهار بایت را مشخص کردم، زیرا این مقدار مقداری است که متغیر در حافظه اشغال می کند من. خروجی نمایش بایت به بایت متغیر در حافظه را نشان می دهد.

    اما یک نکته ظریف در ارتباط با خروجی بایت بایت وجود دارد که باید مدام در نظر گرفته شود - در دستگاه‌های اینتل، بایت‌ها برخلاف ضبط آشناتر به ترتیب «از کم‌اهمیت به بالاترین» (از راست به چپ) ذخیره می‌شوند. برای انسان ها، جایی که پایین ترین بایت باید در پایان باشد (از چپ به راست).

    یکی از راه های روشن شدن این موضوع، اختصاص یک متغیر است منمقدار جالب تر است و دوباره این ناحیه حافظه را بررسی کنید:

    (gdb) تنظیم var i = 0x12345678 (gdb) x/4xb &i 0x7fff5fbff584: 0x78 0x56 0x34 0x12

    کاوش حافظه با تیم ptype

    تیم ptypeشاید یکی از مورد علاقه های من نوع عبارت C را نشان می دهد:

    (gdb) ptype i type = int (gdb) ptype &i نوع = int * (gdb) ptype نوع اصلی = int (باطل)
    انواع در C می توانند پیچیده شوند، اما ptypeبه شما امکان می دهد آنها را به صورت تعاملی کشف کنید.

    اشاره گرها و آرایه ها

    آرایه ها یک مفهوم شگفت آور ظریف در C هستند. نکته این نکته این است که یک برنامه ساده بنویسیم و سپس آن را از طریق GDB اجرا کنیم تا آرایه ها تا حدی معنا پیدا کنند.

    بنابراین ما به کد برنامه با آرایه نیاز داریم آرایه.c:

    Int main() ( int a = (1, 2, 3); return 0; )
    آن را با پرچم کامپایل کنید -g، در GDB و با کمک اجرا شود بعدبه خط اولیه بروید:

    آرایه‌های $ gcc -g
    در این مرحله می توانید محتویات متغیر را نمایش دهید و نوع آن را پیدا کنید:

    (gdb) چاپ $1 = (1, 2, 3) (gdb) ptype a type = int
    اکنون که برنامه ما به درستی در GDB پیکربندی شده است، اولین کاری که باید انجام دهیم استفاده از دستور است ایکستا ببینیم متغیر چگونه است آ"در زیر کاپوت":

    (gdb) x/12xb & a 0x7fff5fbff56c: 0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x7fff5fbff574: 0x03 0x00 0x0 0
    این بدان معنی است که فضای حافظه برای آرایه آاز آدرس شروع می شود 0x7fff5fbff56c. چهار بایت اول شامل آ، چهار بعدی هستند آ، و چهار فروشگاه آخر آ. در واقع، شما می توانید آن را بررسی و مطمئن شوید اندازهمی داند که آدقیقا دوازده بایت حافظه را اشغال می کند:

    (gdb) اندازه چاپ (a) $2 = 12
    تا این مرحله، آرایه ها همانطور که باید به نظر می رسند. آنها انواع آرایه مربوطه دارند و همه مقادیر را در مکان های حافظه پیوسته ذخیره می کنند. با این حال، در شرایط خاص، آرایه ها بسیار شبیه به اشاره گرها عمل می کنند! به عنوان مثال، می توانیم عملیات حسابی را اعمال کنیم آ:

    (gdb) چاپ + 1 $3 = (int *) 0x7fff5fbff570
    در کلمات عادی، این به این معنی است a+1اشاره گر است به بین المللی، که آدرس دارد 0x7fff5fbff570. در این مرحله شما باید به صورت بازتابی نشانگرها را به دستور ارسال کنید ایکس، پس بیایید ببینیم چه اتفاقی افتاده است:

    (gdb) x/4xb a + 1 0x7fff5fbff570: 0x02 0x00 0x00 0x00

    لطفا توجه داشته باشید که آدرس 0x7fff5fbff570دقیقا چهار واحد بیشتر از 0x7fff5fbff56c، یعنی آدرس اولین بایت آرایه آ. با توجه به اینکه نوع بین المللیچهار بایت در حافظه اشغال می کند، می توانیم نتیجه بگیریم که a+1اشاره می کند آ.

    در واقع، نمایه سازی آرایه در C یک قند نحوی برای محاسبات اشاره گر است: a[i]معادل *(a + i). شما می توانید این را در GDB بررسی کنید:

    (gdb) چاپ $4 = 1 (gdb) *(a + 0) $5 = 1 (gdb) چاپ $6 = 2 (gdb) *(a + 1) $7 = 2 (gdb) چاپ $8 = 3 (gdb) چاپ *(a + 2) $9 = 3
    بنابراین، ما این را در برخی شرایط دیده ایم آمانند یک آرایه رفتار می کند و در برخی موارد مانند یک اشاره گر به عنصر اول خود عمل می کند. چه خبر است؟

    پاسخ این است که وقتی یک نام آرایه در یک عبارت در C استفاده می شود، به یک اشاره گر به عنصر اول "تجزیه" می کند. تنها دو استثنا برای این قانون وجود دارد: زمانی که نام آرایه به آن ارسال می شود اندازهو زمانی که نام آرایه با عملگر آدرس استفاده می شود & .

    این واقعیت که نام آهنگام استفاده از عملگر به یک اشاره گر به عنصر اول تبدیل نمی شود & ، یک سوال جالب ایجاد می کند: تفاوت بین اشاره گر که در آن است آو ?

    از نظر عددی، هر دو نشان دهنده یک آدرس هستند:

    (gdb) x/4xb a 0x7fff5fbff56c: 0x01 0x00 0x00 0x00 (gdb) x/4xb &a 0x7fff5fbff56c: 0x01 0x00 0x00 0x00
    با این حال، انواع آنها متفاوت است. همانطور که قبلاً دیدیم، نام یک آرایه به یک اشاره گر به عنصر اول آن مشخص می شود و بنابراین باید از نوع باشد. درون *. در مورد نوع ، سپس می توانیم از GDB در مورد آن سوال کنیم:

    (gdb) ptype &a type = int (*)
    به بیان ساده، اشاره گر به آرایه ای از سه عدد صحیح است. منطقی است: آهنگام انتقال به اپراتور متلاشی نمی شود & و a دارای نوع است بین المللی.

    شما می توانید تفاوت بین اشاره گر که به تقسیم می شود را ردیابی کنید آو جراحی در اینجا مثالی از نحوه رفتار آنها در رابطه با محاسبات نشانگر آورده شده است:

    (gdb) print a + 1 $10 = (int *) 0x7fff5fbff570 (gdb) print & a + 1 $11 = (int (*)) 0x7fff5fbff578
    توجه داشته باشید که اضافه کردن 1 به آآدرس را چهار واحد افزایش می دهد، در حالی که 1 را به آن اضافه می کند دوازده را به آدرس اضافه می کند.

    اشاره گر که در واقع به آبه نظر می رسد :

    (gdb) چاپ و 11 دلار = (int *) 0x7fff5fbff56c

    نتیجه

    امیدوارم شما را متقاعد کرده باشم که GDB یک محیط اکتشافی زیبا برای یادگیری C است. به شما امکان می دهد معنی عبارات را با استفاده از دستور چاپ کنید. چاپ، حافظه را بایت به بایت با دستور کاوش کنید ایکسو با استفاده از دستور با انواع کار کنید ptype.

    1. از GDB برای کار بر روی The Ksplice Pointer Challenge استفاده کنید.
    2. درک کنید که ساختارها چگونه در حافظه ذخیره می شوند. ارتباط آنها با آرایه ها چگونه است؟
    3. از دستورات disassembler GDB استفاده کنید تا درک بهتری از برنامه نویسی زبان اسمبلی به دست آورید. کشف نحوه عملکرد پشته فراخوانی تابع بسیار جالب است.
    4. حالت "TUI" GDB را بررسی کنید، که یک افزونه ncurses گرافیکی را بر روی GDB معمولی ارائه می دهد. در OS X، احتمالاً باید GDB را از منبع بسازید.

    از مترجم: به طور سنتی، از LAN برای نشان دادن خطاها استفاده کنید. من خوشحال خواهم شد که انتقاد سازنده دریافت کنم.