GDB - คู่มือฉบับย่อ

ดีบักเกอร์คือโปรแกรมที่รันโปรแกรมอื่น ๆ ทำให้ผู้ใช้สามารถควบคุมโปรแกรมเหล่านี้และตรวจสอบตัวแปรเมื่อเกิดปัญหาขึ้น

GNU Debugger ซึ่งเรียกอีกอย่างว่า gdb, เป็นดีบักเกอร์ที่ได้รับความนิยมสูงสุดสำหรับระบบ UNIX ในการดีบักโปรแกรม C และ C ++

GNU Debugger ช่วยคุณในการรับข้อมูลเกี่ยวกับสิ่งต่อไปนี้:

  • หากเกิดการถ่ายโอนข้อมูลหลักแล้วคำสั่งหรือนิพจน์ใดที่โปรแกรมขัดข้อง

  • หากเกิดข้อผิดพลาดขณะเรียกใช้ฟังก์ชันบรรทัดใดของโปรแกรมที่มีการเรียกใช้ฟังก์ชันนั้นและพารามิเตอร์คืออะไร

  • ค่าของตัวแปรโปรแกรม ณ จุดใดจุดหนึ่งในระหว่างการทำงานของโปรแกรมคืออะไร?

  • ผลลัพธ์ของนิพจน์เฉพาะในโปรแกรมคืออะไร?

GDB แก้จุดบกพร่องอย่างไร

GDB ช่วยให้คุณสามารถรันโปรแกรมได้จนถึงจุดหนึ่งจากนั้นหยุดและพิมพ์ค่าของตัวแปรบางตัว ณ จุดนั้นหรือทำตามโปรแกรมทีละบรรทัดและพิมพ์ค่าของตัวแปรแต่ละตัวหลังจากดำเนินการแต่ละบรรทัด

GDB ใช้อินเทอร์เฟซบรรทัดคำสั่งง่ายๆ

สิ่งที่ควรทราบ

  • แม้ว่า GDB จะช่วยคุณในการค้นหาจุดบกพร่องที่เกี่ยวข้องกับการรั่วไหลของหน่วยความจำ แต่ก็ไม่ใช่เครื่องมือในการตรวจจับการรั่วไหลของหน่วยความจำ

  • ไม่สามารถใช้ GDB สำหรับโปรแกรมที่คอมไพล์มีข้อผิดพลาดและไม่ได้ช่วยในการแก้ไขข้อผิดพลาดเหล่านั้น

ก่อนที่คุณจะทำการติดตั้งตรวจสอบว่าคุณได้ติดตั้ง gdb ในระบบ Unix แล้วหรือไม่โดยออกคำสั่งต่อไปนี้:

$gdb -help

หากติดตั้ง GDB แล้วจะแสดงตัวเลือกทั้งหมดที่มีอยู่ภายใน GDB ของคุณ หากไม่ได้ติดตั้ง GDB ให้ดำเนินการติดตั้งใหม่

คุณสามารถติดตั้ง GDB บนระบบของคุณได้โดยทำตามขั้นตอนง่ายๆที่กล่าวถึงด้านล่าง

step 1: ตรวจสอบให้แน่ใจว่าคุณมีข้อกำหนดเบื้องต้นในการติดตั้ง gdb:

  • คอมไพเลอร์ C ที่สอดคล้องกับ ANSI (แนะนำให้ใช้ gcc - โปรดทราบว่า gdb สามารถดีบักโค้ดที่สร้างโดยคอมไพเลอร์อื่น ๆ )

  • จำเป็นต้องมีเนื้อที่ว่างบนดิสก์ 115 MB บนพาร์ติชันที่คุณกำลังจะสร้าง gdb

  • จำเป็นต้องมีเนื้อที่ว่างบนดิสก์ 20 MB บนพาร์ติชันที่คุณกำลังจะติดตั้ง gdb

  • โปรแกรมคลายการบีบอัดของ GNU gzip

  • make ยูทิลิตี้ - รุ่น GNU เป็นที่ทราบกันดีว่าทำงานได้โดยไม่มีปัญหาคนอื่น ๆ ก็อาจทำได้เช่นกัน

