这个C程序中,静态变量的内存位置会发生什么变化?

4
我目前正在调试一个使用静态变量来切换调试日志开关的程序(使用lldb)。奇怪的是,一些日志信息没有显示出来(而其他日志信息则有)。
当变量最初被设置时,我在变量地址上设置了硬件断点:idevicedebug.c#L232debug.c#L46 然而,如果我进入其中一个不起作用的日志函数,硬件断点不仅不会触发,而且如果我打印静态变量的地址,它完全不同。

这里举例说明:idevicedebug.c#L322debug_level的地址与最初的internal_set_debug_level不同(值现在为0而不是1):debug.c#L87

我是否误解了静态变量的工作原理?二进制文件是否可能链接到同一代码的两个版本?我不确定如何进一步调试。

编辑:以下是相关代码(经过简化的命令行实用程序,可通过USB连接将GDB数据包命令发送到iOS设备):

idevicedebug.c:

int main(int argc, char *argv[])
{
    /* ... */
    int i;
    int debug_level = 0;
    /* ... */


    /* parse command line arguments */
    for (i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
            debug_level++;
            idevice_set_debug_level(debug_level); // <- local debug_level is 1
            continue;
        }
    }

    /* ... */

    /* set maximum packet size */
    debug_info("Setting maximum packet size..."); // <- this does not print to stdout

    /* ... */

debug.h:

/* ... */

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && !defined(STRIP_DEBUG_CODE)
#define debug_info(...) debug_info_real (__func__, __FILE__, __LINE__, __VA_ARGS__)
#elif defined(__GNUC__) && __GNUC__ >= 3 && !defined(STRIP_DEBUG_CODE)
#define debug_info(...) debug_info_real (__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
#else
#define debug_info(...)
#endif

void debug_info_real(const char *func,
                                            const char *file,
                                            int line,
                                            const char *format, ...);

/* ... */

void internal_set_debug_level(int level);

#endif

debug.c:

/* ... */

static int debug_level;

void internal_set_debug_level(int level)
{
    debug_level = level; // <- static debug_level set to 1
}

/* ... */

void debug_info_real(const char *func, const char *file, int line, const char *format, ...)
{
#ifndef STRIP_DEBUG_CODE
    va_list args;
    char *buffer = NULL;

    if (!debug_level) // <- this is 0 despite being set previously
        return;       // breakpoint in internal_set_debug_level shows
                      // debug_level at 0x00000001000b75fc (== 1), yet
                      // here at 0x00000001000041b4 (== 0)

    /* run the real fprintf */
    va_start(args, format);
    (void)vasprintf(&buffer, format, args);
    va_end(args);

    debug_print_line(func, file, line, buffer);

    free(buffer);
#endif
}

lldb输出:

Process 29615 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
    frame #0: 0x00000001000ae0c7 libimobiledevice.6.dylib`internal_set_debug_level(level=1) at debug.c:46
   43
   44   void internal_set_debug_level(int level)
   45   {
-> 46           debug_level = level;
   47   }
   48
Target 0: (idevicedebug) stopped.
(lldb) p debug_level
(int) $0 = 0
(lldb) p &debug_level
(int *) $1 = 0x00000001000b75fc
(lldb) watch set expression (int *)0x00000001000b75fc
Watchpoint created: Watchpoint 1: addr = 0x1000b75fc size = 8 state = enabled type = w
    new value: 0x0000000000000000
(lldb) n

Watchpoint 1 hit:
old value: 0x0000000000000000
new value: 0x0000000000000001
Process 29615 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1
    frame #0: 0x00000001000ae0d0 libimobiledevice.6.dylib`internal_set_debug_level(level=1) at debug.c:47
   44   void internal_set_debug_level(int level)
   45   {
   46           debug_level = level;
-> 47   }
Target 0: (idevicedebug) stopped.
(lldb) c
Process 29615 resuming
Process 29615 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
    frame #0: 0x0000000100001e58 idevicedebug`main(argc=4, argv=0x00007fff5fbfef50) at idevicedebug.c:359
   357
   358                          /* set maximum packet size */
-> 359                          debug_info("Setting maximum packet size...");
   360
Target 0: (idevicedebug) stopped.
(lldb) s
Process 29615 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
    frame #0: 0x0000000100002fff idevicedebug`debug_info_real(func="main", file="idevicedebug.c", line=359, format="Setting maximum packet size...") at debug.c:85
   82   {
   83   #ifndef STRIP_DEBUG_CODE
   84           va_list args;
-> 85           char *buffer = NULL;
   86
   87           if (!debug_level)
   88                   return;
Target 0: (idevicedebug) stopped.
(lldb) p debug_level
(int) $3 = 0
(lldb) p &debug_level
(int *) $4 = 0x00000001000041b4

2
你确定你没有把在debug.c中声明的静态变量debug_level和在main中声明的局部变量debug_level混淆了吗? - AnT stands with Russia
@AnT 我不这么认为,因为它们两个都应该被设置为1,在我发布的第二次调用中,值为0(这是问题所在)。 - user1234
1
请在此处发布您的代码,而不是在远程站点上。请将其缩小为 [mcve] 而不是发布整个代码。 - Barmar
@Barmar 我不确定如何做到这一点,因为这不是我的代码(我正在调试一个我编译的第三方程序,它无法正常工作)。 - user1234
也许您忘记了用“-fPIC”编译库。如果共享库被交换出去,然后恢复,它将表现出奇怪的行为。 - jxh
显示剩余3条评论
1个回答

2
你没有问题理解静态变量的工作原理。
很不确定,但是问题似乎出在链接阶段。可能是静态/动态链接的混合。根据调试器输出,你包含了相同的代码两次:
- `libimobiledevice.la` 包含 `common/debug.c`(通过 `common/libinternalcommon.la`) - `idevicedebug` 似乎通过 `libinternalcommon` 静态地和通过 `libimobiledevice` 动态地包含它。
我建议在 `tools/Makefile.am` 中将 `common/libinternalcommon.la` 从 `idevicedebug_LDFLAGS` 中移除。
我的机器上执行 `autogen.sh` 失败了,所以我无法提供更多帮助,但你应该明白了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接