高级 Visual Studio 功夫测试——调试期间从立即窗口调用函数

发布于 2024-09-05 14:26:54 字数 1179 浏览 6 评论 0原文

我看到有人提出了一些相关问题,但它们要么太高级,我无法掌握,要么缺乏从头到尾的逐步指导(其中大多数最终都是内部人士谈论他们自己的实验结果)。好吧,给定这个简单的程序:

#include <stdio.h>
#include <string.h>

int main()
{
    FILE * f;
    char buffer[100];

    memset(buffer, 0, 100);

    fun();

    f = fopen("main.cpp", "r");
    fread(buffer, 1, 99, f);
    printf(buffer);
    fclose(f);

    return 0;
}

它所做的基本上就是打印自身(假设文件名是 main.cpp)。

问题

如何让它打印另一个文件,例如 foobar.txt 而不修改源代码?它与通过 VS 运行它、单步执行函数并在调用 fread() 之前劫持 FILE 指针有关。无需担心调用fclose()会泄漏资源。

我尝试了简单的 f = fopen("foobar.txt", "r") ,它给出了

CXX0017: Error: symbol "fopen" not found

任何想法?

编辑

我在 在 Windows 上调试 Mozilla 常见问题解答上偶然发现了解决方案。放入立即窗口的正确命令是

f = {,,MSVCR100D}fopen("foo.txt", "r")

但是,它并没有真正回答这个问题:

  • 我仍然不明白这里发生了什么。
  • 如何系统地找出任何给定方法的 {,,MSVCR100D} 部分?我知道 MSVCR 版本随系统的不同而变化。我怎样才能找到它?
  • 谁能解释一下大括号语法,特别是那两个逗号在那里做什么?使用这种语法还有更多隐藏的宝石吗?

I see some related questions have been asked, but they're either too advanced for me to grasp or lacking a step-by-step guide from start to finish (most of them end up being insider talk of their own experiment results). OK here it is, given this simple program:

#include <stdio.h>
#include <string.h>

int main()
{
    FILE * f;
    char buffer[100];

    memset(buffer, 0, 100);

    fun();

    f = fopen("main.cpp", "r");
    fread(buffer, 1, 99, f);
    printf(buffer);
    fclose(f);

    return 0;
}

What it does is basically print itself (assume file name is main.cpp).

Question

How can I have it print another file, say foobar.txt without modifying the source code? It has something to do with running it through VS's, stepping through the functions and hijacking the FILE pointer right before fread() is called. No need to worry about leaking resources by calling fclose().

I tried the simple f = fopen("foobar.txt", "r") which gave

CXX0017: Error: symbol "fopen" not found

Any ideas?

Edit

I found out the solution accidentally on Debugging Mozilla on Windows FAQ. The correct command to put into the Immediate Window is

f = {,,MSVCR100D}fopen("foo.txt", "r")

However, it doesn't really answer this question:

  • I still don't understand what is going on here.
  • How to systematically find out the {,,MSVCR100D} part for any given method? I know the MSVCR version changes from system to system. How can I find that out?
  • Could anyone explain the curly brace syntax, especially, what are those two commas doing there? Are there more hidden gems using this syntax?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏末染殇 2024-09-12 14:26:54

大括号语法是 VS Context Operator,它大部分都被破坏了 - 正如链接中所详细说明的(或者至少,几乎不是一个隐藏的宝石)。它可用于 VS 表达式求值引擎需要在运行时解析函数的任何地方,例如在监视窗口中求值复合表达式、设置断点或(如您所见)在立即/命令窗口中。

它的第三个参数是二进制文件,其中包含您要调用的函数的实现。对于 CRT 函数(例如 fopen),通常相当于 -

MSVCR[VS版本][D].dll

(我似乎记得需要扩展名 - 但也许在 VS2010 中发生了变化)。 “D”表示调试 dll 版本。 VS版本号解码为:VS2005 -> 8、VS2008-> 9、VS2010-> 10.

另请注意,评估引擎具有 各种其他需要注意的问题

The curly-braces syntax is the VS Context Operator, which is mostly broken - as elaborated at the link (or at least, hardly a hidden gem). It is used anywhere the VS expression-evaluation-engine needs to resolve functions at runtime, e.g. evaluating compound expressions in the watch window, setting breakpoints, or (as you witnessed) in the immediate/command windows.

Its 3rd argument is the binary which includes the implementation of the function you wish to call. For a CRT function such as fopen, that usually amounts to -

MSVCR[VS version][D].dll

(I seem to recall the extension was needed - but maybe that changed in VS2010). The 'D' indicates the debug dll version. The VS version number is decoded as: VS2005 -> 8, VS2008 -> 9, VS2010 -> 10.

Also note the evaluation-engine has various other gotchas to watch out for.

浪菊怪哟 2024-09-12 14:26:54

为了补充 Ofek 的出色答案,我发现了一种方法可以系统地找出函数调用属于哪个模块。 (即 MSVCR100D 部分)。

  • 单步执行调试器,查找要调用的函数的实例。 (在本例中,我正在寻找fopen);
  • 找到它后,按 F11 进入它。
  • 右键单击并选择“显示反汇编”
  • 可以找到当前正在执行的指令的地址。 (如果未显示,请单击查看选项周围进行切换)
  • 打开模块调试窗口 (Alt+Ctrl+U)
  • 查看已加载模块的列表,其中地址范围涵盖当前指令的地址。砰,您已经找到了该函数的模块名称!

我相信您可以使用此方法来查找任何类的模块名称。例如,当您正在查看大型代码库并且想要在立即窗口中动态调用某些任意类的方法时,这可能很有用。您或许还可以通过自己调用构造函数来动态创建类的实例。

C++ 不是母语吗?我们几乎感觉就像在一个托管的脚本环境中:P

To supplement Ofek's excellent answer, here is a way I found to systematically find out what module a function call belongs to. (i.e. the MSVCR100D part).

  • Step through the debugger looking for an instance of the function you want to call. (In this case, I was looking for fopen);
  • When you find it, step into it by pressing F11.
  • Right click and choose Show Disassembly
  • You can find the address of the currently executing instruction. (Click around the Viewing Options to toggle it if it isn't shown)
  • Open the Modules debug window (Alt+Ctrl+U)
  • Look through the list of loaded modules with the Address range covering the current instruction's address. Bam, you've found the module name for the function!

I believe you can use this method to find the module name for any class. This can be useful when for example you're reviewing a large code base and you want to invoke some arbitrary class's method on the fly in the Immediate Window. You can probably also create instances of classes on the fly by calling the constructor yourself.

Now wasn't C++ a native language? We almost feel like in a managed, scripting environment here :P

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文