【问题标题】:core file memory analysis verification核心文件内存分析验证
【发布时间】:2020-02-14 19:21:01
【问题描述】:

一个应用程序正在生成一个核心文件。

这里是核心信息。

获取了错误堆栈,目的是检查 myStruct 变量中的数据内容,因为这是在核心发生时传递给 myFunction 的内容。

(gdb) where
#0  0x000000000041bba1 in myFunction (myStruct=0x7ffff9dd0c20) at myTest.c:344
        :
        :
        :

从上面我得到了 myStruct 在 0x7ffff9dd0c20 的地址,并转储了 200 个字。

(gdb) x/200x 0x7ffff9dd0c20
0x7ffff9dd0c20: 0x01938640      0x00000000      0x00001c34      0x000002c8
0x7ffff9dd0c30: 0x00000400      0x00000000      0x01939760      0x00000000
0x7ffff9dd0c40: 0x00000014      0x00000000      0x00000000      0x00000000
0x7ffff9dd0c50: 0x00000000      0x0005000c      0x00000000      0x000d0000
0x7ffff9dd0c60: 0x00000004      0x00000000      0x00000000      0x00000000
0x7ffff9dd0c70: 0x00000000      0x00000000      0x00040000      0x00000000
0x7ffff9dd0c80: 0x0001000c      0x00000000      0x00000000      0x00000000
0x7ffff9dd0c90: 0x00000000      0x00000000      0x00000009      0x00000000
0x7ffff9dd0ca0: 0x00000000      0x00000000      0x410d999a      0x418d999a
0x7ffff9dd0cb0: 0x40b80000      0x41380000      0x000010cc      0x00000000
0x7ffff9dd0cc0: 0x0192edd0      0x00000000      0x00000a30      0x00000158
   :
   :
   :

现在我想验证我是否正确读取了数据的输出。

这是结构信息。

typedef struct 
    {
    char *a;            
    unsigned int b; 
    unsigned int c; 
    int d;          
    } structA;

typedef struct
    {
    structA e;
    char *f;
    } myStruct;  <----------This is what gets passed in and what I am trying to examine.

在 Linux 上运行了一个程序来验证数据类型的大小。

Size of char* : 8
Size of int : 4

知道地址是 0x7ffff9dd0c20 并且结构是 myStruct,我假设 我从分析 structA 开始,因为它是第一个。

由于 char *a 是 structA 的第一部分,而 char * 是 2 个单词,我要看看这个:

  0x01938640      0x00000000 

接下来基本上有 3 个整数(2 个无符号整数和 1 个整数),我从输出中将它们视为这些:

0x00001c34      
0x000002c8
0x00000400

这将我带回到 structB 和应该是 2 个单词的 char *f 属性。
这是否意味着这是正确的地址:

0x00000000      0x01939760  

我在这里再次复制了内存信息,以便于参考。

(gdb) x/200x 0x7ffff9dd0c20
0x7ffff9dd0c20: 0x01938640      0x00000000      0x00001c34      0x000002c8
0x7ffff9dd0c30: 0x00000400      0x00000000      0x01939760      0x00000000
0x7ffff9dd0c40: 0x00000014      0x00000000      0x00000000      0x00000000
0x7ffff9dd0c50: 0x00000000      0x0005000c      0x00000000      0x000d0000
0x7ffff9dd0c60: 0x00000004      0x00000000      0x00000000      0x00000000
0x7ffff9dd0c70: 0x00000000      0x00000000      0x00040000      0x00000000
0x7ffff9dd0c80: 0x0001000c      0x00000000      0x00000000      0x00000000
0x7ffff9dd0c90: 0x00000000      0x00000000      0x00000009      0x00000000
0x7ffff9dd0ca0: 0x00000000      0x00000000      0x410d999a      0x418d999a
0x7ffff9dd0cb0: 0x40b80000      0x41380000      0x000010cc      0x00000000
0x7ffff9dd0cc0: 0x0192edd0      0x00000000      0x00000a30      0x00000158

