Score:12

ฉันจะหาไฟล์คอร์ดัมพ์ได้จากที่ใด และฉันจะดูและวิเคราะห์ backtrace (สแต็กเทรซ) ในไฟล์เดียวได้อย่างไร

ธง cn

เมื่อฉันเรียกใช้โปรแกรม C บน Ubuntu 20.04 ฉันได้รับข้อผิดพลาดรันไทม์นี้:

ข้อผิดพลาดการแบ่งส่วน (คอร์ดัมพ์)

ฉันต้องการค้นหาและดู แกนกลาง ไฟล์ แต่ฉันไม่พบที่ใดก็ได้ มันอยู่ที่ไหน และฉันจะดู backtrace ในนั้นได้อย่างไร?

Score:17
ธง cn

ทดสอบใน Ubuntu 20.04

1. เปิดใช้งานไฟล์หลัก

ก่อนอื่นให้เรียกใช้ ขีด จำกัด -c เพื่อดูว่าขนาดสูงสุดที่อนุญาตคือเท่าใดสำหรับไฟล์หลักในระบบของคุณ สำหรับฉันบน Ubuntu 20.04 ของฉันกลับมา 0ซึ่งหมายความว่าไม่สามารถสร้างไฟล์หลักได้

ulimit -- ช่วยด้วย แสดงความหมายของ -ค:

-c ขนาดสูงสุดของไฟล์หลักที่สร้างขึ้น

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

# กำหนดขนาดไฟล์การถ่ายโอนข้อมูลคอร์สูงสุดเป็นไม่จำกัด
ulimit -c ไม่จำกัด
# ยืนยันว่าตอนนี้ตั้งค่าเป็น "ไม่จำกัด"
ขีด จำกัด -c

แค่นั้นแหละ! ตอนนี้, เรียกใช้โปรแกรมของคุณและหากเกิดข้อผิดพลาดและทำการ "ถ่ายโอนข้อมูลหลัก" โปรแกรมจะถ่ายโอนข้อมูลหลักเป็น แกนกลาง ไฟล์ลงใน ไดเร็กทอรีเดียวกับที่คุณเคยเรียกไฟล์ปฏิบัติการ. ชื่อของไฟล์คือ "core"

2. ดู backtrace ใน gdb

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

ใน gcc ใช้ -ggdb -O0 เพื่อเปิดใช้การดีบู สัญลักษณ์ที่ปรับให้เหมาะสมสำหรับ จีดีบี นู๋ อีอั๊กเกอร์ คุณยังสามารถใช้ -g -O0, -g3 -O0ฯลฯ แต่ -ggdb -O0 ดีที่สุด เราต้องการการเพิ่มประสิทธิภาพระดับ 0 จริง ๆ หรือไม่ (-O0) สำหรับสิ่งนี้? ใช่ใช่เราทำ ดูคำตอบของฉันที่นี่: Stack Overflow: คอมไพเลอร์ของ -O0 ตัวเลือกและ -Og ตัวเลือก?

ตัวอย่างคำสั่ง build และ run ใน C และ C++: ดังนั้นคำสั่งบิลด์และรันแบบเต็มของคุณใน C หรือ C++ อาจมีลักษณะดังนี้:

# C สร้างและเรียกใช้คำสั่งสำหรับ "hello_world.c"
gcc -Wall -Wextra -Werror -ggdb -O0 -std=c11 -o hello_world hello_world.c \
&& ./สวัสดีชาวโลก

# C ++ สร้างและเรียกใช้คำสั่งสำหรับ "hello_world.c"
g++ -Wall -Wextra -Werror -ggdb -O0 -std=c++17 -o hello_world hello_world.c \
&& ./สวัสดีชาวโลก

เปิดไฟล์หลักใน จีดีบี แบบนี้:

เส้นทาง gdb/to/my/executable path/to/core

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

เส้นทาง gdb/to/my/executable core

ใน จีดีบีดู backtrace (สแตกการเรียกใช้ฟังก์ชันในขณะที่เกิดข้อขัดข้อง) ด้วย:

