วิธีการใช้งาน gdbserver สำหรับการดีบักระยะไกลบน Linux

การปรับปรุงครั้งล่าสุด: 14/01/2026
ผู้แต่ง: ไอแซก
  • gdbserver ทำหน้าที่เป็นเอเจนต์ระยะไกลของ GDB เพื่อควบคุมกระบวนการบนเครื่องอื่นผ่านทาง TCP หรือพอร์ตอนุกรม
  • ในการดีบักจากระยะไกล สิ่งสำคัญคือการคอมไพล์ด้วย สัญลักษณ์, usar el gdb adecuado y configurar bien rutas de símbolos y fuentes.
  • gdbserver มีโหมดการทำงานแบบกระบวนการเดียวและแบบหลายกระบวนการ รวมถึงการทำงานร่วมกับ WinDbg และ QEMU สำหรับการดีบักเคอร์เนล
  • ตัวเลือกต่างๆ เช่น --debug, sysroot และการจำกัดขนาดค่า ช่วยในการวินิจฉัยปัญหาและทำให้เซสชันมีเสถียรภาพ

การดีบักระยะไกลด้วย gdbserver

หากคุณเขียนโปรแกรมด้วยภาษา C หรือ C++ ลินุกซ์ และคุณไม่เคยใช้ gdbserver มาก่อนเลยคุณกำลังพลาดเครื่องมือที่มีประโยชน์ที่สุดอย่างหนึ่งสำหรับการดีบักกระบวนการทำงานจากระยะไกล ไม่ว่าจะเป็นบนเซิร์ฟเวอร์ ระบบฝังตัว หรือแม้แต่ภายในเครื่องเสมือนหรือ WSL gdbserver ไม่ใช่สิ่ง "มหัศจรรย์" หรือสงวนไว้สำหรับผู้เชี่ยวชาญเท่านั้น มันเป็นเพียงโปรแกรมขนาดเล็กที่สื่อสารกับ gdb และควบคุมการทำงานของกระบวนการเป้าหมาย

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

gdbserver คืออะไร และเมื่อไหร่จึงเหมาะสมที่จะใช้มัน?

gdbserver คืออะไร?

gdbserver เป็น "เอเจนต์" สำหรับการดีบักระยะไกลสำหรับ GNU gdbหน้าที่ของมันมีความเฉพาะเจาะจงมาก คือ มันจะทำงานบนเครื่องที่โปรแกรมที่จะวิเคราะห์กำลังทำงานอยู่ ควบคุมกระบวนการนั้น (หรือหลายกระบวนการ) และสื่อสารกับไคลเอ็นต์ gdb ที่อยู่บนเครื่องอื่น (หรือบนเครื่องเดียวกัน) ผ่านการเชื่อมต่อระยะไกล

ในการใช้งานประจำวัน gdbserver จะถูกใช้ในสองสถานการณ์ทั่วไปซอฟต์แวร์ดีบักที่ทำงานในสภาพแวดล้อมแบบฝังตัว (เราเตอร์ บอร์ดที่มีระบบปฏิบัติการ Linux เวอร์ชันลดทอน อุปกรณ์ต่างๆ) IoTเป็นต้น) และกระบวนการดีบักบนเครื่อง Linux ระยะไกล ซึ่งไม่สะดวกหรือไม่ก็เป็นไปไม่ได้ที่จะมี gdb เวอร์ชันเต็มที่มีไลบรารีและสัญลักษณ์ทั้งหมด

ในทางปฏิบัติ gdbserver จัดการงานต่างๆ เช่น อ่านและเขียนรีจิสเตอร์และหน่วยความจำของกระบวนการ ควบคุมการทำงาน (ดำเนินการต่อ หยุดชั่วคราว ก้าวผ่านทีละขั้นตอน) จัดการเบรกพอยต์ และส่งข้อมูลทั้งหมดนี้ไปยัง gdb โดยใช้โปรโตคอลระยะไกลของ GDB หลักการนี้คล้ายคลึงกับเครื่องมืออย่าง OpenOCD ซึ่งทำหน้าที่เป็นสะพานเชื่อมระหว่าง gdb และ ฮาร์ดแวร์ ภายนอก โดยมีความแตกต่างตรงที่ gdbserver ทำงานบนระบบเดียวกันกับที่ไฟล์ไบนารีทำงาน

