如何设置(struct _IO_FILE *) - > _IO_read_base?

时间:2015-10-06 06:16:06

标签: c file unix glibc stdio

为可能奇怪的问题标题道歉。我不希望它看起来像一个标题为“如何C文件I / O在低级别工作?”的标题。我希望很明显,我的问题是具体的。

无论如何,当C中的文件为fopen时,它会返回struct _IO_FILE *

FILE *f = fopen("hello.txt", "r");
printf("Fileno: %i\n", f->_fileno); // 3

我查看了libio.h和gdb的“标签”输出,并确认struct _IO_FILE的内容如下:

struct _IO_FILE {
  int _flags;
  char* _IO_read_ptr;
  char* _IO_read_end;
  char* _IO_read_base; // <-- file contents
  char* _IO_write_base;
  char* _IO_write_ptr;
  char* _IO_write_end;
  char* _IO_buf_base;
  char* _IO_buf_end;
  char *_IO_save_base;
  char *_IO_backup_base;
  char *_IO_save_end;
  struct _IO_marker *_markers;
  struct _IO_FILE *_chain;
  int _fileno;
  int _flags2;
  __off_t _old_offset;
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];
  _IO_lock_t *_lock;
  __off64_t _offset;
  void *__pad1;
  void *__pad2;
  void *__pad3;
  void *__pad4;
  size_t __pad5;
  int _mode;
  char _unused2[...];
};

我已经在gdb中对它们中的每一个进行了刺激,并且最初注意到f->_IO_read_base0x0,但是成为指向正确字符串的指针,该字符串包含文件的全部内容在至少调用一次fgetc()(或类似函数)后,。在对glibc代码库进行了一些粗暴和广泛的搜索之后,我似乎已将其追踪到一个名为__uflow的函数

所以我的问题是,_IO_read_base如何初始化? 哪里从中获取内容? 如何获取所述内容? IO_read_base从空指针转换为字符串时?我将如何仅使用struct本身和一些系统调用来执行此操作?我想了解它在低级别的工作原理。

...
(gdb) print fp->_IO_read_base 
$3 = 0x0
(gdb) n
434    in genops.c
< a few more times ... >
_IO_getc (fp=0x602010) at getc.c:38
38    getc.c: No such file or directory.
(gdb) print fp->_IO_read_base 
$4 = 0x7ffff7ff4000 "#include <stdio.h> ..."
(gdb) 

您可以看到它转化的位置。在genops.c中的某个地方。据推测__uflow()。但它的来源没有回答任何问题:

int
__uflow (fp)
     _IO_FILE *fp;
{
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
  if (_IO_vtable_offset (fp) == 0 && _IO_fwide (fp, -1) != -1)
    return EOF;
#endif

  if (fp->_mode == 0)
    _IO_fwide (fp, -1);
  if (_IO_in_put_mode (fp))
    if (_IO_switch_to_get_mode (fp) == EOF)
      return EOF;
  if (fp->_IO_read_ptr < fp->_IO_read_end)
    return *(unsigned char *) fp->_IO_read_ptr++;
  if (_IO_in_backup (fp))
    {
      _IO_switch_to_main_get_area (fp);
      if (fp->_IO_read_ptr < fp->_IO_read_end)
    return *(unsigned char *) fp->_IO_read_ptr++;
    }
  if (_IO_have_markers (fp))
    {
      if (save_for_backup (fp, fp->_IO_read_end))
    return EOF;
    }
  else if (_IO_have_backup (fp))
    _IO_free_backup_area (fp);
  return _IO_UFLOW (fp);
}
libc_hidden_def (__uflow)

测试gdb中的每个调用,如果检查失败则每个调用,所以我假设它返回_IO_UFLOW (fp);。有趣的是_IO_UFLOW是__uflow的宏包装器,所以......它正在调用自己。并且它无法无限递归。为什么呢?

有了这个,我已经走到了尽头,因为仍然没有解释我可以找到fp->IO_read_ptr如何填写。我所知道的是它发生在genops.c的“某处”。

1 个答案:

答案 0 :(得分:0)

在GDB中具有硬件观察点支持的平台上,您可以通过在fp->_IO_read_base上设置观察点来轻松回答此问题。例如:

(gdb) watch -l fp->_IO_read_base
Hardware watchpoint 2: -location fp->_IO_read_base
(gdb) c
Continuing.
Hardware watchpoint 2: -location fp->_IO_read_base

Old value = 0x0
New value = 0x7ffff7ff7000 ""
__GI__IO_switch_to_get_mode (fp=fp@entry=0x602010) at genops.c:191
191 genops.c: No such file or directory.
(gdb) bt
#0  __GI__IO_switch_to_get_mode (fp=fp@entry=0x602010) at genops.c:191
#1  0x00007ffff7a8f670 in _IO_new_file_underflow (fp=0x602010) at fileops.c:602
#2  0x00007ffff7a841a5 in _IO_getdelim (lineptr=0x7fffffffdc88, n=0x7fffffffdc90, delimiter=10, fp=0x602010) at iogetdelim.c:77
#3  0x00000000004005b7 in main () at t.c:9