为可能奇怪的问题标题道歉。我不希望它看起来像一个标题为“如何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_base
是0x0
,但是成为指向正确字符串的指针,该字符串包含文件的全部内容在至少调用一次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
的“某处”。
答案 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