我很好奇是否有人可以在这里指出我正确的方向。我正在学习计算机系统编程(基础知识),我正在尝试通过不同级别跟踪代码,以了解每个代码如何与另一个进行交互。一个例子是调用C中的fgets()
函数或C ++中的getline()
或类似函数。这两个都会调用系统吗?有没有一种简单的方法来查看被调用的代码?
我正在使用Unix(Ubuntu)。这是Windows和Apple专有的东西吗?这种东西有什么好的资源吗?一如既往,谢谢你们!
答案 0 :(得分:2)
至少在UNIX世界中,答案很简单:“使用Source,Luke”。
在您的示例中,您将查看fgetc()的源代码。这是在C标准库中,找到源代码的最简单方法是谷歌类似“C libraary fgets()source”。
当你获得该源代码时,你会看到一堆代码处理缓冲区等,以及系统调用,可能是 read(2)。那里的“2”告诉你它在手册的第2章中有记录(例如,你可以用man 2 read
找到它。)
系统调用在内核中实现,因此您需要读取内核源代码。从那里继续。
现在,您需要找到所有内容而无需在源代码中随机阅读(虽然这是许多人学习它的方式,但效率不高)是在Linux上掌握一本像Kerrisk的书 The Linux Programming Interface ,它解释了其中的一些内容,而不仅仅是来源。
答案 1 :(得分:2)
fgets
内的某些内容位于libc
内。也就是说,它是与大多数C二进制文件链接的用户区库。查看glibc
,这是目前最常见的实施方式。
最终,libc
将开始对内核进行系统调用。您可以在kernel.org获取来源。查看KGDB以获取内核调试。进行内核调试的最简单方法是使用通过null模型电缆连接的第二台机器。
答案 2 :(得分:2)
在Windows上,您可以通过一些方法获得一些见解。首先,您需要一些与您要调查的二进制文件相对应的符号文件。符号文件将文本名称与浮动在程序周围的全局/堆栈/堆变量相关联。因此,要将内存中的地址映射到函数fgets,并查看某些程序中的fgets,您需要具有Microsoft的C std库实现版本的symobls。幸运的是,MS制作符号freely available
其次,你需要捕获一个比fgets更深入的callstack。最明显的方法是成为Microsoft开发人员并将崩溃引入深度MS dll,然后使用调试器和符号分析崩溃转储,但遗憾的是我们无法做到这一点。您可以做的是使用称为抽样分析器的内容,如在Microsoft this one中免费提供的那样。采样分析器通过定期快照程序的调用堆栈来对代码进行分析。使用Microsoft的符号文件,我们可以将该callstack消化为有意义的东西。
鉴于这2条信息,构建一个程序并了解fgets调用的内容并不难。然后,您可以使用带有Microsoft符号的采样分析器来了解程序中的最新情况。
按照这些方针,我构建了以下程序来试试这个:
int FgetSTest()
{
FILE* fp;
fp = fopen("C:/test.txt", "w");
char data[100];
int sum = 0;
for (int i = 0; i < 100; ++i)
{
fgets(data, 100, fp);
sum += data[0];
}
fclose(fp);
return sum;
}
int _tmain(int argc, _TCHAR* argv[])
{
int sum = 0;
for (int i = 0; i < 100; ++i)
{
sum += FgetSTest();
}
std::cout << sum;
return 0;
}
假设您已将其编译成程序(我将其编译为一个名为perfPlay.exe的程序),您可以在exe上运行MS的采样分析器,如下所示:
C:\path\to\exe>vsperfcmd /start:sample /output:perfPlay.vsp
Microsoft (R) VSPerf Command Version 9.0.30729 x86
Copyright (C) Microsoft Corp. All rights reserved.
C:\path\to\exe\>vsperfcmd /launch:perfPlay.exe
Microsoft (R) VSPerf Command Version 9.0.30729 x86
Copyright (C) Microsoft Corp. All rights reserved.
Successfully launched process ID:3700 perfPlay.exe
sum is:40000
C:\path\to\exe>vsperfcmd /shutdown
Microsoft (R) VSPerf Command Version 9.0.30729 x86
Copyright (C) Microsoft Corp. All rights reserved.
Shutting down the Profile Monitor
------------------------------------------------------------
获取探查器输出,注意“symbolpath”开关将命令指向Microsoft的符号服务器:
C:\path\to\exe>vsperfreport perfplay.vsp /summary:all /symbolpath:srv*c:\symbols*htt
号码://msdl.microsoft.com/download/symbols
您可以直接检查来电者 - 被叫方报告的csv,或找到一个好的查看器,例如the one I've been working on,您可以了解fgets大部分时间的花费:
可悲的是,不是非常有见地。不幸的是,这种方法遇到的问题之一是许多函数fgets在发布模式下调用很可能是inlined - 这就是它们作为最终程序中的函数被删除了很多他们的内容直接“粘贴”到他们使用的地方。
您可以尝试在调试模式下重复上述操作以查看您获得的内容,因为内联的可能性较小。
答案 3 :(得分:1)
首先要做的事情;这项任务需要很好的工具。在导航源时,我发现etags
,cscope
和gid
(来自GNU idutils
)必不可少的工具。弄清楚如何将这些中的一个或多个集成到您喜欢的编辑器或IDE中。切换编辑器或IDE以获取这些功能,没有任何借口可用于糟糕的工具。如果你正在寻找一个建议,我喜欢vim
,很多人争论emacs
,并且有些人喜欢他们的Eclipse。
您需要源本地; lxr是一个了不起的工具,但重复的Web请求所涉及的延迟会让任何严肃的工作都变得疲惫不堪。在Debian派生的系统上,这很容易;将目录更改为您希望存储源的位置,并运行apt-get source eglibc
以下载glibc
源。我建议通过来自http://www.kernel.org或cloning the master git
repository的tarball获取内核源代码(如果你想阅读更改日志或轻松获取更新,这是一个更好的选择 - 尽管截至2012年6月它确实扩展到2.7千兆字节,所以它显然不适合所有人)。
为C库构建标记文件后,您只需运行:vim -t fgets
,它就会直接打开libio/bits/stdio2.h
fgets()
例程的源代码。 (它的可读性远远低于您的预期。)请遵循这些,直到最终进入read()
系统调用。 (可能需要一段时间。)
现在切换到内核源代码。请查看此fs/read_write.c
:
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
内核使用宏定义系统调用的方式的一个缺点是它使搜索函数变得复杂。 vim -t
无法直接找到此内容。查找系统调用时最简单的方法是运行gid -s SYSCALL_DEFINE | grep read
。 (如果您找到了更好的工具,请告诉我。)一旦找到系统调用入口点,就可以更容易地阅读其余的内核源代码。 (我通常发现它比glibc
来源更易读 - 尽管远离块级bread()
调用的五或六个函数调用的日子早已不复存在。)