step 2: ดาวน์โหลดการแจกจ่ายซอร์ส gdb จาก ftp.gnu.org/gnu/gdb. (เราใช้ gdb-6.6.tar.gz สำหรับคำแนะนำเหล่านี้) วางไฟล์การแจกจ่ายในไดเร็กทอรีบิลด์ของคุณ

step 3:ในไดเร็กทอรีบิลด์ของคุณคลายการบีบอัด gdb-6.6.tar.gz และแตกไฟล์ต้นทางจากไฟล์เก็บถาวร เมื่อแตกไฟล์เสร็จแล้วให้เปลี่ยนไดเร็กทอรีการทำงานของคุณเป็นไดเร็กทอรี gdb-6.6 ที่สร้างขึ้นโดยอัตโนมัติในไดเร็กทอรีบิลด์ของคุณ

$ build> gzip -d gdb-6.6.tar.gz 
$ build> tar xfv gdb-6.6.tar 
$ build> cd gdb-6.6

step 4: รันสคริปต์กำหนดค่าเพื่อกำหนดค่าโครงสร้างต้นทางสำหรับแพลตฟอร์มของคุณ

$ gdb-6.6> .⁄configure

step 5: สร้าง gdb โดยใช้ไฟล์ make ยูทิลิตี้

$ gdb-6.6> make

step 6: ล็อกอินด้วยรูทและติดตั้ง gdb โดยใช้คำสั่งต่อไปนี้

$ gdb-6.6> make install

step 7: หากต้องการพื้นที่ดิสก์สามารถเรียกคืนได้โดยการลบไดเร็กทอรี gdb build และไฟล์เก็บถาวรหลังจากการติดตั้งเสร็จสมบูรณ์

$ gdb-6.6> cd .. 
$ build> rm -r gdb-6.6 
$ build> rm gdb-6.6.tar

ตอนนี้คุณได้ติดตั้ง gdb ในระบบของคุณแล้วและพร้อมใช้งาน

Debugging Symbol Tableแมปคำแนะนำในโปรแกรมไบนารีที่คอมไพล์กับตัวแปรฟังก์ชันหรือบรรทัดที่เกี่ยวข้องในซอร์สโค้ด การทำแผนที่นี้อาจเป็นดังนี้:

  • คำสั่งโปรแกรม⇒ชื่อรายการประเภทรายการไฟล์ต้นฉบับหมายเลขบรรทัดที่กำหนด

ตารางสัญลักษณ์อาจถูกฝังลงในโปรแกรมหรือจัดเก็บเป็นไฟล์แยกต่างหาก ดังนั้นหากคุณวางแผนที่จะดีบักโปรแกรมของคุณคุณจะต้องสร้างตารางสัญลักษณ์ซึ่งจะมีข้อมูลที่จำเป็นในการดีบักโปรแกรม

เราสามารถสรุปข้อเท็จจริงเกี่ยวกับตารางสัญลักษณ์ต่อไปนี้:

  • ตารางสัญลักษณ์ใช้งานได้กับโปรแกรมเวอร์ชันใดเวอร์ชันหนึ่ง - หากโปรแกรมเปลี่ยนแปลงต้องสร้างตารางใหม่

  • การสร้างดีบักมักมีขนาดใหญ่และช้ากว่าการสร้างแบบขายปลีก (ไม่ใช่การแก้ปัญหา) การสร้างการแก้ปัญหาประกอบด้วยตารางสัญลักษณ์และข้อมูลเสริมอื่น ๆ

  • หากคุณต้องการดีบักโปรแกรมไบนารีที่คุณไม่ได้คอมไพล์เองคุณต้องได้รับตารางสัญลักษณ์จากผู้เขียน

เพื่อให้ GDB สามารถอ่านข้อมูลทั้งหมดทีละบรรทัดจากตารางสัญลักษณ์เราจำเป็นต้องรวบรวมข้อมูลให้แตกต่างกันเล็กน้อย โดยปกติเรารวบรวมโปรแกรมของเราเป็น:

gcc hello.cc -o hello

แทนที่จะทำสิ่งนี้เราต้องคอมไพล์ด้วยแฟล็ก -g ดังที่แสดงด้านล่าง:

gcc -g hello.cc -o hello