ถ้าคุณมาจากสภาพแวดล้อมแบบนั้น Windows เป็นเรื่องที่น่าสนใจเช่นกันที่จะทราบ โปรแกรมดีบักเกอร์อย่าง WinDbg สามารถสื่อสารกับ gdbserver บน Linux ได้ ดังนั้นคุณจึงสามารถดีบักกระบวนการของผู้ใช้บน Linux จาก WinDbg โดยใช้การสนับสนุนการดีบักระยะไกลผ่านโปรโตคอล gdb ที่ Microsoft ได้รวมไว้ในเวอร์ชันล่าสุด

ข้อกำหนดพื้นฐานสำหรับการดีบักด้วย gdb และ gdbserver

ข้อกำหนดสำหรับการใช้งาน gdbserver

ก่อนที่คุณจะเริ่มดีบักระยะไกล คุณต้องเข้าใจความสัมพันธ์ระหว่างโฮสต์และเป้าหมายเสียก่อน. และ เป้า นี่คือเครื่องคอมพิวเตอร์ที่โปรแกรมที่ต้องการดีบักทำงานอยู่ และเป็นเครื่องที่จะเรียกใช้ gdbserver; เจ้าภาพ นี่คือเครื่องที่คุณจะใช้รัน gdb (หรือ WinDbg) และเป็นที่ที่คุณจะมีซอร์สโค้ด และหากมี ควรมีสัญลักษณ์สำหรับการดีบักด้วย

จุดเริ่มต้นที่สำคัญคือการคอมไพล์ไบนารีด้วยสัญลักษณ์ใน GCC หรือ g++ สามารถทำได้โดยใช้แฟล็ก -gและโดยปกติแล้วควรปิดใช้งานการเพิ่มประสิทธิภาพด้วย (ตัวอย่างเช่น ด้วย) -O0วิธีนี้ช่วยให้ดีบักเกอร์แสดงตัวแปร มาโคร และโครงสร้างโค้ดได้อย่างแม่นยำยิ่งขึ้น สำหรับมาโครเฉพาะ คุณสามารถใช้ระดับการดีบักที่สูงขึ้นได้ เช่น -g3.

ฝั่งโฮสต์ คุณจะต้องมี gdb เวอร์ชันที่เข้ากันได้ โดยใช้สถาปัตยกรรมเป้าหมาย ในการดีบักระบบฝังตัว MIPS, ARM หรือสถาปัตยกรรมอื่นๆ คุณต้องใช้ gdb ของชุดเครื่องมือข้ามแพลตฟอร์มที่เกี่ยวข้อง (ตัวอย่างเช่น) arm-none-eabi-gdb o gdb-multiarch) และหากจำเป็น ให้กำหนดค่าสถาปัตยกรรมและลำดับไบต์ด้วย คำสั่ง ในขณะที่ set arch y set endian.

ในส่วนของการเชื่อมต่อ gdbserver รองรับการเชื่อมต่อหลักสองประเภทการเชื่อมต่อแบบอนุกรม (พบได้บ่อยในฮาร์ดแวร์ฝังตัว ผ่าน UART) และ TCP/IP ซึ่งสะดวกที่สุดเมื่อเป้าหมายอยู่บนเครือข่ายเดียวกันหรือเป็นเครื่อง Linux ที่สามารถเข้าถึงได้ผ่านเครือข่าย ในทั้งสองกรณี จะใช้คำสั่งจาก gdb target remote เพื่อเชื่อมต่อกับเอนด์พอยต์ที่เปิดเผยโดย gdbserver

วิธีการเริ่มต้นใช้งาน gdbserver: โหมดกระบวนการเดียวและโหมดหลายกระบวนการ

โหมดการทำงานของ gdbserver

gdbserver สามารถทำงานได้สองวิธีหลักๆ เมื่อเราพูดถึงการดีบักในโหมดผู้ใช้: หมายถึงการดีบักที่เกี่ยวข้องโดยตรงกับกระบวนการเดียว หรือในฐานะ "เซิร์ฟเวอร์กระบวนการ" ที่อนุญาตให้แสดงรายการและเชื่อมต่อกับกระบวนการระบบต่างๆ

