《coredump问题原理探究》Linux x86版3.1节栈布局之概述

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/details/8498773

在定位core dump问题,看栈是必要的一步。因为栈是反映了程序崩溃那一瞬间的情况,包括函数调用关系,参数,局部变量。要找出程序崩溃的地方,必须以栈为依据。而在开发过程中,一般会有调试版本和发布版本,其中调试版本会包含很多符号信息便于调试,而发布版本往往为了商业秘密的保护,在产品发布时去掉了调试信息。这两种方式会导致栈在可读性上不一样。

调试版本:

(gdb) bt
#0  recurse (num=1, level=9) at xuzhina_dump_c3.cpp:9
#1  0x080484a0 in recurse (num=2, level=8) at xuzhina_dump_c3.cpp:6
#2  0x080484a0 in recurse (num=3, level=7) at xuzhina_dump_c3.cpp:6
#3  0x080484a0 in recurse (num=4, level=6) at xuzhina_dump_c3.cpp:6
#4  0x080484a0 in recurse (num=5, level=5) at xuzhina_dump_c3.cpp:6
#5  0x080484a0 in recurse (num=6, level=4) at xuzhina_dump_c3.cpp:6
#6  0x080484a0 in recurse (num=7, level=3) at xuzhina_dump_c3.cpp:6
#7  0x080484a0 in recurse (num=8, level=2) at xuzhina_dump_c3.cpp:6
#8  0x080484a0 in recurse (num=9, level=1) at xuzhina_dump_c3.cpp:6
#9  0x080484a0 in recurse (num=10, level=0) at xuzhina_dump_c3.cpp:6
#10 0x080484d5 in main () at xuzhina_dump_c3.cpp:14

发布版本:

(gdb) bt
#0  0x080484a9 in recurse(int, int) ()
#1  0x080484a0 in recurse(int, int) ()
#2  0x080484a0 in recurse(int, int) ()
#3  0x080484a0 in recurse(int, int) ()
#4  0x080484a0 in recurse(int, int) ()
#5  0x080484a0 in recurse(int, int) ()
#6  0x080484a0 in recurse(int, int) ()
#7  0x080484a0 in recurse(int, int) ()
#8  0x080484a0 in recurse(int, int) ()
#9  0x080484a0 in recurse(int, int) ()
#10 0x080484d5 in main ()

同时在开发过程中,由于逻辑太过复杂,不小心引入了栈溢出,导致栈混乱,如前言里:

(gdb) bt
#0  0x6f745374 in ?? ()
#1  0x57735571 in ?? ()
#2  0xbff80065 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

第一种栈非常简单,也非常容易定位。但生活并不是那么容易。在产品的生命周期中,调试版本的时间是非常短的,而且在调试版本阶段,产品测试环境无论怎么模拟都没有产品发布后的客户环境那么复杂,很多潜在问题往往并不能在这个阶段发现。第二种栈比较麻烦,因为不知道函数的参数和局部变量,也不和代码行对应,出现问题非常难确定原因,且它在产品的生命周期的时间就非常长,从发布之前(一般发布版本在发布前一个阶段已经制作了)到产品该版本完全退出市场,甚至长达几年时间,而这几年时间内,相应的调试版本或调试信息文件可能已经由于历经几个版本的迭代而无从查找或者删除。第三种栈是最麻烦,因为根本就不知道问题出在哪个函数,特别在大型项目中,面对几百,几千万行的代码,更加无从入手,虽然它出现的机率可能很低,它的时间有可能从第一版本到整个产品退出市场为止,长达十几年,甚至二十几年。

由于第二,三种栈复杂性,所以希望找出栈布局的规律, 在遇到这种问题时不会措手不及。由于函数调用树在调试版本和发布版本一样,所以发布版本和调试版本的堆栈是一样的。

栈存放着函数相关的信息。这种情况叫做”调用约定(CallingConvention)”。如果阅读x86的规范,就会知道栈存放着函数桢指针,函数返回地址,函数参数,局部变量,及它们之间的布局。但是,也可以自己找出这种关系,这样印象会更深刻一些。

可以通过下面的步骤来探究”调用约定”:

1.      构造一些没有参数和局部变量的空函数来找出桢指针,返回地址的布局

2.      构造一些没有参数但有局部变量的函数来找出桢指针,返回地址,局部变量的布局

3.      构造一些有参数和局部变量的函数来看一下桢指针,返回地址,局部变量,参数的布局

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术记录

谈谈序列化—实体bean一定要实现Serializable接口?

导读:最近在做项目的过程中,发现一个问题,就是我们最开始的时候,传递参数包括返回类型,都有map类型。但是由于map每次都要匹配key值,很麻烦。所以在之后就将...

46580
来自专栏程序员互动联盟

【编程基础第四讲】遇到编译错误怎么办?

存在问题: 现在刚入门的小伙伴,在编译初级的代码一遇到错误就显得不知所措,那么怎么办? 解决方案: 编程的新手,包括刚毕业工作的同学在解决编译错误时有时候不知...

38390
来自专栏JavaQ

拒绝一针串到底式参数类

当参数个数多于三个的时候,通常会将这些参数封装到一个类中,进而形成参数类。参数类通常是类间或方法间进行通信的纽带,起到承上启下的作用。 基本上一个稍微有些规模的...

28680
来自专栏java一日一条

11 个简单的 Java 性能调优技巧

大多数开发人员理所当然地以为性能优化很复杂,需要大量的经验和知识。好吧,不能说这是完全错误的。优化应用程序以获得最佳性能不是一件容易的事情。但是,这并不意味着如...

11120
来自专栏java一日一条

Java 元编程及其应用

同样是实现一个投票系统,一个是python程序员,基于django-framework,用了半小时就搭建了一个完整系统,另外一个是标准的SSM(Spring-S...

20810
来自专栏mini188

学习笔记:内存,堆栈,到底为何物?

     在网上看到了一篇关于面试的博客文,突然发现自己对于这个博主而言简直差的是十万八千里,他提到的许多技术我尽然一个也答不上来。于是就开始反思,还是要抱一抱...

24660
来自专栏程序员宝库

给Python新手的一些编码建议

每天你都应该努力提升自己的编码技能,今天我给Python新手带来了一些编程建议。 Python箴言 打开Python交互终端并运行下面命令 ? 然后命令会有一...

387100
来自专栏子勰随笔

SDK开发经验之开发习惯

267100
来自专栏韩伟的专栏

实用主义编程规范:JAVA篇

JAVA代码规范 1.规范说明 此规范包含:避免出现常见恶劣代码的禁令;指导编写合格代码的基本规则 此规范不包含:分析与设计出符合业务需求的代码; 2.基本原则...

46460
来自专栏ytkah

调用finecms栏目多图怎么实现

  finecms栏目自定义字段添加图集怎么调用出来?已经上传两张图片了,点击可以预览图片,前端显示不了,如下图所示。调用栏目多图这个要涉及到二次开发,首先要先...

28660

扫码关注云+社区

领取腾讯云代金券