GDB มีรายการคำสั่งจำนวนมากอย่างไรก็ตามคำสั่งต่อไปนี้เป็นคำสั่งที่ใช้บ่อยที่สุด:

  • b main - กำหนดจุดพักที่จุดเริ่มต้นของโปรแกรม

  • b - วางเบรกพอยต์ที่บรรทัดปัจจุบัน

  • b N - กำหนดจุดพักที่บรรทัด N

  • b +N - วางเบรกพอยต์ N เส้นลงจากบรรทัดปัจจุบัน

  • b fn - กำหนดจุดพักที่จุดเริ่มต้นของฟังก์ชัน "fn"

  • d N - ลบหมายเลขเบรกพอยต์ N

  • info break - รายการเบรกพอยต์

  • r - รันโปรแกรมจนกว่าจุดพักหรือข้อผิดพลาด

  • c - รันโปรแกรมต่อไปจนถึงจุดพักหรือข้อผิดพลาดถัดไป

  • f - รันจนกว่าฟังก์ชันปัจจุบันจะเสร็จสิ้น

  • s - รันบรรทัดถัดไปของโปรแกรม

  • s N - รัน N บรรทัดถัดไปของโปรแกรม

  • n - ชอบ s แต่ไม่เข้าขั้นเป็นฟังก์ชัน

  • u N - รันจนกว่าคุณจะได้ N บรรทัดหน้าบรรทัดปัจจุบัน

  • p var - พิมพ์ค่าปัจจุบันของตัวแปร "var"

  • bt - พิมพ์การติดตามสแต็ก

  • u - เพิ่มระดับในสแต็ก

  • d - ลดระดับลงในสแต็ก

  • q - ออกจาก gdb

เริ่มต้นใช้งาน: การเริ่มต้นและการหยุด

  • gcc -g myprogram.c

    • คอมไพล์ myprogram.c ด้วยอ็อพชันการดีบัก (-g) คุณยังคงได้รับ a.out แต่มีข้อมูลการดีบักที่ช่วยให้คุณใช้ตัวแปรและชื่อฟังก์ชันภายใน GDB แทนตำแหน่งหน่วยความจำดิบ (ไม่ใช่เรื่องสนุก)

  • gdb a.out

    • เปิด GDB ด้วยไฟล์ a.out แต่ไม่ได้เรียกใช้โปรแกรม คุณจะเห็นข้อความแจ้ง (gdb) - ตัวอย่างทั้งหมดมาจากพรอมต์นี้

  • r

  • r arg1 arg2

  • r <file1

    • สามวิธีในการเรียกใช้“ a.out” ซึ่งโหลดไว้ก่อนหน้านี้ คุณสามารถเรียกใช้โดยตรง (r) ส่งผ่านอาร์กิวเมนต์ (r arg1 arg2) หรือฟีดในไฟล์ โดยปกติคุณจะกำหนดจุดพักก่อนที่จะทำงาน

  • help

  • h เบรกพอยต์

    • แสดงหัวข้อวิธีใช้ (ความช่วยเหลือ) หรือรับความช่วยเหลือในหัวข้อเฉพาะ (h เบรกพอยต์) GDB ได้รับการบันทึกไว้เป็นอย่างดี

  • q - ออกจาก GDB

ก้าวผ่านรหัส

Stepping ช่วยให้คุณสามารถติดตามเส้นทางของโปรแกรมของคุณและเป็นศูนย์ในโค้ดที่หยุดทำงานหรือส่งคืนอินพุตที่ไม่ถูกต้อง

  • l

  • ล. 50

    • แสดงรายการซอร์สโค้ด 10 บรรทัดสำหรับบรรทัดปัจจุบัน (l) บรรทัดเฉพาะ (l 50) หรือสำหรับฟังก์ชัน (l myfunction)

  • ต่อไป

    • รันโปรแกรมจนถึงบรรทัดถัดไปจากนั้นหยุดชั่วคราว หากบรรทัดปัจจุบันเป็นฟังก์ชันฟังก์ชันนี้จะเรียกใช้ฟังก์ชันทั้งหมดจากนั้นหยุดชั่วคราวnext เหมาะสำหรับการเดินผ่านโค้ดของคุณอย่างรวดเร็ว

  • ขั้นตอน

    • รันคำสั่งถัดไปไม่ใช่บรรทัด หากคำสั่งปัจจุบันกำลังตั้งค่าตัวแปรจะเหมือนกับnext. ถ้าเป็นฟังก์ชันมันจะกระโดดเข้าสู่ฟังก์ชันเรียกใช้คำสั่งแรกจากนั้นหยุดชั่วคราวstep เหมาะสำหรับการดำน้ำลึกลงไปในรายละเอียดของรหัสของคุณ

  • เสร็จสิ้น

    • เสร็จสิ้นการเรียกใช้ฟังก์ชันปัจจุบันจากนั้นหยุดชั่วคราว (เรียกอีกอย่างว่า step out) มีประโยชน์หากคุณบังเอิญก้าวเข้าสู่ฟังก์ชัน