ในโหมดประมวลผลเดียว คุณเรียกใช้ gdbserver โดยระบุโฮสต์:พอร์ต และโปรแกรมที่จะเรียกใช้ ในตัวอย่างง่ายๆ บนเครื่องเดสก์ท็อป Linux คุณสามารถทำได้ดังนี้:

คำสั่ง: gdbserver localhost:3333 foo

ด้วยคำสั่งนั้น gdbserver จะเริ่มต้นไบนารี foo และเขายังคงฟังอยู่ที่พอร์ต 3333โปรแกรมจะยังคงหยุดทำงานจนกว่า gdb จะเชื่อมต่อจากระยะไกล เมื่อ gdb เชื่อมต่อแล้ว โปรแกรมก็จะเริ่มทำงาน target remote localhost:3333กระบวนการดังกล่าวเริ่มถูกควบคุมโดยเครื่องบด

ในโหมดมัลติโปรเซส (เซิร์ฟเวอร์โปรเซส) จะใช้ตัวเลือกนี้ --multiในกรณีนี้ gdbserver ไม่ได้เรียกใช้โปรแกรมใด ๆ โดยตรง แต่จะคอยรับฟังการเชื่อมต่อที่เข้ามา และปล่อยให้ไคลเอ็นต์ (gdb หรือ WinDbg) จัดการว่าจะสร้างหรือเชื่อมต่อกับกระบวนการใด:

  Google เปิดตัว Gemini Code Assist ผู้ช่วยการเขียนโปรแกรมที่ขับเคลื่อนด้วย AI ฟรี

คำสั่ง: gdbserver --multi localhost:1234

เมื่อใช้งาน WinDbg บน Linux โหมดการทำงานหลายโหมดนี้มีความน่าสนใจเป็นพิเศษเนื่องจากจาก WinDbg เอง คุณสามารถแสดงรายการกระบวนการทำงานบนระบบระยะไกล ดู PID ผู้ใช้ และบรรทัดคำสั่ง และเชื่อมต่อกับกระบวนการที่คุณสนใจได้ ในลักษณะเดียวกับที่ทำกับเซิร์ฟเวอร์กระบวนการทำงาน dbgsrv.exe บน Windows

การดีบักระยะไกลด้วย gdbserver และ gdb ทีละขั้นตอน

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

ขั้นแรก คุณต้องเขียนและคอมไพล์โปรแกรมขนาดเล็กตัวอย่างเช่น ลูปง่ายๆ ที่พิมพ์ตัวนับออกมา:

คำสั่ง: gcc -g foo.c -o foo

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

ขั้นตอนต่อไปคือการเริ่มต้น gdbserver บนเครื่องเป้าหมายถ้าเครื่องโฮสต์และเครื่องเป้าหมายเป็นเครื่องเดียวกัน แสดงว่า:

คำสั่ง: gdbserver localhost:3333 foo

คุณจะเห็นข้อความที่คล้ายกับข้อความนี้ “สร้างกระบวนการ foo แล้ว; pid = XXXX; กำลังรอรับการเชื่อมต่อที่พอร์ต 3333” นี่แสดงว่า gdbserver ได้สร้างกระบวนการแล้วและกำลังรอให้ gdb เชื่อมต่อ หากคุณใช้งานบนระบบที่ต้องการสิทธิ์เพิ่มเติม (เช่น เพื่อเชื่อมต่อกับกระบวนการของระบบ) คุณอาจต้องเรียกใช้คำสั่งด้วยสิทธิ์เพิ่มเติม sudoแต่การระมัดระวังเมื่อให้การอนุญาตนั้นเป็นเรื่องที่ฉลาดเสมอ ราก ไปยังเครื่องกำจัดกำมะถัน

บนเครื่องโฮสต์ ให้เริ่มใช้งาน gdb โดยระบุไฟล์ปฏิบัติการในเครื่อง (ตัวเดียวกับที่กำลังทำงานอยู่บนเครื่องเป้าหมาย หรือสำเนาที่เหมือนกันทุกประการพร้อมสัญลักษณ์):

