2

プロセスの proc/pid/mem スタックを読み取ろうとしています (トレースには ptrace を使用します)

1) /proc/pid/maps を読み取り、スタックの先頭と末尾を保存します

unsigned int start_stack, end_stack;

2) lseek と read を使用して、スタックアドレスのメモリを読み取ります

読み込もうとすると問題が発生します:

  int mem_file = open (mem_file_name, O_RDONLY);
  if(mem_file==-1)perror("open file mem_file failed");

  printf("start_stack = %x, end_stack = %x \n", 
     start_stack, end_stack);

  /*I think the problem is here, but i'm not sure*/
  if(lseek(mem_file, start_stack, 
       SEEK_SET)==-1)perror("lseek failed");

  int buf_size = (int)(end_stack-start_stack);
  buf = calloc(buf_size, sizeof(char));

  if(read(mem_file, buf, size_buf) == -1 )perror("read failed");
  printf("buf=");
  for(i=0; i<size_buf; i+=2)
      printf("%02x",buf[i]);

出力は次のとおりです。

start stack = bffde000, end stack = bffff000 
buf = 00000000000000000000000000000000000000000000

lseek のオフセットが間違っているのでしょうか? この例では、オフセットは (unsigned int)bffde00、スタックの開始です。

助言がありますか ?ありがとう

4

2 に答える 2

4

intまたはunsigned int、64 ビット Linux アーキテクチャでメモリ アドレスを記述するのに十分な大きさではありません (それらはすべて ILP64 ではなく LP64 であるため)。

unsigned long代わりに使用してください。これは、すべての Linux アーキテクチャーで任意のメモリー・アドレスを保持するのに十分な大きさです。

Linux のほとんどのアーキテクチャでは、スタックが成長ます。これは、スタックの最下位アドレスがゼロであることが予想されることを意味します。スタック内の「最も古い」値は最上位アドレスにあります。

unistd.h低レベルの I/O は、短い読み取りを返すことができます。これは、単に を呼び出しread()て、結果が -1 でないことを確認し、要求したすべてを読み取ったと仮定することはできないことを意味します。読み取った文字数を返しますが、それはあなたが要求したよりも少ないかもしれません。すべての一般的な低レベル I/O 関数はerrno == EINTR、シグナルが配信された場合 (たとえば、プログラムの停止または継続時) に -1 を返すこともあります。

たとえば、ファイルまたは疑似ファイルを読み取り専用で開くには、次のようにします。

do {
    fd = open(filename, O_RDONLY);
} while (fd == -1 && errno == EINTR);
if (fd == -1)
    /* Cannot open, see strerror(errno) */

ファイル記述子を閉じるには、

do {
    result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1)
    /* Delayed write error, or other I/O error,
       see strerror(errno) */

特定のオフセットからいくつかのデータを読み取り#define _POSIX_C_SOURCE 200809L、使用するにはpread():

/* Read length chars into buffer starting at offset
 * from descriptor fd. Returns 0 if success,
 * errno error code otherwise; ENOSPC if a premature
 * end of input occurs. */
int read_from(const int fd, const off_t offset,
              void *const buffer, size_t const length)
{
    char   *const ptr = buffer;
    size_t  have = 0;
    ssize_t n;

    while (have < length) {

        n = pread(fd, ptr + have, length - have, offset + (off_t)have);
        if (n > (ssize_t)0)
            have += n;

        else
        if (n == (ssize_t)0)
            return errno = ENOSPC; /* Premature end of input */

        else
        if (n != (ssize_t)-1)
            return errno = EIO; /* Kernel bug catcher */

        else
        if (errno != EINTR)
            return errno;
    }

    return 0;
}

を使用する必要はありませんpread()、上記のread_from()関数は、複数のスレッドが同じファイルから同時に読み取る場合でも機能します。そのため、POSIX.1-2001 でpread()およびのサポートが追加されましpwrite()た。

(64 ビットであることを確認したい場合off_tは、#define _FILE_OFFSET_BITS 64. すべての 64 ビット Linux システムでは既にそうであるため、この特定のプログラムでは必要ありません。)

于 2013-07-22T22:22:28.443 に答える