เรียกใช้แอปพลิเคชันใน GDB จนกว่าจะมีข้อยกเว้นเกิดขึ้น


102

ฉันกำลังทำงานกับแอพพลิเคชั่นมัลติเธรดและต้องการดีบักโดยใช้ GDB

ปัญหาคือหนึ่งในเธรดของฉันยังคงตายด้วยข้อความ:

pure virtual method called
terminate called without an active exception
Abort

ฉันรู้สาเหตุของข้อความนั้น แต่ฉันไม่รู้ว่ามันเกิดขึ้นที่ไหนในชุดข้อความ backtrace จะเป็นประโยชน์จริงๆ

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


GDB รายงานสัญญาณใดเมื่อหยุดทำงานชั่วคราว คุณควรจะสามารถเรียกใช้คำสั่งเช่นhandle SIGUSR1 pass noprint nostop
Hasturkun

คำตอบ:


147

คุณสามารถลองใช้ "catchpoint" ( catch throw) เพื่อหยุดการดีบักเกอร์ ณ จุดที่สร้างข้อยกเว้น

ข้อความที่ตัดตอนมาจากคู่มือ gdb ต่อไปนี้จะอธิบายถึงคุณลักษณะ catchpoint


5.1.3 การตั้งจุดสังเกต

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

  • จับเหตุการณ์

    หยุดเมื่อเกิดเหตุการณ์ เหตุการณ์อาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้:

    • โยน

      การขว้างข้อยกเว้น C ++

    • จับ

      การจับข้อยกเว้น C ++

    • ผู้บริหาร

      โทรหาผู้บริหาร ขณะนี้ใช้ได้เฉพาะกับ HP-UX เท่านั้น

    • ส้อม

      การเรียกร้องให้แยก ขณะนี้ใช้ได้เฉพาะกับ HP-UX เท่านั้น

    • vfork

      โทรหา vfork ขณะนี้ใช้ได้เฉพาะกับ HP-UX เท่านั้น

    • โหลดหรือโหลด libname

      การโหลดแบบไดนามิกของไลบรารีที่แบ่งใช้หรือการโหลดไลบรารี libname ขณะนี้ใช้ได้เฉพาะกับ HP-UX เท่านั้น

    • ยกเลิกการโหลดหรือยกเลิกการโหลด libname

      การยกเลิกการโหลดไลบรารีที่แบ่งใช้ที่โหลดแบบไดนามิกหรือการยกเลิกการโหลดไลบรารี libname ขณะนี้ใช้ได้เฉพาะกับ HP-UX เท่านั้น

  • เหตุการณ์ tcatch

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

ใช้info breakคำสั่งเพื่อแสดงรายการจุดรับกระแสปัจจุบัน

ขณะนี้มีข้อ จำกัด บางประการในการจัดการข้อยกเว้น C ++ (จับโยนและจับ) ใน GDB:

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

  • คุณไม่สามารถเพิ่มข้อยกเว้นแบบโต้ตอบได้

  • คุณไม่สามารถติดตั้งตัวจัดการข้อยกเว้นแบบโต้ตอบได้

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

หากต้องการหยุดก่อนที่จะมีการเรียกตัวจัดการข้อยกเว้นคุณจำเป็นต้องมีความรู้เกี่ยวกับการนำไปใช้งาน ในกรณีของ GNU C ++ มีการเพิ่มข้อยกเว้นโดยการเรียกใช้ฟังก์ชันไลบรารีชื่อ __raise_exception ซึ่งมีอินเตอร์เฟส ANSI C ดังต่อไปนี้:

/* addr is where the exception identifier is stored.
   id is the exception identifier.  */
void __raise_exception (void **addr, void *id);

ในการทำให้ดีบักเกอร์ตรวจจับข้อยกเว้นทั้งหมดก่อนที่การคลายสแต็กจะเกิดขึ้นให้ตั้งค่าเบรกพอยต์ที่ __raise_exception (ดูหัวข้อเบรกพอยต์จุดเฝ้าดูและข้อยกเว้น)

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


catch throw std::runtime_exceptionนอกจากนี้คุณยังสามารถระบุชนิดของข้อยกเว้นที่จะจับเช่น
scai

5

ตั้งค่าเบรกพอยต์บน __pure_virtual


ในคำตอบของ @JeffreyHill เรียกว่า __cxa_pure_virtual ในขณะนี้ ฉันไม่ทราบวิธีการตรวจสอบตัวเองดังนั้นฉันจึงไม่ต้องการแก้ไขคำตอบ ฉันไม่ได้ตั้งใจจะลงคะแนน แต่ตอนนี้คำตอบอาจผิดและควรได้รับการแก้ไขโดยคนที่รู้ว่าอะไรถูกต้อง
Philipp Claßen

5

FWIW เห็นได้ชัดว่าใน gcc 4.1 ชื่อฟังก์ชันที่เหมาะสมได้เปลี่ยนไปและต้องตั้งค่าเบรกพอยต์ในฟังก์ชันนี้

__cxa_pure_virtual


0

ด้านล่างเดียวเท่านั้นที่ใช้ได้กับฉันกับ gdb 8.3:

break _Unwind_RaiseException

"จับโยน" หรือ "ทำลาย __cxx_throw" ไม่ได้ผลสำหรับฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.