คำสั่ง: gdb foo

เมื่อเข้าสู่ gdb แล้ว คุณจะต้องสร้างการเชื่อมต่อระยะไกลด้วย:

คำสั่ง: target remote localhost:3333

ในขั้นตอนนี้ gdb จะโหลดสัญลักษณ์จากไฟล์ไบนารีในเครื่องมันจะซิงโครไนซ์กับ gdbserver และควบคุมกระบวนการที่กำลังทำงานอยู่ภายใต้ gdbserver จากนั้นขั้นตอนก็จะเป็นไปตามปกติ คือใช้คำสั่งต่างๆ เช่น break เพื่อกำหนดจุดแตกหัก continue, step, next, print เพื่อตรวจสอบตัวแปร backtrace เพื่อดูแบตเตอรี่ เป็นต้น

การเชื่อมต่อกับกระบวนการที่กำลังทำงานอยู่ด้วย gdbserver

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

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

คำสั่ง: gdbserver localhost:3333 --attach <pid_de_httpd>

ฝั่งโฮสต์ คุณจะต้องใช้ gdb เวอร์ชันที่รองรับสถาปัตยกรรมของเราเตอร์ตัวอย่างเช่น gdb-multiarchกำหนดค่าสถาปัตยกรรมและลำดับไบต์ล่วงหน้า:

คำสั่ง: set arch mips
set endian big

จากนั้นให้ระบุไฟล์ในเครื่องที่ประกอบด้วยสัญลักษณ์เหล่านั้น ของไบนารีระยะไกล (ตัวอย่างเช่น) file httpdและหากจำเป็น คุณสามารถบอก gdb ว่าไบนารีนั้นกำลังทำงานอยู่ที่ใดบนเป้าหมายด้วย set remote exec-file /usr/bin/httpdสุดท้ายนี้ เช่นเดียวกับที่ผ่านมา คุณจะได้เชื่อมต่อกับ:

คำสั่ง: target remote 192.168.0.1:3333

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

การใช้งาน gdbserver ร่วมกับ WinDbg บน Linux

ในช่วงไม่กี่ปีที่ผ่านมา ไมโครซอฟต์ได้เพิ่มการสนับสนุนการดีบักกระบวนการ Linux ใน WinDbg ใช้ gdbserver เป็นแบ็กเอนด์ ฟังก์ชันนี้มีไว้สำหรับสถานการณ์ที่คุณทำงานบน Windows แต่โค้ดทำงานบน Linux (รวมถึง WSL)