จุดพักหรือจุดชมวิว

เบรกพอยต์มีบทบาทสำคัญในการดีบัก พวกเขาหยุด (หยุดพัก) โปรแกรมชั่วคราวเมื่อถึงจุดหนึ่ง คุณสามารถตรวจสอบและเปลี่ยนแปลงตัวแปรและดำเนินการต่อได้ สิ่งนี้มีประโยชน์เมื่อเกิดความล้มเหลวในการป้อนข้อมูลหรือต้องทดสอบอินพุต

  • แตก 45

  • ทำลายการทำงานของฉัน

    • ตั้งเบรกพอยต์ที่บรรทัด 45 หรือที่ฟังก์ชันของฉัน โปรแกรมจะหยุดชั่วคราวเมื่อถึงจุดพัก
  • ดู x == 3

    • ตั้งค่า watchpoint ซึ่งจะหยุดโปรแกรมชั่วคราวเมื่อเงื่อนไขเปลี่ยนไป (เมื่อ x == 3 เปลี่ยน) Watchpoints เหมาะสำหรับอินพุตบางอย่าง (myPtr! = NULL) โดยไม่ต้องหยุดการเรียกใช้ฟังก์ชันทุกครั้ง

  • ดำเนินการต่อ

    • ดำเนินการต่อหลังจากถูกหยุดชั่วคราวโดยเบรกพอยต์ / จุดเฝ้าระวัง โปรแกรมจะดำเนินต่อไปจนกว่าจะถึงจุดพัก / จุดเฝ้าระวังถัดไป

  • ลบ N

    • ลบเบรกพอยต์ N (เบรกพอยต์จะมีหมายเลขเมื่อสร้าง)

การตั้งค่าตัวแปร

การดูและการเปลี่ยนแปลงตัวแปรที่รันไทม์เป็นส่วนสำคัญของการดีบัก ลองป้อนข้อมูลที่ไม่ถูกต้องให้กับฟังก์ชันหรือเรียกใช้กรณีทดสอบอื่น ๆ เพื่อค้นหาสาเหตุที่แท้จริงของปัญหา โดยปกติคุณจะดู / ตั้งค่าตัวแปรเมื่อโปรแกรมหยุดชั่วคราว

  • พิมพ์ x

    • พิมพ์ค่าปัจจุบันของตัวแปร x ความสามารถในการใช้ชื่อตัวแปรดั้งเดิมเป็นสาเหตุที่ต้องใช้แฟล็ก (-g) โปรแกรมที่คอมไพล์เป็นประจำจะลบข้อมูลนี้ออกไป

  • ตั้งค่า x = 3

  • ตั้งค่า x = y

    • ตั้งค่า x เป็นค่าชุด (3) หรือตัวแปรอื่น (y)
  • โทร myfunction ()

  • เรียก myotherfunction (x)

  • โทร strlen (mystring)

    • เรียกใช้ฟังก์ชันที่ผู้ใช้กำหนดหรือระบบ สิ่งนี้มีประโยชน์อย่างยิ่ง แต่ระวังการเรียกใช้ฟังก์ชันบั๊กกี้

  • แสดง x

    • แสดงค่าของตัวแปร x อย่างต่อเนื่องซึ่งจะแสดงหลังจากทุกขั้นตอนหรือหยุดชั่วคราว มีประโยชน์หากคุณตรวจสอบค่าที่แน่นอนอยู่ตลอดเวลา

  • ไม่แสดง x

    • ลบการแสดงค่าคงที่ของตัวแปรที่แสดงโดยคำสั่ง display

Backtrace และการเปลี่ยนเฟรม

