c - जीडीबी ब्रेकपॉइंट सम्मिलित नहीं किया जा सकता, क्या XXX को पता करने में स्मृति का उपयोग नहीं किया जा सकता?




debugging gdb (2)

इस सवाल का पहले से ही उत्तर दिया गया है:

मैंने एक बहुत ही साधारण प्रोग्राम लिखा था:

[email protected]:~/test$ cat main.c
int main() {
    int i = 0;
    return i;
}

और मैंने इसे छेड़छाड़ मोड के लिए संकलित -s

[email protected]:~/test$ gcc -s main.c -o f3
[email protected]:~/test$ file f3
f3: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=4dc6b893fbae8b418ca41ddeef948df1fcb26d3d, stripped

अब, मैं जीडीबी का इस्तेमाल करते हुए मुख्य कार्य प्रारंभ पता जानने का प्रयास कर रहा हूं:

[email protected]:~/test$ gdb -nh f3
GNU gdb (Ubuntu 7.11.90.20161005-0ubuntu2) 7.11.90.20161005-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from f3...(no debugging symbols found)...done.

चूंकि फ़ाइल के अंदर कोई प्रतीक जानकारी नहीं है, मुझे फाइल एंट्री बिंदु पर एक ब्रेक लगाने और इसे अलग करने और main फ़ंक्शन के प्रारंभ पते को खोजने की आवश्यकता है। इसलिए मैंने फ़ाइल entry point पते को खोजने के लिए info file कमांड का इस्तेमाल किया:

