ฉันสามารถตั้งเบรกพอยต์ใน 'การเข้าถึงหน่วยความจำ' ใน GDB ได้หรือไม่?


244

ฉันใช้งานแอพพลิเคชั่นผ่าน gdb และฉันต้องการตั้งค่าเบรกพอยต์เมื่อใดก็ตามที่มีการเข้าถึง / เปลี่ยนแปลงตัวแปรเฉพาะ มีวิธีที่ดีในการทำเช่นนี้หรือไม่? ฉันยังสนใจวิธีอื่น ๆ ในการตรวจสอบตัวแปรใน C / C ++ เพื่อดูว่า / เมื่อมันเปลี่ยนแปลง

คำตอบ:


286

ดูเฉพาะการหยุดพักการเขียนrwatchให้คุณหยุดอ่านและawatchให้คุณหยุดอ่าน / เขียน

คุณสามารถตั้งค่า watchpoints ที่อ่านในตำแหน่งหน่วยความจำ:

gdb$ rwatch *0xfeedface
Hardware read watchpoint 2: *0xfeedface

แต่มีข้อ จำกัด หนึ่งข้อที่ใช้กับคำสั่ง rwatch และ awatch; คุณไม่สามารถใช้ตัวแปร gdb ในนิพจน์:

gdb$ rwatch $ebx+0xec1a04f
Expression cannot be implemented with read/access watchpoint.

ดังนั้นคุณต้องขยายพวกเขาเอง:

gdb$ print $ebx 
$13 = 0x135700
gdb$ rwatch *0x135700+0xec1a04f
Hardware read watchpoint 3: *0x135700 + 0xec1a04f
gdb$ c
Hardware read watchpoint 3: *0x135700 + 0xec1a04f

Value = 0xec34daf
0x9527d6e7 in objc_msgSend ()

แก้ไข:โอ้และโดยวิธีการ คุณจำเป็นต้องมีทั้งฮาร์ดแวร์หรือซอฟต์แวร์ที่สนับสนุน ซอฟต์แวร์ช้าลงอย่างเห็นได้ชัดมาก ในการตรวจสอบว่าระบบปฏิบัติการของคุณรองรับจุดเฝ้าดูฮาร์ดแวร์หรือไม่คุณสามารถดูการตั้งค่าสภาพแวดล้อมcan-use-hw-watchpoints

gdb$ show can-use-hw-watchpoints
Debugger's willingness to use watchpoint hardware is 1.

7
หากคุณต้องการที่จะดูเป็นสมาชิกของวิธีการ c ++ watch -location mTextFormattedผมพบว่าตัวแปรนี้มีประโยชน์อย่างมาก:
Ivan Vučica

ถ้าฉันไม่มีที่อยู่ของตัวแปรล่ะ ฉันสามารถใช้ชื่อมันได้หรือไม่
Raffi Khatchadourian

5
คุณสามารถให้ GDB พิมพ์ที่อยู่ของตัวแปรด้วยตัวดำเนินการ address-of print &variable
Loduwijk

1
คำตอบนี้ไม่ได้พูดอะไรเกี่ยวกับขนาดของตำแหน่งหน่วยความจำที่ถูกดูโดยwatchคำสั่ง ในขณะเดียวกันนี้เป็นคำถามที่กำปั้นที่ปรากฏในใจหลังจากอ่านข้างต้น กี่ไบต์rwatch *0xfeedfaceจะดูจริง ๆ ?
AnT

8
@AnT ฉันคิดว่ามันน่าจะเป็นไบต์เดียวซึ่งน่าจะเป็นกรณี แต่คุณสามารถแปลงมันเป็นประเภทเฉพาะเช่นrwatch *(int *)0xfeedfaceและมันจะดูsizeof(int)ไบต์: sourceware.org/gdb/onlinedocs/gdb/Set-Watchpoints html
Askol

28

สิ่งที่คุณกำลังมองหาเรียกว่าจุดเฝ้าดู

การใช้

(gdb) watch foo: ดูค่าของตัวแปร foo

(gdb) watch *(int*)0x12345678: ดูค่าที่ชี้ไปตามที่อยู่และเลือกประเภทที่คุณต้องการ

(gdb) watch a*b + c/d: ดูการแสดงออกที่ซับซ้อนโดยพลการที่ถูกต้องในภาษาพื้นเมืองของโปรแกรม

จุดชมวิวมีสามประเภท:

  • watch : gdb จะหยุดเมื่อมีการเขียนเกิดขึ้น
  • rwatch : gdb จะแตกเมื่อมีการอ่านเกิดขึ้น
  • awatch : gdb จะแตกทั้งสองกรณี

คุณสามารถเลือกสิ่งที่เหมาะสมกว่าสำหรับความต้องการของคุณ

สำหรับข้อมูลเพิ่มเติมโปรดตรวจสอบนี้ออก


5
ฉันเขียนคำตอบอื่นเพราะคนที่มีอยู่ไม่ได้ตรงกับฉันมากนัก ...
เปาโลเอ็ม

25

การสมมติว่าคำตอบแรกนั้นหมายถึงไวยากรณ์ C-like (char *)(0x135700 +0xec1a04f)ดังนั้นคำตอบที่ต้องทำrwatch *0x135700+0xec1a04fนั้นไม่ถูกต้อง rwatch *(0x135700+0xec1a04f)ไวยากรณ์ที่ถูกต้องคือ

การขาดสิ่งเหล่า()นี้ทำให้ฉันเจ็บปวดอย่างมากในการพยายามใช้จุดเฝ้าระวังตัวเอง


9

ฉันลองต่อไปนี้:

 $ cat gdbtest.c
 int abc = 43;

 int main()
 {
   abc = 10;
 }
 $ gcc -g -o gdbtest gdbtest.c
 $ gdb gdbtest
 ...
 (gdb) watch abc
 Hardware watchpoint 1: abc
 (gdb) r
 Starting program: /home/mweerden/gdbtest 
 ...

 Old value = 43
 New value = 10
 main () at gdbtest.c:6
 6       }
 (gdb) quit

ดูเหมือนเป็นไปได้ แต่คุณต้องการการสนับสนุนฮาร์ดแวร์


หากแพลตฟอร์มของคุณไม่รองรับจุดเฝ้าดูฮาร์ดแวร์ gdb ควรกลับไปที่จุดเฝ้าดูซอฟต์แวร์
ท็อด

2

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

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

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