我正在努力查找新程序中何时何地发生损坏。这个程序只有495行,gdb没有帮我调试它
> 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 = ' 00' <repeats 1023 times>
(gdb) print sizeof(strWork)
$3 = 1024
(gdb) step
procNameFromCmdline (pid=0, result=0x0, resultLen=0, fullCmd=0 ' 00') at psgrep-2020.c:58
58 int procNameFromCmdline(pid_t pid, char *result, int resultLen, BOOL fullCmd) {
(gdb)
在调用进程(procNameFromCmdline(开始时,我们可以看到每个参数都是不正确的(通过#define,TRUE等于1(。有时gdb显示如下:
procNameFromCmdline (pid=0, result=0x19c5b4 <error: Cannot access memory at address 0x19c5b4>, resultLen=1689012, fullCmd=0 ' 00')
我不是想让别人替我找问题;我想做的是找到一种方法,当程序被破坏时,我可以检测到。我相信我所有的memset、snprintf((等等都受到了正确的约束;显然是出了问题。
如果有任何帮助并正确看待问题,以下是调用之前的相关代码。。。
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指向一个字符[665535],/fproc/893/stat中该字段的值长度为9加上一个终止符。根据文档,16就足够了。但这不是重点。(
有办法吗?我需要更专业的调试器吗?
(虽然我不是在找人来解决这个程序的问题,但它似乎已经引起了一些兴趣。从这个角度来看,我发布了引用代码中使用的结构。(这在linux内核源代码(fs/proc/array.c(中有文档记录,(不是我的版本(可以在[这里][1]和许多其他地方看到。
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
在被调用进程(procNameFromCmdline(开始时,我们可以看到每个参数都是不正确的
这很可能意味着GDB没有跳过函数prolog(就像它应该跳过的那样(。很可能是因为这个。
如果您执行另一个step
或next
,参数将突然再次变得正确。
请注意,上述错误已在较新的GDB版本中修复,因此更新GDB是另一种解决方案。