ในการดีบักกระบวนการ Linux เฉพาะด้วย WinDbg โดยใช้ gdbserverขั้นตอนจะเป็นประมาณนี้: ขั้นแรก คุณต้องค้นหาโปรเซสเป้าหมายบนเครื่อง Linux ด้วยคำสั่งเช่นนี้ ps -A (ตัวอย่างเช่น python3 (ซึ่งกำลังทำงานอยู่) จากนั้นให้เรียกใช้ gdbserver บนเป้าหมาย:

คำสั่ง: gdbserver localhost:1234 python3

หากสภาพแวดล้อมเอื้ออำนวย คุณอาจจำเป็นต้องใช้ sudo gdbserver ...โดยใช้มาตรการรักษาความปลอดภัยเช่นเดิม เมื่อ gdbserver แสดงว่า "กำลังรับฟังที่พอร์ต 1234" แล้ว ใน WinDbg ให้ไปที่ "ไฟล์ / เชื่อมต่อกับดีบักเกอร์ระยะไกล" และระบุสตริงการเชื่อมต่อในรูปแบบต่อไปนี้:

คำสั่ง: gdb:server=localhost,port=1234

WinDbg ใช้ "ไดรเวอร์" โปรโตคอล gdb ขนาดเล็กในการสื่อสารกับ gdbserver และเมื่อการเชื่อมต่อถูกสร้างขึ้นแล้ว การเชื่อมต่อจะหยุดอยู่ที่จุดนั้น รองเท้า ของกระบวนการ จากนั้นคุณสามารถใช้หน้าต่างสแต็ก โมดูล หน่วยความจำ จุดหยุดการทำงาน รวมถึงคำสั่งต่างๆ เช่น k เพื่อดูแบตเตอรี่หรือ lm เพื่อแสดงรายการโมดูล (โปรดทราบว่าบางคำสั่งคาดหวังรูปแบบ PE ไม่ใช่ ELF ดังนั้นอาจแสดงข้อมูลที่ผิดเพี้ยนในบางกรณี)

gdbserver และ WinDbg process server

นอกเหนือจากกรณีการทำงานแบบกระบวนการเดียวแล้ว WinDbg ยังสามารถเชื่อมต่อกับ gdbserver ซึ่งทำหน้าที่เป็นเซิร์ฟเวอร์กระบวนการได้อีกด้วย เพื่อให้ทำงานในลักษณะที่คล้ายคลึงกับการทำงานกับกระบวนการ Windows ระยะไกล ในโหมดนี้ gdbserver จะถูกเรียกใช้งานด้วย --multi และโดยไม่มีกระบวนการที่เกี่ยวข้อง:

  วิธีที่ดีที่สุดในการเปิดใช้งานโหมดพลังงานต่ำบน iPhone

คำสั่ง: sudo gdbserver --multi localhost:1234

จาก WinDbg ให้เลือก “ไฟล์ / เชื่อมต่อกับเซิร์ฟเวอร์ประมวลผล” และคุณนำสตริงการเชื่อมต่อกลับมาใช้ใหม่ gdb:server=localhost,port=1234เมื่อการเชื่อมต่อทำงานอยู่ คุณสามารถแสดงรายการกระบวนการ Linux ที่ใช้งานได้ และเชื่อมต่อกับกระบวนการที่คุณต้องการ หรือแม้แต่เริ่มกระบวนการใหม่ได้

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

เพื่อยุติเซสชันของเจ้าหน้าที่ส่งหมายศาลโดยปกติแล้ว การกด CTRL+D ในคอนโซลที่ gdbserver กำลังทำงานอยู่ และหยุดการดีบักจาก WinDbg ก็เพียงพอแล้ว ในบางกรณีที่รุนแรง หากมีปัญหาการซิงโครไนซ์ อาจจำเป็นต้องปิดดีบักเกอร์ทั้งหมดและเริ่มต้น gdbserver ใหม่ตั้งแต่ต้น

การจัดการสัญลักษณ์และซอร์สโค้ดในการดีบักระยะไกล

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

ในสถานการณ์การใช้งาน gdb + gdbserver แบบคลาสสิก การเก็บสำเนาของไฟล์ปฏิบัติการพร้อมสัญลักษณ์ไว้ในเครื่องโฮสต์ถือเป็นวิธีที่ดีที่สุด (ที่ยังไม่ได้ตัดสัญลักษณ์) และโครงสร้างต้นไม้ของซอร์สโค้ด gdb ไม่จำเป็นต้องให้ไบนารีระยะไกลมีสัญลักษณ์อยู่ด้วย เพียงแค่ไฟล์ในเครื่องที่คุณโหลดด้วย gdb ก็เพียงพอแล้ว file จับคู่ไฟล์ปฏิบัติการระยะไกลที่ระดับออฟเซ็ต

ในโลกของ WinDbg และการดีบักบน Linux บริการต่างๆ เช่น DebugInfoD ก็ได้ถือกำเนิดขึ้นเช่นกันซึ่งแสดงสัญลักษณ์และแบบอักษรผ่าน HTTP WinDbg สามารถใช้เส้นทางพิเศษประเภทนี้ได้ DebugInfoD*https://debuginfod.elfutils.org ทั้งสองเข้า .sympath ในขณะที่ .srcpath เพื่อดาวน์โหลดสัญลักษณ์ DWARF และซอร์สโค้ดไบนารี Linux ELF ตามต้องการ

ในตัวอย่างเฉพาะเจาะจงกับ WSL ซึ่งโค้ดของผู้ใช้อยู่ภายใต้ C:\Users\Bob\คุณสามารถบอก WinDbg ได้ว่า:

คำสั่ง: .sympath C:\Users\Bob\
.srcpath C:\Users\Bob\

และหากคุณต้องการใช้ DebugInfoD สำหรับไฟล์ไบนารีของระบบด้วย:

คำสั่ง: .sympath+ DebugInfoD*https://debuginfod.elfutils.org
.srcpath+ DebugInfoD*https://debuginfod.elfutils.org

ด้วยการตั้งค่านี้ เมื่อคุณตรวจสอบสแต็กหรือเข้าสู่ฟังก์ชัน libcWinDbg อาจพยายามดาวน์โหลดสัญลักษณ์ DWARF ที่เกี่ยวข้อง และหากเซิร์ฟเวอร์เปิดเผยโค้ดด้วย ก็อาจแสดงซอร์สโค้ดโดยละเอียด แม้ว่าภายในแล้วชุดเครื่องมือของ Windows จะไม่จัดการ ELF และ DWARF ได้อย่าง "เป็นธรรมชาติ" เหมือนกับ PE และ PDB ก็ตาม

ตัวอย่างการใช้งานจริง: การดีบักโปรแกรม C++ ด้วย gdbserver และ WinDbg

ตัวอย่างประกอบคือแอปพลิเคชัน C++ ขนาดเล็กที่เขียนคำทักทายลงบนหน้าจอคอมไพล์ใน WSL พร้อมสัญลักษณ์ดีบัก ลองนึกภาพโปรแกรมที่จองไว้ std::array<wchar_t, 50> และคัดลอกข้อความที่ยาวกว่าลงไป ทำให้ข้อความถูกตัดทอนและตัวอักษรปรากฏขึ้น ???? ในตอนท้าย

หลังจากคอมไพล์ด้วยอะไรบางอย่างเช่นนี้:

คำสั่ง: g++ DisplayGreeting.cpp -g -o DisplayGreeting

คุณเริ่มใช้งาน gdbserver กับไฟล์ไบนารีนั้น:

คำสั่ง: gdbserver localhost:1234 DisplayGreeting

ใน WinDbg คุณเชื่อมต่อด้วยสตริง gdb:server=localhost,port=1234 และเมื่อสร้างเซสชันและกำหนดค่าเส้นทางสัญลักษณ์และฟอนต์เรียบร้อยแล้ว คุณก็ตั้งเบรกพอยต์ใน DisplayGreeting!mainคุณสามารถใช้ dx greeting เพื่อตรวจสอบอาร์เรย์ภายในเครื่องและดูขนาดของมัน (50 ตำแหน่ง) และตรวจสอบด้วยสายตาในแท็บหน่วยความจำหรือในมุมมองตัวแปรว่าข้อความทักทายถูกตัดไปอย่างไร

จุดเด่นของตัวอย่างนี้อยู่ที่การแสดงให้เห็นว่า แม้ว่า WinDbg จะไม่รองรับรูปแบบ ELF/DWARF ทั้งหมดอย่างเต็มรูปแบบ แต่ผลลัพธ์ที่ได้ก็คือ...คุณสามารถสำรวจสแต็ก ตรวจสอบประเภท ตั้งเบรกพอยต์ตามชื่อฟังก์ชัน และนำทางผ่านโค้ด C++ ได้อย่างสะดวกสบายพอสมควรโดยใช้ gdbserver เป็นแบ็กเอนด์ระยะไกล

การดีบักเคอร์เนล Linux ด้วย qemu และ gdb

gdbserver ไม่ได้ใช้เฉพาะในโหมดผู้ใช้เท่านั้น แต่ยังมีสถานการณ์การใช้งานที่มีประสิทธิภาพสูงมากในโหมดเคอร์เนลด้วยโดยเฉพาะอย่างยิ่งเมื่อคุณใช้ QEMU ร่วมกับการสนับสนุนการดีบัก แม้ว่าในที่นี้บทบาทของ "gdbserver" จะถูกเติมเต็มโดยตัวเลือกของ QEMU เอง แต่แนวทางก็เหมือนกัน: ด้านหนึ่งรันระบบที่จะดีบักและเปิดพอร์ต gdb ส่วนอีกด้านหนึ่งจะเป็น gdb หรือดีบักเกอร์ที่สื่อสารด้วยโปรโตคอลระยะไกล

ในการดีบักเคอร์เนล คุณต้องคอมไพล์มันโดยใช้ตัวเลือกการดีบักเฉพาะ: เปิดใช้งานการสร้างข้อมูลการดีบัก (CONFIG_DEBUG_INFO), สคริปต์เคอร์เนล GDB (CONFIG_GDB_SCRIPTS) และโหมดดีบักของเคอร์เนลเอง (CONFIG_DEBUG_KERNELสิ่งสำคัญอีกประการหนึ่งคือการปิดใช้งานตัวเลือกที่ลบสัญลักษณ์ระหว่างการเชื่อมโยง เช่น "ลบสัญลักษณ์ที่สร้างโดยแอสเซมเบลอร์ระหว่างการเชื่อมโยง"

หลังจากคอมไพล์เสร็จ คุณจะได้ไฟล์ไบนารี vmlinux “ไม่ได้ถูกถอดออก”ซึ่งเป็นตัวที่คุณจะใช้จาก gdb นอกจากนี้คุณยังต้องการ initramfs พื้นฐาน ซึ่งคุณสามารถสร้างได้ด้วยคำสั่งเช่น:

คำสั่ง: mkinitramfs -o ramdisk.img

จากนั้นเริ่มใช้งาน QEMU โดยกำหนดพารามิเตอร์สำหรับการดีบักตัวอย่างทั่วไปได้แก่ ตัวเลือก -gdb tcp::1234 เพื่อเปิดเอนด์พอยต์ระยะไกลที่เข้ากันได้กับ gdb และ -S เพื่อให้เครื่องเสมือนเริ่มต้นในสถานะหยุดชั่วคราวตั้งแต่แรก คุณยังสามารถระบุเคอร์เนลได้ด้วย -kernel vmlinux, -initrd ramdisk.imgความทรงจำกับ -m 512 และโดยปกติคุณจะเปลี่ยนเส้นทางคอนโซลไปยัง ttyS0 เพื่อจัดการทุกอย่างตั้งแต่ต้นจนจบ สถานีปลายทาง.

  วิธีอัปเดต Edge เป็นเวอร์ชันล่าสุดบน Windows 11: คำแนะนำทีละขั้นตอนแบบครบถ้วน

เนื่องจาก QEMU ถูกกักไว้เพื่อรอ gdbจากเครื่องโฮสต์ คุณเริ่ม gdb โดยชี้ไปยัง vmlinux และคุณเชื่อมต่อกับ target remote localhost:1234จากตรงนั้น คุณสามารถตั้งค่าเบรกพอยต์ล่วงหน้าได้ เช่น hb start_kernelและควบคุมการดำเนินการด้วยคำสั่งต่างๆ เช่น c (ดำเนินการต่อ) และกด CTRL+C เพื่อหยุดชั่วคราวอีกครั้ง

การเปลี่ยนแปลงและรายละเอียดปลีกย่อยล่าสุดใน gdb และ gdbserver

ในระบบปฏิบัติการรุ่นใหม่ เช่น Red Hat Enterprise Linux 8 มีการเปลี่ยนแปลงหลายอย่างใน gdb และ gdbserver ที่ควรทราบไว้โดยเฉพาะอย่างยิ่งหากคุณเคยใช้เวอร์ชันก่อนหน้า หรือมีสคริปต์ที่วิเคราะห์ผลลัพธ์จากดีบักเกอร์

ในอีกด้านหนึ่ง gdbserver เริ่มกระบวนการ "ระดับล่าง" โดยใช้เชลล์เช่นเดียวกับ gdb ฟังก์ชันนี้อนุญาตให้ขยายและแทนที่ตัวแปรบนบรรทัดคำสั่งได้ หากคุณต้องการปิดใช้งานพฤติกรรมนี้ด้วยเหตุผลใดก็ตาม มีการตั้งค่าเฉพาะที่ระบุไว้ใน RHEL 8 เพื่อเปลี่ยนกลับไปใช้โหมดก่อนหน้า

มีหลายสิ่งที่ถูกลบออกหรือเปลี่ยนแปลงไปเช่นกัน: การสนับสนุนการดีบักสำหรับโปรแกรม Java ที่คอมไพล์ด้วย gcjโหมดความเข้ากันได้ของ HP-UX XDB และคำสั่งต่างๆ เช่น set remotebaud (แทนที่ด้วย) set serial baudหรือความเข้ากันได้กับรูปแบบเก่าบางรูปแบบ stabsนอกจากนี้ การกำหนดหมายเลขเธรดไม่ได้เป็นแบบทั่วโลกอีกต่อไป แต่เป็นไปตามเธรด "ล่าง" และปรากฏดังนี้ inferior_num.thread_numโดยมีตัวแปรอำนวยความสะดวกใหม่ๆ เช่น $_gthread เพื่ออ้างอิงถึงตัวระบุสากล

อีกหนึ่งคุณสมบัติใหม่ที่เกี่ยวข้องคือการปรับแต่ง max-value-sizeการตั้งค่านี้จะจำกัดปริมาณหน่วยความจำที่ gdb สามารถจัดสรรเพื่อแสดงเนื้อหาของค่าได้ ค่าเริ่มต้นคือ 64 KiB ดังนั้นการพยายามพิมพ์อาร์เรย์ขนาดใหญ่หรือโครงสร้างขนาดใหญ่อาจส่งผลให้เกิดคำเตือน "ค่าใหญ่เกินไป" แทนที่จะแสดงหน่วยความจำทั้งหมดที่มีอยู่

นอกจากนี้ ยังมีการปรับปรุงวิธีการที่ gdb จัดการกับเรื่องนี้ด้วย sysrootค่าเริ่มต้นคือ ตอนนี้ target:หมายความว่าสำหรับกระบวนการระยะไกล ระบบจะพยายามค้นหาไลบรารีและสัญลักษณ์บนระบบเป้าหมายก่อน หากคุณต้องการให้ระบบให้ความสำคัญกับสัญลักษณ์ในเครื่อง คุณควรเรียกใช้คำสั่งต่อไปนี้ set sysroot โดยเลือกเส้นทางที่คุณสนใจก่อนลงมือทำ target remote.

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

เคล็ดลับการทำงานและวิธีการแก้ไขปัญหาด้วย gdbserver

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

ในสภาพแวดล้อมที่มีคอร์ประมวลผลผิดพลาดจำนวนมาก การเรียนรู้วิธีใช้ gdb ในโหมดแบตช์นั้นคุ้มค่าโดยมีธงต่างๆ เช่น --batch, --ex y -x เพื่อเรียกใช้คำสั่งโดยอัตโนมัติบนรายการของคอร์และประมวลผลข้อมูลการติดตามการทำงานจากสคริปต์ (ตัวอย่างเช่นใน หลามวิธีนี้ช่วยให้คุณกรองปัญหาที่ซ้ำกัน จัดกลุ่มความล้มเหลวตาม stack trace และอื่นๆ ได้อย่างรวดเร็ว

เมื่อเกิดปัญหาในการเชื่อมต่อระยะไกล ตัวเลือกดังกล่าว --debug gdbserver คือเพื่อนที่ดีที่สุดของคุณตัวอย่างเช่น หากคุณเริ่มต้นติดต่อเจ้าหน้าที่ส่งหมายศาลด้วยข้อความดังนี้:

คำสั่ง: gdbserver --debug --multi localhost:1234

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

ในบริบทต่างๆ เช่น เราเตอร์ TP-Link ที่คุณแนบ gdbserver เข้ากับกระบวนการที่สำคัญ httpdเป็นเรื่องปกติที่เบรกพอยต์บางจุดจะทำให้เกิดสภาวะการแข่งขัน (race condition) หรือกลไกตรวจสอบการทำงาน (watchdog) ที่ยุติกระบวนการเมื่อมัน "ค้าง" อยู่นานเกินไปในดีบักเกอร์ ในสถานการณ์เหล่านี้ อาจจำเป็นต้องปรับเปลี่ยนสัญญาณที่ถูกบล็อก เธรดที่ถูกควบคุม และหากจำเป็น ให้แก้ไขการตั้งค่าระบบเอง (เวลาหมดเวลา กลไกตรวจสอบการทำงานของฮาร์ดแวร์) เพื่อให้สามารถดีบักได้นานขึ้น

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