(gdb) info file
Symbols from "/home/ebrahim/test/f3".
Local exec file:
    `/home/ebrahim/test/f3', file type elf64-x86-64.
    Entry point: 0x530     <<<<=============
    0x0000000000000238 - 0x0000000000000254 is .interp
    0x0000000000000254 - 0x0000000000000274 is .note.ABI-tag
    0x0000000000000274 - 0x0000000000000298 is .note.gnu.build-id
    0x0000000000000298 - 0x00000000000002b4 is .gnu.hash
    0x00000000000002b8 - 0x0000000000000360 is .dynsym
    0x0000000000000360 - 0x00000000000003f1 is .dynstr
    0x00000000000003f2 - 0x0000000000000400 is .gnu.version
    0x0000000000000400 - 0x0000000000000420 is .gnu.version_r
    0x0000000000000420 - 0x00000000000004f8 is .rela.dyn
    0x00000000000004f8 - 0x000000000000050f is .init
    0x0000000000000510 - 0x0000000000000520 is .plt
    0x0000000000000520 - 0x0000000000000528 is .plt.got
    0x0000000000000530 - 0x00000000000006e2 is .text
    0x00000000000006e4 - 0x00000000000006ed is .fini
    0x00000000000006f0 - 0x00000000000006f4 is .rodata
    0x00000000000006f4 - 0x0000000000000728 is .eh_frame_hdr
    0x0000000000000728 - 0x000000000000081c is .eh_frame
    0x0000000000200de0 - 0x0000000000200de8 is .init_array
    0x0000000000200de8 - 0x0000000000200df0 is .fini_array
    0x0000000000200df0 - 0x0000000000200df8 is .jcr
    0x0000000000200df8 - 0x0000000000200fb8 is .dynamic
    0x0000000000200fb8 - 0x0000000000201000 is .got
    0x0000000000201000 - 0x0000000000201010 is .data
    0x0000000000201010 - 0x0000000000201018 is .bss

जैसा कि हम उम्मीद करते थे कि प्रवेश बिंदु .text अनुभाग की शुरुआत है। इसलिए मैंने इस पते पर ब्रेकपॉइंट डाल दिया:

(gdb) b *0x0000000000000530
Breakpoint 1 at 0x530
(gdb) r
Starting program: /home/ebrahim/test/f3 
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x530

(gdb)

सवाल यह है कि क्यों जीडीबी इस ब्रेकपॉइंट को सम्मिलित नहीं कर सकता है?


डीबगिंग छेड़छाड़ कोड शायद बहुत बेकार है (रिवर्स इंजीनियरिंग को छोड़कर), लेकिन आप gdb को बहुत पहले निर्देश पर रोक सकते हैं, और आप पहले से ही यह गलती से कर रहे हैं। यदि ब्रेकपॉइंट का पता मैप नहीं किया जा सकता है, तो gdb बंद हो जाता है और आपको त्रुटि बताता है। एक साइड इफेक्ट के रूप में, आपका प्रोग्राम अपने पहले निर्देश पर रोक दिया गया है। एक पते जो अस्वीकार्य होने की गारंटी है, वह 0 , इसलिए निम्न कार्य करें:

(gdb) b *0
Breakpoint 1 at 0x0
(gdb) r
Starting program: [...]
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x0

(gdb) disas
Dump of assembler code for function _start:
=> 0x00007ffff7ddd190 <+0>: mov    %rsp,%rdi
   0x00007ffff7ddd193 <+3>: callq  0x7ffff7de0750 <_dl_start>

यहां आप देखते हैं कि PC 0x00007ffff7ddd190 पर बैठता है। तो रनटाइम पर यह आपका प्रवेश बिंदु है

जारी रखने में सक्षम होने के लिए (या: उदाहरण के लिए एकल-चरण), आपको अपमानजनक ब्रेकपाइंट को हटाना होगा:

(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) c
Continuing.

इस जवाब के लिए क्रेडिट रिवर्स इंजीनियरिंग पर इस उत्तर पर जाते हैं


समस्या यह है कि आप साझा ऑब्जेक्ट को डिबग करने का प्रयास कर रहे हैं, हालांकि यह निष्पादन योग्य था। विशेष रूप से आपकी file की रिपोर्ट की गई:

ELF 64-बिट LSB साझा ऑब्जेक्ट

क्योंकि यह निष्पादन योग्य के बजाय एक साझा ऑब्जेक्ट है, आपको शायद एक वास्तविक कार्यक्रम के साथ शुरू करना होगा। इस विशेष मामले में, आपको उस साझा वस्तु फ़ाइल को अपने खुद के बनाने के दूसरे कार्यक्रम के साथ लिंक करने की आवश्यकता होगी। उदाहरण के लिए, मैंने एक सरल साझा ऑब्जेक्ट बनाया है:

snoot.c

#include <stdio.h>

int square(int test) {
    return test*test;
}

int func() {
    n = 7;
    printf("The answer is %d\n", square(n)-5);
}

संकलन

gcc -shared -fpic snoot.c -o libsnoot.so
strip libsnoot.so

अब हमारे पास आपके छीन लिया गया लाइब्रेरी के बराबर है यदि हम objdump -T libsnoot.so करते हैं तो हमें यह मिलता है:

libsnoot.so:     file format elf64-x86-64

DYNAMIC SYMBOL TABLE:
0000000000000580 l    d  .init  0000000000000000              .init
0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 printf
0000000000000000  w   D  *UND*  0000000000000000              __gmon_start__
0000000000000000  w   D  *UND*  0000000000000000              _Jv_RegisterClasses
0000000000000000  w   D  *UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000  w   DF *UND*  0000000000000000  GLIBC_2.2.5 __cxa_finalize
0000000000201028 g    D  .got.plt   0000000000000000  Base        _edata
00000000000006e0 g    DF .text  0000000000000010  Base        square
0000000000201030 g    D  .bss   0000000000000000  Base        _end
0000000000201028 g    D  .bss   0000000000000000  Base        __bss_start
0000000000000580 g    DF .init  0000000000000000  Base        _init
0000000000000724 g    DF .fini  0000000000000000  Base        _fini
00000000000006f0 g    DF .text  0000000000000032  Base        func

.text अनुभाग में केवल दो प्रतीकों हम परिभाषित दो कार्य हैं। दुर्भाग्य से, फ़ंक्शन को कॉल करने का तरीका निर्धारित करने का कोई सामान्य तरीका नहीं है (अर्थात, मूल सी फ़ंक्शन प्रोटोटाइप को पुनर्प्राप्त करने का कोई तरीका नहीं है) लेकिन हम अनुमान लगा सकते हैं। यदि हम गलत अनुमान लगाते हैं, तो स्टैक बंद हो जाएगा उदाहरण के लिए, चलो इस प्रोग्राम के साथ square से लिंक करने का प्रयास करें:

testsnoot.c

extern void square(void);

int main() {
    square();
}

इस so फाइल को मानते ही एक ही निर्देशिका में है, हम इस तरह संकलन और लिंक कर सकते हैं:

gcc testsnoot.c -o testsnoot -L. -lsnoot

अब हम सामान्य रूप से डिबग कर सकते हैं, क्योंकि यह टेस्ट ड्रायवर हमारे नियंत्रण में है:

LD_LIBRARY_PATH = "।" जीडीबी ./testsnoot

ध्यान दें कि हमें LD_LIBRARY_PATH सेट करने की आवश्यकता है या नहीं, जिस लाइब्रेरी के साथ हम काम कर रहे हैं वह लोड नहीं होगा और निष्पादन समाप्त हो जाएगा।

(gdb) b square
Breakpoint 1 at 0x400560
(gdb) r
Starting program: /home/edward/test/testsnoot 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.24-4.fc25.x86_64

Breakpoint 1, 0x00007ffff7bd56e4 in square () from ./libsnoot.so
(gdb) x/20i $pc
=> 0x7ffff7bd56e4 <square+4>:   mov    %edi,-0x4(%rbp)
   0x7ffff7bd56e7 <square+7>:   mov    -0x4(%rbp),%eax
   0x7ffff7bd56ea <square+10>:  imul   -0x4(%rbp),%eax
   0x7ffff7bd56ee <square+14>:  pop    %rbp
   0x7ffff7bd56ef <square+15>:  retq   
   0x7ffff7bd56f0 <func>:   push   %rbp
   0x7ffff7bd56f1 <func+1>: mov    %rsp,%rbp
   0x7ffff7bd56f4 <func+4>: sub    $0x10,%rsp
   0x7ffff7bd56f8 <func+8>: movl   $0x7,-0x4(%rbp)
   0x7ffff7bd56ff <func+15>:    mov    -0x4(%rbp),%eax
   0x7ffff7bd5702 <func+18>:    mov    %eax,%edi
   0x7ffff7bd5704 <func+20>:    callq  0x7ffff7bd55b0 <[email protected]>
   0x7ffff7bd5709 <func+25>:    sub    $0x5,%eax
   0x7ffff7bd570c <func+28>:    mov    %eax,%esi
   0x7ffff7bd570e <func+30>:    lea    0x18(%rip),%rdi        # 0x7ffff7bd572d
   0x7ffff7bd5715 <func+37>:    mov    $0x0,%eax
   0x7ffff7bd571a <func+42>:    callq  0x7ffff7bd55c0 <[email protected]>
   0x7ffff7bd571f <func+47>:    nop
   0x7ffff7bd5720 <func+48>:    leaveq 
   0x7ffff7bd5721 <func+49>:    retq   

अब आप समारोह के disassembly को देख सकते हैं और देखें कि यह क्या कर रहा है। इस मामले में, जब से हम देखते हैं कि -0x4(%rbp) का कोई संदर्भ है, यह स्पष्ट है कि यह फ़ंक्शन वास्तव में एक तर्क की उम्मीद कर रहा है, हालांकि हम वास्तव में किस तरह से नहीं जानते हैं

हम टेस्ट ड्राइव फ़ंक्शन को दोबारा लिख ​​सकते हैं और जब तक हम छीन ली गई पुस्तकालय की समझ हासिल नहीं कर लेते हैं तब तक डीबगिंग का अनुभव करते हैं।

मैं मान रहा हूँ कि आप इसे वहां से ले सकते हैं, अब जब मैंने सामान्य प्रक्रिया दिखा दी है





entry-point