首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >gdb -如何使用gdb捕获腐败

gdb -如何使用gdb捕获腐败
EN

Stack Overflow用户
提问于 2022-02-17 19:04:33
回答 1查看 234关注 0票数 0

我正在试图找出新程序中的腐败发生在哪里/何时。程序只有495行,而gdb并没有帮助我调试它。(至少,在我目前的知识背景下,情况并非如此。)考虑以下几点:

代码语言:javascript
复制
> gdb psgrep-2020
(comments omitted)
Reading symbols from psgrep-2020...
(gdb) b 466
Breakpoint 1 at 0x3073: file psgrep-2020.c, line 466.
(gdb) run -F dnsmasq
Starting program: /usr/local/src/psgrep-2022/psgrep-2020 -F dnsmasq

Breakpoint 1, showProcess (pid=893) at psgrep-2020.c:466
466         if (printCmdline) {
(gdb) step
467             procNameFromCmdline(pid, strWork, sizeof(strWork), TRUE) ;
(gdb) p pid
$1 = 893
(gdb) p strWork
$2 = '\000' <repeats 1023 times>
(gdb) print sizeof(strWork)
$3 = 1024
(gdb) step
procNameFromCmdline (pid=0, result=0x0, resultLen=0, fullCmd=0 '\000') at psgrep-2020.c:58
58  int procNameFromCmdline(pid_t pid, char *result, int resultLen, BOOL fullCmd) {
(gdb) 

在被调用的进程(procNameFromCmdline)开始时,我们可以看到每个参数都是不正确的(TRUE等于1,通过#define)。有时,gdb显示如下:

代码语言:javascript
复制
procNameFromCmdline (pid=0, result=0x19c5b4 <error: Cannot access memory at address 0x19c5b4>, resultLen=1689012, fullCmd=0 '\000') 

我不是想让别人帮我找到问题,我想要做的是找到一种方法,当程序被破坏时,我可以检测到。我相信,我所有的memset、snprintf()等等都是正确约束的;很明显,有些地方出了问题。

如果这是有帮助的,为了正确看待,下面是调用前的代码.

代码语言:javascript
复制
    fpProcFile = fopen(sProcPath, "rt") ; // Open the stat file for reading text
    if (fpProcFile) {
        fscanf(fpProcFile
            , "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld "
              "%ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u "
              "%u %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %d"
            , &(s->pid),           s->comm,       &(s->state),       &(s->ppid),        &(s->pgrp)
            , &(s->session),     &(s->tty_nr),    &(s->tpgid),       &(s->flags),       &(s->minflt)
            , &(s->cminflt),     &(s->majflt),    &(s->cmajflt),     &(s->utime),       &(s->stime)
            , &(s->cutime),      &(s->cstime),    &(s->priority),    &(s->nice),        &(s->num_threads)
            , &(s->itrealvalue), &(s->starttime), &(s->vsize),       &(s->rss),         &(s->rsslim)
            , &(s->startcode),   &(s->endcode),   &(s->startstack),  &(s->kstkesp),     &(s->kstkeip)
            , &(s->signal),      &(s->blocked),   &(s->sigignore),   &(s->sigcatch),    &(s->wchan)
            , &(s->nswap),       &(s->cnswap),    &(s->exit_signal), &(s->processor),   &(s->rt_priority)
            , &(s->policy),      &(s->delayacct_blkio_ticks)
                                               ,  &(s->guest_time),  &(s->cguest_time), &(s->start_data)
            , &(s->end_data),    &(s->start_brk), &(s->arg_start),   &(s->arg_end),     &(s->env_start)
            , &(s->env_end),     &(s->exit_code)
             ) ;
        fclose(fpProcFile) ;
        processName = s->comm ;
        memset(strWork, 0x00, sizeof(strWork)) ;
        if (printCmdline) {
            procNameFromCmdline(pid, strWork, sizeof(strWork), TRUE) ;

( fscanf中唯一的%s指向一个char65535,/fproc/893/stat中该字段的值有长度9加上终止符。根据文件,16就足够了。但这并不是重点。)

有办法吗?我需要更专业的调试器吗?

(虽然我不是在找人来解决这个程序的问题,但它似乎获得了一些兴趣。在这种情况下,我将在引用的代码中发布使用的结构。)在linux内核源代码(fs/proc/array.c)和(不是我的版本)中可以看到这里和许多其他地方。

代码语言:javascript
复制
struct myProcStat {
    int pid ;       // Process ID
    char comm[65535] ; // Command name limited to 16 bytes
    char state ;    // R=Running S=Sleeping D=WaitingDisk Z=Zombie T=Stopped 
                    // t=TracingStopped W=Paging X=Dead x=Dead K=Wakekill
                    // W=Waking P=Parked
    int ppid ;      // Parent process ID
    int pgrp ;      // Process group ID
    int session ;   // Session ID
    int tty_nr ;    // Controlling terminal
    int tpgid ;     // Foreground process group
    unsigned int flags ; // Kernel flags
    unsigned long int minflt ; // Number of minor faults
    unsigned long int cminflt ; // Children's minor faults
    unsigned long int majflt ; // Number of major faults
    unsigned long int cmajflt ; // Children's major faults
    unsigned long int utime ; // Amount of time scheduled user mode
    unsigned long int stime ; // Amount of time scheduled kernel mode
    long int cutime ;   // Amount of time waited-for children scheduled user mode
    long int cstime ;   // Amount of time waited-for children scheduled kernel mode
    long int priority ; // Priority running real-time scheduling policy
    long int nice ;     // Nice value
    long int num_threads ; // Number of threads in this process
    long int itrealvalue ; // Time in jiffies before next SIGALARM is sent
// 21 above, 22 next ...
    unsigned long long int starttime ; // Start tine (in clock ticks) after system boot (divide by sysconf(_SC_CLK_TCK))
    unsigned long int vsize ; // Virtual memory size in bytes
    long int rss ;  // Resident set size
    unsigned long int rsslim ; // Current soft limit in bytes on rss
    unsigned long int startcode ; // address above which text can be run
    unsigned long int endcode ;   // Address below which text can be run
    unsigned long int startstack ; // Address of the start (bottom) of the stack
    unsigned long int kstkesp ; // Current stack pointer from kernel perspective
    unsigned long int kstkeip ; // Current EIP (instruction pointer)
    unsigned long int signal ; // Bitmap of pending signals as a decimal number. Obsolete. use /proc/[pid]/status instead.
    unsigned long int blocked ; // Bitmap of blocked signals. Obsolete. Use /proc/[pid]/status instead
    unsigned long int sigignore ; // Bitmap of ignored signals. Obsolete, use /proc/[pid]/status instead
    unsigned long int sigcatch ; // Bitmap of caught signals.  Use /proc/[pid]/status instead
    unsigned long int wchan ; // Channel in which process is waiting. Use with /proc/[pid]/wchan
    unsigned long int nswap ; // Number of pages swapped (not maintained - ignore)
    unsigned long int cnswap ; // Number of child process pages swapped (not maintained - ignore)
    int exit_signal ; // Signal to be sent to parent upon death
    int processor ;   // CPU last executed on
    unsigned int rt_priority ; // Real-time scheduling priority
    unsigned int policy ; // Scheduling policy for real-time scheduling
    unsigned long long int delayacct_blkio_ticks ; // Aggregated block I/O delays, in clock ticks
    unsigned long int guest_time ; // Guest time (time spent running virtual CPU for guest OS)
    unsigned long int cguest_time ; // Guest time of processes' children
    unsigned long int start_data ; // Address above which program BSS data are placed
    unsigned long int end_data ; // Address below which program BSS data are placed
    unsigned long int start_brk ; // Address above which program heap can be expanded
    unsigned long int arg_start ; // Address above which program command-line arguments (argv) are placed
    unsigned long int arg_end ; // Address below which argv are placed
    unsigned long int env_start ; // Address above which environment is placed
    unsigned long int env_end ; // Address below which environment is placed
    int exit_code ; // The thread's exit status in form reported by waitpid(2)
    } ;


  [1]: https://elixir.bootlin.com/linux/latest/source/fs/proc/array.c
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-18 23:16:14

在被调用的进程(procNameFromCmdline)开始时,我们可以看到每个参数都不正确。

这很可能意味着GDB没有跳过prolog函数(就像它应该跳过的那样)。很可能是因为

如果您执行另一个stepnext,参数将突然再次正确。

请注意,上面的bug已在较新的GDB版本中修复,因此更新GDB是另一种解决方案。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71164006

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档