สแต็กคือรายการของการเรียกใช้ฟังก์ชันปัจจุบันซึ่งจะแสดงตำแหน่งที่คุณอยู่ในโปรแกรม กรอบเก็บรายละเอียดของการเรียกใช้ฟังก์ชันเดียวเช่นการขัดแย้ง

  • bt

    • Backtracesหรือพิมพ์สแต็กฟังก์ชันปัจจุบันเพื่อแสดงตำแหน่งที่คุณอยู่ในโปรแกรมปัจจุบัน หากสายหลักทำงาน a () ซึ่งเรียก b () ซึ่งเรียก c () backtrace คือ

  • c <= current location 
    b 
    a 
    main
  • up

  • ลง

    • เลื่อนไปที่เฟรมถัดไปขึ้นหรือลงในกองฟังก์ชัน ถ้าคุณอยู่ในc, คุณสามารถย้ายไปที่ b หรือ a เพื่อตรวจสอบตัวแปรท้องถิ่น

  • กลับ

    • ส่งกลับจากฟังก์ชันปัจจุบัน

การจัดการสัญญาณ

สัญญาณคือข้อความที่เกิดขึ้นหลังจากเหตุการณ์บางอย่างเช่นตัวจับเวลาหรือข้อผิดพลาด GDB อาจหยุดชั่วคราวเมื่อพบสัญญาณ คุณอาจต้องการเพิกเฉยแทน

  • จัดการ [ชื่อสัญญาณ] [การกระทำ]

  • ด้ามจับ SIGUSR1 nostop

  • จัดการกับ SIGUSR1 noprint

  • จัดการกับ SIGUSR1 ละเว้น

    • สั่งให้ GDB ละเว้นสัญญาณบางอย่าง (SIGUSR1) เมื่อเกิดขึ้น การละเว้นมีหลายระดับ

ดูตัวอย่างต่อไปนี้เพื่อทำความเข้าใจขั้นตอนการดีบักโปรแกรมและคอร์ที่ดัมพ์

  • ตัวอย่างการดีบัก 1

    ตัวอย่างนี้แสดงให้เห็นว่าคุณจะจับข้อผิดพลาดที่เกิดขึ้นได้อย่างไรเนื่องจากมีข้อยกเว้นที่เพิ่มขึ้นในขณะที่หารด้วยศูนย์

  • ตัวอย่างการดีบัก 2

    ตัวอย่างนี้แสดงให้เห็นถึงโปรแกรมที่สามารถดัมพ์คอร์ได้เนื่องจากหน่วยความจำที่ไม่ได้เริ่มต้น

ทั้งสองโปรแกรมเขียนด้วย C ++ และสร้างคอร์ดัมพ์เนื่องจากเหตุผลที่แตกต่างกัน หลังจากผ่านสองตัวอย่างนี้แล้วคุณควรอยู่ในตำแหน่งที่จะดีบักโปรแกรม C หรือ C ++ ที่สร้างการถ่ายโอนข้อมูลหลัก

หลังจากอ่านบทช่วยสอนนี้แล้วคุณจะต้องมีความเข้าใจเป็นอย่างดีเกี่ยวกับการดีบักโปรแกรม C หรือ C ++ โดยใช้ GNU Debugger ตอนนี้คุณควรเรียนรู้การทำงานของดีบักเกอร์อื่น ๆ ได้ง่ายมากเพราะคล้ายกับ GDB มาก ขอแนะนำอย่างยิ่งให้คุณตรวจสอบผู้ตรวจแก้จุดบกพร่องอื่น ๆ ด้วยเพื่อทำความคุ้นเคยกับคุณสมบัติของพวกเขา

มีตัวแก้จุดบกพร่องที่ดีอยู่ไม่น้อยในตลาด:

  • DBX Debugger- นี่เรือบั๊กพร้อมกับ Sun Solaris และคุณจะได้รับข้อมูลที่สมบูรณ์เกี่ยวกับบั๊กนี้โดยใช้หน้าคนของ DBX คือDBX คน

  • DDD Debugger- นี่เป็นเวอร์ชันกราฟิกของ dbx และสามารถใช้งานได้ฟรีบน Linux จะมีรายละเอียดที่สมบูรณ์ใช้หน้าคนของวววคือวววคน

คุณสามารถดูรายละเอียดที่ครอบคลุมเกี่ยวกับ GNU Debugger ได้จากลิงค์ต่อไปนี้: การดีบักด้วย GDB