这是检查和解析数据的正确方法吗?

这是另一种结构的定义。

typedef struct
    {
    short w;                    
    unsigned long x;            
    short y;                    
    short z;                    
    } otherStruct;

这是预期存储在 f 中的内容。

    char *f;

在 gdb 中,我尝试了以下操作:

 p (otherStruct *)0x1939760

然后打印出来:

 $12 = (otherStruct *) 0x1939760

奇怪的是,当我最初打印数据时,它显示 *f 如下,它看起来不像结构:

  f = 0x1939760 "\315\314\274@"

【问题讨论】:

    标签: c gdb coredump


    【解决方案1】:

    您正在艰难地读取数据。 gdb 知道结构定义,因此您可以使用p 命令告诉它直接打印结构。

    例如,给定这段代码使用你的结构:

    int main()
    {
        myStruct s = { { "aaa", 4, 5, 6 }, "bbb" };
        printf("hello\n");
    }
    

    在gdb下运行代码:

    (gdb) start
    Temporary breakpoint 1 at 0x400535: file x1.c, line 19.
    Starting program: /home/dbush/./x1 
    
    Temporary breakpoint 1, main () at x1.c:19
    19      myStruct s = { { "aaa", 4, 5, 6 }, "bbb" };
    Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.x86_64
    (gdb) step
    20      printf("hello\n");
    (gdb) p s
    $1 = {e = {a = 0x400600 "aaa", b = 4, c = 5, d = 6}, f = 0x400604 "bbb"}
    (gdb) 
    

    对于实际包含otherStruct * 的字段f,您可以通过强制转换f 并取消引用结果来打印其中包含的内容:

    p *(otherStruct *)myStruct->f
    

    话虽如此,您没有考虑结构内的填充。因为structA 包含一个大小为8 字节的char *,所以stuct 必须在8 字节边界上对齐。查看布局,这意味着 4 个字节的填充位于结构的末尾。

    所以转储中的第 6 个 32 位字 (0x00000000) 实际上就是那个填充。所以构成f的字节实际上是0x01939760 0x00000000

    查看上面示例代码的转储:

    (gdb) p s
    $1 = {e = {a = 0x400600 "aaa", b = 4, c = 5, d = 6}, f = 0x400604 "bbb"}
    (gdb) p &s
    $5 = (myStruct *) 0x7fffffffde50
    (gdb) x/20x 0x7fffffffde50
    0x7fffffffde50: 0x00400600  0x00000000  0x00000004  0x00000005
    0x7fffffffde60: 0x00000006  0x00007fff  0x00400604  0x00000000
    0x7fffffffde70: 0x00000000  0x00000000  0xf7a2f505  0x00007fff
    0x7fffffffde80: 0x00000000  0x00000000  0xffffdf58  0x00007fff
    0x7fffffffde90: 0x00000000  0x00000001  0x0040052d  0x00000000
    

    您可以看到e 字段中的值与原始转储匹配。 接下来您会看到填充字节,在这种情况下其值为0x00007fff。之后的 8 个字节与 f 的值匹配。

    【讨论】:

    • 哇,非常简单且易于阅读。非常感谢。
    • 嗯,“填充”带来了新的变化。它是否填充了随机值而不总是 0x00000000?
    • @UnhandledException struct 或 union 中填充字节的值未指定,这意味着值可以是任何值。
    • @UnhandledException 这将取消对指针的引用,但它仍然只是转储字节。您必须应用正确的演员表,即p (char *)0x01938640,然后您会将其视为字符串。
    • @UnhandledException 取消引用指针:p *((otherStruct*)myStruct-&gt;f)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2013-01-03
    • 2021-10-25
    • 2021-06-25
    • 1970-01-01
    • 2021-09-13
    相关资源
    最近更新 更多