จขกท
# หรือ (คำสั่งเดียวกันทุกประการ)
ที่ไหน

# หรือ (สำหรับรายละเอียดเพิ่มเติม เช่น การดูอาร์กิวเมนต์ทั้งหมดของฟังก์ชัน--
# ขอบคุณ Peter Cordes ในความคิดเห็นด้านล่าง)
เต็ม

# สำหรับความช่วยเหลือและรายละเอียดเกี่ยวกับ gdb โปรดดูที่:
ช่วย จขกท
# หรือ
ช่วยที่ไหน

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

3. ลองทำดู

  1. ในเทอร์มินัล ให้เรียกใช้ นอน 30 เพื่อเริ่มกระบวนการพักเครื่องเป็นเวลา 30 วินาที
  2. ขณะที่กำลังทำงาน ให้กด Ctrl + \ เพื่อบังคับการถ่ายโอนข้อมูลหลัก ตอนนี้คุณจะเห็น แกนกลาง ไฟล์ในไดเรกทอรีที่คุณอยู่
  3. เนื่องจากเราไม่มีไฟล์เรียกทำงานที่มีสัญลักษณ์ดีบักอยู่ในนั้น เราจะเปิดไฟล์หลักใน gdb แทนไฟล์เรียกทำงานที่มีสัญลักษณ์ + ไฟล์หลัก ดังนั้นเรียกใช้ แกน gdb -c เพื่อเปิดไฟล์หลักที่สร้างขึ้นโดยการบังคับหยุดทำงาน
  4. คุณจะเห็นสิ่งนี้ สังเกตว่ามันรู้ว่าคุณเรียกคำสั่งอะไร (นอน 30) เมื่อเกิดการถ่ายโอนข้อมูลหลัก:
    Core ถูกสร้างขึ้นโดย `sleep 30'
    โปรแกรมสิ้นสุดด้วยสัญญาณ SIGQUIT, Quit
    #0 0x00007f93ed32d334 ใน ?? ()
    (จีดีบี) 
    
  5. วิ่ง จขกท หรือ ที่ไหน เพื่อดูย้อนหลัง คุณจะเห็นสิ่งนี้:
    (gdb) บต
    #0 0x00007f93ed32d334 ใน ?? ()
    #1 0x000000000000000a ใน ?? ()
    #2 0x00007f93ed2960a5 ใน ?? ()
    #3 0x0000000000000000 ใน ?? ()
    (จีดีบี)
    
  6. ที่อยู่เหล่านี้เป็นที่อยู่ของฟังก์ชันที่เรียกบน call stack หากคุณเปิดใช้สัญลักษณ์การดีบัก คุณจะเห็นข้อมูลเพิ่มเติมมากมาย รวมถึงชื่อฟังก์ชันและหมายเลขบรรทัด เช่นนี้ (ดึงมาจากโปรแกรม C ของฉัน):
    #10 0x00007fc1152b8ebf ใน __printf (format=<optimized out>) ที่ printf.c:33
    #11 0x0000562bca17b3eb ใน fast_malloc (num_bytes=1024) ที่ src/fast_malloc.c:225
    #12 0x0000562bca17bb66 ใน malloc (num_bytes=1024) ที่ src/fast_malloc.c:496
    

4. ลืมไฟล์หลักและเรียกใช้โปรแกรมไปยังจุดผิดพลาดใน gdb โดยตรง!

ตามที่ @Peter Cordes ระบุไว้ในความคิดเห็นด้านล่าง คุณยังสามารถเรียกใช้โปรแกรมภายใน gdb ได้โดยตรง ปล่อยให้มันพังที่นั่น ดังนั้นคุณไม่จำเป็นต้องเปิดไฟล์หลักในภายหลัง! เขากล่าวว่า:

คำสั่ง GDB เหล่านั้นไม่เฉพาะเจาะจงกับไฟล์หลัก แต่จะทำงานทุกครั้งที่คุณหยุดที่เบรกพอยต์ หากคุณมีข้อขัดข้องที่ทำซ้ำได้ มักจะง่ายกว่า/ดีกว่าในการรันโปรแกรมของคุณภายใต้ GDB (เช่น gdb ./a.out) ดังนั้น GDB จะมีกระบวนการในหน่วยความจำแทนไฟล์หลัก ข้อได้เปรียบหลักคือคุณสามารถตั้งจุดพักหรือจุดเฝ้าดูที่ใดที่หนึ่งได้ ก่อน สิ่งที่ผิดพลาดและขั้นตอนเดียวเพื่อดูว่าเกิดอะไรขึ้น หรือด้วยสิ่งอำนวยความสะดวกในการบันทึกของ GDB คุณอาจก้าวไปได้ ถอยหลัง และดูว่าอะไรนำไปสู่ความผิดพลาด แต่นั่นอาจไม่สม่ำเสมอ ช้า และใช้หน่วยความจำมาก

ตามที่ระบุไว้ข้างต้น คุณควรรวบรวมโปรแกรมของคุณด้วยสัญลักษณ์การดีบักบนและด้วยการปรับให้เหมาะสมระดับ 0 โดยใช้ -ggdb -O0. ดูตัวอย่างคำสั่ง build และ run ทั้งหมดในภาษา C และ C++ ด้านบน

ตอนนี้รันโปรแกรมใน gdb:

# เปิดปฏิบัติการใน gdb
เส้นทาง gdb/to/my/executable
# เรียกใช้ (หากยังขัดข้องอยู่ คุณจะเห็นว่ามันขัดข้อง)
ร 
# ดู backtrace (กองโทร)
จขกท  
#เลิกทำเถอะครับ 
ถาม

และหากคุณจำเป็นต้องบันทึก backtrace ด้วยตนเองลงในไฟล์บันทึกเพื่อวิเคราะห์ในภายหลัง คุณสามารถทำได้ดังนี้ (ดัดแปลงมาจาก บันทึกในของฉัน eRCaGuy_dotfiles ซื้อคืนที่นี่):

ตั้งค่าไฟล์บันทึก gdb_log.txt
ตั้งค่าการเข้าสู่ระบบ
ตั้งค่าคำสั่งติดตามบน
แสดงการบันทึก # พิสูจน์การบันทึกเปิดอยู่
ล้างออก
ตั้งพิมพ์สวยบน
bt #ดูย้อนหลัง
ตั้งค่าการออกจากระบบ  
แสดงการบันทึก # พิสูจน์ว่าการบันทึกถูกปิด

เสร็จแล้ว! ตอนนี้ คุณได้บันทึก gdb backtrace ในไฟล์ "gdb_log.txt" แล้ว

อ้างอิง:

  1. [คำตอบที่ฉันต้องการอยู่ในคำถามนี้] https://stackoverflow.com/questions/2065912/core-dumped-but-core-file-is-not-in-the-current-directory
  2. https://stackoverflow.com/questions/5115613/core-dump-file-analysis
  3. https://stackoverflow.com/questions/8305866/how-do-i-analyze-a-programs-core-dump-file-with-gdb-when-it-has-command-line-pa/30524347#30524347
  4. [ข้อมูลที่มีประโยชน์มากรวมถึง เดอะ Ctrl + \ เคล็ดลับในการบังคับการถ่ายโอนข้อมูลหลัก!] https://unix.stackexchange.com/questions/277331/segmentation-fault-core-dumped-to-where-what-is-it-and-why/409776#409776
  5. [อ้างอิงจากคำตอบข้างต้น] https://unix.stackexchange.com/questions/179998/where-to-search-for-the-core-file-generated-by-the-crash-of-a-linux-application/180004#180004
  6. [คำตอบอยู่ในคำถามเอง] ฉันจะหาคอร์ดัมพ์ใน Ubuntu 16.04LTS ได้ที่ไหน
  7. [คำตอบของฉัน] Stack Overflow: คอมไพเลอร์ของ -O0 ตัวเลือกและ -Og ตัวเลือก?

อ่านเพิ่มเติมที่ต้องทำ

  1. [ฉันยังต้องศึกษาและลองใช้] วิธีใช้ LD_PRELOAD กับ จีดีบี: https://stackoverflow.com/questions/10448254/how-to-use-gdb-with-ld-preload
Peter Cordes avatar
fr flag
หากคุณมีสัญลักษณ์การดีบัก `bt full` ก็ดี: แสดง args และสิ่งต่างๆ หรือแม้กระทั่ง `thread apply all bt full` สำหรับโปรแกรมแบบมัลติเธรด (แม้ว่าจะดูมากกว่าปกติที่คุณต้องการดูพร้อมกัน ดังนั้นการส่งรายงานข้อบกพร่องจึงมีประโยชน์มากกว่าการใช้งานของคุณเอง)
Gabriel Staples avatar
cn flag
@PeterCordes ขอบคุณ ฉันได้เพิ่มบันทึกเกี่ยวกับ `bt full` ในคำตอบด้วย ฉันยังใหม่กับการดูที่การถ่ายโอนข้อมูลหลัก การเขียนคำตอบนี้เมื่อวานนี้เป็นครั้งแรกที่ฉันเห็นไฟล์ `core` และเป็นครั้งแรกที่ฉันทำ backtrace ในไฟล์นั้น
Peter Cordes avatar
fr flag
คำสั่ง GDB เหล่านั้นไม่เฉพาะเจาะจงกับไฟล์หลัก แต่จะทำงานทุกครั้งที่คุณหยุดที่เบรกพอยต์ หากคุณเกิดข้อขัดข้องที่ทำซ้ำได้ มักจะง่ายกว่า/ดีกว่าในการรันโปรแกรมของคุณภายใต้ GDB (เช่น `gdb ./a.out`) ดังนั้น GDB จะมีกระบวนการในหน่วยความจำแทนที่จะเป็นไฟล์หลัก ข้อได้เปรียบหลักคือคุณสามารถตั้งค่าเบรกพอยต์หรือจุดเฝ้าดูที่ใดที่หนึ่ง *ก่อน* สิ่งที่ขัดข้อง และขั้นตอนเดียวเพื่อดูว่าเกิดอะไรขึ้น หรือด้วยสิ่งอำนวยความสะดวกในการบันทึกข้อมูลของ GDB คุณอาจสามารถก้าว *ถอยหลัง* และดูว่าอะไรนำไปสู่ความผิดพลาดได้ แต่นั่นอาจไม่สม่ำเสมอ ช้า และใช้หน่วยความจำมาก
Score:1
ธง cn

พบผ่านการค้นหา ฉันใช้ Ubuntu Mate 21.10 สำหรับผู้ที่ใช้ Ubuntu รุ่นเก่า แอพ จะสร้างการถ่ายโอนข้อมูลใน /var/lib/apport/coredump.

หากคุณไม่พบไฟล์การถ่ายโอนข้อมูลหลักของคุณ แมว /var/log/apport.log. เมื่อฉันทำอย่างนั้น ฉันเห็น:

ปฏิบัติการไม่ได้อยู่ในแพ็คเกจโดยไม่สนใจ
เรียกใช้ pid 5545, สัญญาณ 11, ขีดจำกัดคอร์ 0, โหมดดัมพ์ 1

สังเกตขีดจำกัดคอร์ 0 ซึ่งหมายความว่าจะไม่มีการสร้างไฟล์ดัมพ์คอร์ ดังนั้นฉันจึงรันคำสั่งที่แสดงในโพสต์นี้ (ulimit -c ไม่จำกัด) และในครั้งนี้ apport.log แสดงสิ่งนี้:

การเขียนการถ่ายโอนข้อมูลหลักไปยัง core._my_prog.1000.e43b2f33-4708-438c-a7d7-05062f381382.5650.795448 (จำกัด: -1)

ฉันไม่พบสิ่งนี้ในไดเร็กทอรีปัจจุบันหรือไดเร็กทอรีที่มีไฟล์เรียกทำงาน ดังนั้นฉันจึงค้นหาทั้งระบบและพบใน /var/lib/apport/coredump.

โพสต์คำตอบ

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