arm平台的调用栈回溯(backtrace)

介绍

arm平台的调用栈与x86平台的调用栈大致相同,稍微有些区别,主要在于栈帧的压栈内容和传参方式不同。在arm平台的不同程序,采用的编译选项不同,程序运行期间的栈帧也会不同。有些工具在对arm的调用栈回溯时,可能会遇到无法回溯的情况。例如gdb在使用bt查看core dump文件调用栈时,有时会出现Backtrace stoped的情况,有可能就是栈空间的压栈顺序导致的。当工具无法回溯时,就需要人工结合汇编代码对栈进行回溯,或者使用unwind进行回溯。

arm栈帧结构

![arm的一种栈结构](data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8%0D%0AIURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3%0D%0ALnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPCEtLSDnlLEgTWljcm9z%0D%0Ab2Z0IFZpc2lvLCBTVkcgRXhwb3J0IOeUn+aIkCBzdGFjay5zdmcgUGFnZS0xIC0tPg0KPHN2ZyB4%0D%0AbWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3%0D%0ALnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpldj0iaHR0cDovL3d3dy53My5vcmcvMjAwMS94bWwt%0D%0AZXZlbnRzIg0KCQl4bWxuczp2PSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3Zpc2lvLzIw%0D%0AMDMvU1ZHRXh0ZW5zaW9ucy8iIHdpZHRoPSI0LjUwMTY3aW4iIGhlaWdodD0iMy42MTU0NGluIg0K%0D%0ACQl2aWV3Qm94PSIwIDAgMzI0LjEyIDI2MC4zMTIiIHhtbDpzcGFjZT0icHJlc2VydmUiIGNvbG9y%0D%0ALWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiIgY2xhc3M9InN0MTYiPg0KCTx2OmRvY3VtZW50%0D%0AUHJvcGVydGllcyB2OmxhbmdJRD0iMjA1MiIgdjptZXRyaWM9InRydWUiIHY6dmlld01hcmt1cD0i%0D%0AZmFsc2UiPg0KCQk8djp1c2VyRGVmcz4NCgkJCTx2OnVkIHY6bmFtZVU9Im1zdk5vQXV0b0Nvbm5l%0D%0AY3QiIHY6dmFsPSJWVDAoMSk6MjYiLz4NCgkJPC92OnVzZXJEZWZzPg0KCTwvdjpkb2N1bWVudFBy%0D%0Ab3BlcnRpZXM+DQoNCgk8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCTwhW0NEQVRBWw0KCQkuc3Qx%0D%0AIHtmaWxsOiNmZmZmZmY7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tl%0D%0ALWxpbmVqb2luOnJvdW5kO3N0cm9rZS13aWR0aDowLjI0O3Zpc2liaWxpdHk6aGlkZGVufQ0KCQku%0D%0Ac3QyIHtmaWxsOiNmZmZmZmY7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ry%0D%0Ab2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS13aWR0aDowLjI0fQ0KCQkuc3QzIHtmaWxsOiNlZWVh%0D%0AZjI7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJv%0D%0AdW5kO3N0cm9rZS13aWR0aDowLjI0fQ0KCQkuc3Q0IHtmaWxsOiMwMDAwMDA7Zm9udC1mYW1pbHk6%0D%0A5a6L5L2TO2ZvbnQtc2l6ZTowLjY2NjY2NGVtfQ0KCQkuc3Q1IHtmaWxsOiNmOWM0OTk7c3Ryb2tl%0D%0AOiMwMDAwMDA7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9r%0D%0AZS13aWR0aDowLjI0fQ0KCQkuc3Q2IHttYXJrZXItZW5kOnVybCgjbXJrcjQtNDkpO3N0cm9rZToj%0D%0AMDAwMDAwO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Ut%0D%0Ad2lkdGg6MC4yNH0NCgkJLnN0NyB7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZToj%0D%0AMDAwMDAwO3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLXdpZHRoOjAuMDg2OTU2NTIxNzM5MTN9DQoJ%0D%0ACS5zdDgge2ZpbGw6bm9uZTtzdHJva2U6bm9uZTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2Ut%0D%0AbGluZWpvaW46cm91bmQ7c3Ryb2tlLXdpZHRoOjAuNzV9DQoJCS5zdDkge2ZpbGw6I2RkZTJjZH0N%0D%0ACgkJLnN0MTAge3N0cm9rZTpub25lO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9p%0D%0Abjpyb3VuZDtzdHJva2Utd2lkdGg6MC43NX0NCgkJLnN0MTEge3N0cm9rZTojMDAwMDAwO3N0cm9r%0D%0AZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6MC4yNH0N%0D%0ACgkJLnN0MTIge2ZpbGw6I2ZmZmZmZjtzdHJva2U6bm9uZTtzdHJva2UtbGluZWNhcDpyb3VuZDtz%0D%0AdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLXdpZHRoOjAuMjR9DQoJCS5zdDEzIHtmb250LXNp%0D%0AemU6MWVtfQ0KCQkuc3QxNCB7bWFya2VyLWVuZDp1cmwoI21ya3I0LTQ5KTttYXJrZXItc3RhcnQ6%0D%0AdXJsKCNtcmtyMTAtODApO3N0cm9rZTojMDAwMDAwO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9r%0D%0AZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6MC4yNH0NCgkJLnN0MTUge2ZpbGw6I2ZmZmZm%0D%0AZjtzdHJva2U6bm9uZTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS13aWR0aDo3LjJ9DQoJCS5z%0D%0AdDE2IHtmaWxsOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7Zm9udC1zaXplOjEycHg7b3ZlcmZsb3c6%0D%0AdmlzaWJsZTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6M30NCgldXT4N%0D%0ACgk8L3N0eWxlPg0KDQoJPGRlZnMgaWQ9Ik1hcmtlcnMiPg0KCQk8ZyBpZD0ibGVuZDQiPg0KCQkJ%0D%0APHBhdGggZD0iTSAyIDEgTCAwIDAgTCAyIC0xIEwgMiAxICIgc3R5bGU9InN0cm9rZTpub25lIi8+%0D%0ADQoJCTwvZz4NCgkJPG1hcmtlciBpZD0ibXJrcjQtNDkiIGNsYXNzPSJzdDciIHY6YXJyb3dUeXBl%0D%0APSI0IiB2OmFycm93U2l6ZT0iMiIgdjpzZXRiYWNrPSIyMyIgcmVmWD0iLTIzIiBvcmllbnQ9ImF1%0D%0AdG8iDQoJCQkJbWFya2VyVW5pdHM9InN0cm9rZVdpZHRoIiBvdmVyZmxvdz0idmlzaWJsZSI+DQoJ%0D%0ACQk8dXNlIHhsaW5rOmhyZWY9IiNsZW5kNCIgdHJhbnNmb3JtPSJzY2FsZSgtMTEuNSwtMTEuNSkg%0D%0AIi8+DQoJCTwvbWFya2VyPg0KCQk8ZyBpZD0ibGVuZDEwIj4NCgkJCTxwYXRoDQoJCQkJCWQ9Ik0g%0D%0AMCAwLjc1IEMgLTAuNDE0MjE0IDAuNzUgLTAuNzUgMC40MTQyMTQgLTAuNzUgMCAtMC43NSAtMC40%0D%0AMTQyMTQgLTAuNDE0MjE0IC0wLjc1IDAgLTAuNzUgMC40MTQyMTQgLTAuNzUgMC43NSAtMC40MTQy%0D%0AMTQgMC43NSAwIDAuNzUgMC40MTQyMTQgMC40MTQyMTQgMC43NSAwIDAuNzUgWiAiDQoJCQkJCXN0%0D%0AeWxlPSJzdHJva2U6bm9uZSIvPg0KCQk8L2c+DQoJCTxtYXJrZXIgaWQ9Im1ya3IxMC04MCIgY2xh%0D%0Ac3M9InN0NyIgdjphcnJvd1R5cGU9IjEwIiB2OmFycm93U2l6ZT0iMiIgdjpzZXRiYWNrPSI3LjEy%0D%0ANSIgcmVmWD0iNy4xMjUiIG9yaWVudD0iYXV0byINCgkJCQltYXJrZXJVbml0cz0ic3Ryb2tlV2lk%0D%0AdGgiIG92ZXJmbG93PSJ2aXNpYmxlIj4NCgkJCTx1c2UgeGxpbms6aHJlZj0iI2xlbmQxMCIgdHJh%0D%0AbnNmb3JtPSJzY2FsZSgxMS41KSAiLz4NCgkJPC9tYXJrZXI+DQoJPC9kZWZzPg0KCTxnIHY6bUlE%0D%0APSIwIiB2OmluZGV4PSIxIiB2Omdyb3VwQ29udGV4dD0iZm9yZWdyb3VuZFBhZ2UiPg0KCQk8dGl0%0D%0AbGU+6aG1LTE8L3RpdGxlPg0KCQk8djpwYWdlUHJvcGVydGllcyB2OmRyYXdpbmdTY2FsZT0iMC4w%0D%0AMzkzNzAxIiB2OnBhZ2VTY2FsZT0iMC4wMzkzNzAxIiB2OmRyYXdpbmdVbml0cz0iMjQiIHY6c2hh%0D%0AZG93T2Zmc2V0WD0iOC41MDM5NCINCgkJCQl2OnNoYWRvd09mZnNldFk9Ii04LjUwMzk0Ii8+DQoJ%0D%0ACTxnIGlkPSJncm91cDItMSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTM2LjAxMywtMTguMTIpIiB2%0D%0AOm1JRD0iMiIgdjpncm91cENvbnRleHQ9Imdyb3VwIj4NCgkJCTx2OnVzZXJEZWZzPg0KCQkJCTx2%0D%0AOnVkIHY6bmFtZVU9InZpc1ZlcnNpb24iIHY6dmFsPSJWVDAoMTUpOjI2Ii8+DQoJCQk8L3Y6dXNl%0D%0AckRlZnM+DQoJCQk8dGl0bGU+5aCG5qCI5oiW5aCGPC90aXRsZT4NCgkJCTxnIGlkPSJzaGFwZTMt%0D%0AMiIgdjptSUQ9IjMiIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUo%0D%0AMCwtMjcwKSI+DQoJCQkJPHRpdGxlPuW3peS9nOihqC4zPC90aXRsZT4NCgkJCQk8cmVjdCB4PSIw%0D%0AIiB5PSIyNDIuMzEyIiB3aWR0aD0iNzAuODY2MSIgaGVpZ2h0PSIxOCIgY2xhc3M9InN0MSIvPg0K%0D%0ACQkJPC9nPg0KCQkJPGcgaWQ9InNoYXBlNC00IiB2Om1JRD0iNCIgdjpncm91cENvbnRleHQ9InNo%0D%0AYXBlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLC0yNTIpIj4NCgkJCQk8dGl0bGU+5bel5L2c6KGo%0D%0ALjQ8L3RpdGxlPg0KCQkJCTxyZWN0IHg9IjAiIHk9IjI0Mi4zMTIiIHdpZHRoPSI3MC44NjYxIiBo%0D%0AZWlnaHQ9IjE4IiBjbGFzcz0ic3QxIi8+DQoJCQk8L2c+DQoJCQk8ZyBpZD0ic2hhcGU1LTYiIHY6%0D%0AbUlEPSI1IiB2Omdyb3VwQ29udGV4dD0ic2hhcGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTIz%0D%0ANCkiPg0KCQkJCTx0aXRsZT7lt6XkvZzooaguNTwvdGl0bGU+DQoJCQkJPHJlY3QgeD0iMCIgeT0i%0D%0AMjQyLjMxMiIgd2lkdGg9IjcwLjg2NjEiIGhlaWdodD0iMTgiIGNsYXNzPSJzdDEiLz4NCgkJCTwv%0D%0AZz4NCgkJCTxnIGlkPSJzaGFwZTYtOCIgdjptSUQ9IjYiIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSIg%0D%0AdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMjE2KSI+DQoJCQkJPHRpdGxlPuW3peS9nOihqC42PC90%0D%0AaXRsZT4NCgkJCQk8cmVjdCB4PSIwIiB5PSIyNDIuMzEyIiB3aWR0aD0iNzAuODY2MSIgaGVpZ2h0%0D%0APSIxOCIgY2xhc3M9InN0MSIvPg0KCQkJPC9nPg0KCQkJPGcgaWQ9InNoYXBlNy0xMCIgdjptSUQ9%0D%0AIjciIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTk4KSI+%0D%0ADQoJCQkJPHRpdGxlPuW3peS9nOihqC43PC90aXRsZT4NCgkJCQk8cmVjdCB4PSIwIiB5PSIyNDIu%0D%0AMzEyIiB3aWR0aD0iNzAuODY2MSIgaGVpZ2h0PSIxOCIgY2xhc3M9InN0MSIvPg0KCQkJPC9nPg0K%0D%0ACQkJPGcgaWQ9InNoYXBlOC0xMiIgdjptSUQ9IjgiIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSIgdHJh%0D%0AbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTgwKSI+DQoJCQkJPHRpdGxlPuW3peS9nOihqC44PC90aXRs%0D%0AZT4NCgkJCQk8cmVjdCB4PSIwIiB5PSIyNDIuMzEyIiB3aWR0aD0iNzAuODY2MSIgaGVpZ2h0PSIx%0D%0AOCIgY2xhc3M9InN0MiIvPg0KCQkJPC9nPg0KCQkJPGcgaWQ9InNoYXBlOS0xNCIgdjptSUQ9Ijki%0D%0AIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTYyKSI+DQoJ%0D%0ACQkJPHRpdGxlPuW3peS9nOihqC45PC90aXRsZT4NCgkJCQk8ZGVzYz5sb2NhbCB2YXJzLi4uPC9k%0D%0AZXNjPg0KCQkJCTx2OnRleHRCbG9jayB2Om1hcmdpbnM9InJlY3QoMSwxLDEsMSkiIHY6dGFiU3Bh%0D%0AY2U9IjQyLjUxOTciLz4NCgkJCQk8djp0ZXh0UmVjdCBjeD0iMzUuNDMzMSIgY3k9IjI1MS4zMTIi%0D%0AIHdpZHRoPSI3MC44NyIgaGVpZ2h0PSIxOCIvPg0KCQkJCTxyZWN0IHg9IjAiIHk9IjI0Mi4zMTIi%0D%0AIHdpZHRoPSI3MC44NjYxIiBoZWlnaHQ9IjE4IiBjbGFzcz0ic3QzIi8+DQoJCQkJPHRleHQgeD0i%0D%0AOS40MyIgeT0iMjUzLjcxIiBjbGFzcz0ic3Q0IiB2OmxhbmdJRD0iMTAzMyI+PHY6cGFyYWdyYXBo%0D%0AIHY6aG9yaXpBbGlnbj0iMSIvPjx2OnRhYkxpc3QvPmxvY2FsIHZhcnMuLi48L3RleHQ+CQkJPC9n%0D%0APg0KCQkJPGcgaWQ9InNoYXBlMTAtMTciIHY6bUlEPSIxMCIgdjpncm91cENvbnRleHQ9InNoYXBl%0D%0AIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLC0xNDQpIj4NCgkJCQk8dGl0bGU+5bel5L2c6KGoLjEw%0D%0APC90aXRsZT4NCgkJCQk8ZGVzYz5mcDwvZGVzYz4NCgkJCQk8djp0ZXh0QmxvY2sgdjptYXJnaW5z%0D%0APSJyZWN0KDEsMSwxLDEpIiB2OnRhYlNwYWNlPSI0Mi41MTk3Ii8+DQoJCQkJPHY6dGV4dFJlY3Qg%0D%0AY3g9IjM1LjQzMzEiIGN5PSIyNTEuMzEyIiB3aWR0aD0iNzAuODciIGhlaWdodD0iMTgiLz4NCgkJ%0D%0ACQk8cmVjdCB4PSIwIiB5PSIyNDIuMzEyIiB3aWR0aD0iNzAuODY2MSIgaGVpZ2h0PSIxOCIgY2xh%0D%0Ac3M9InN0MyIvPg0KCQkJCTx0ZXh0IHg9IjMxLjQzIiB5PSIyNTMuNzEiIGNsYXNzPSJzdDQiIHY6%0D%0AbGFuZ0lEPSIxMDMzIj48djpwYXJhZ3JhcGggdjpob3JpekFsaWduPSIxIi8+PHY6dGFiTGlzdC8+%0D%0AZnA8L3RleHQ+CQkJPC9nPg0KCQkJPGcgaWQ9InNoYXBlMTEtMjAiIHY6bUlEPSIxMSIgdjpncm91%0D%0AcENvbnRleHQ9InNoYXBlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLC0xMjYpIj4NCgkJCQk8dGl0%0D%0AbGU+5bel5L2c6KGoLjExPC90aXRsZT4NCgkJCQk8ZGVzYz5zcDwvZGVzYz4NCgkJCQk8djp0ZXh0%0D%0AQmxvY2sgdjptYXJnaW5zPSJyZWN0KDEsMSwxLDEpIiB2OnRhYlNwYWNlPSI0Mi41MTk3Ii8+DQoJ%0D%0ACQkJPHY6dGV4dFJlY3QgY3g9IjM1LjQzMzEiIGN5PSIyNTEuMzEyIiB3aWR0aD0iNzAuODciIGhl%0D%0AaWdodD0iMTgiLz4NCgkJCQk8cmVjdCB4PSIwIiB5PSIyNDIuMzEyIiB3aWR0aD0iNzAuODY2MSIg%0D%0AaGVpZ2h0PSIxOCIgY2xhc3M9InN0MyIvPg0KCQkJCTx0ZXh0IHg9IjMxLjQzIiB5PSIyNTMuNzEi%0D%0AIGNsYXNzPSJzdDQiIHY6bGFuZ0lEPSIxMDMzIj48djpwYXJhZ3JhcGggdjpob3JpekFsaWduPSIx%0D%0AIi8+PHY6dGFiTGlzdC8+c3A8L3RleHQ+CQkJPC9nPg0KCQkJPGcgaWQ9InNoYXBlMTItMjMiIHY6%0D%0AbUlEPSIxMiIgdjpncm91cENvbnRleHQ9InNoYXBlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLC0x%0D%0AMDgpIj4NCgkJCQk8dGl0bGU+5bel5L2c6KGoLjEyPC90aXRsZT4NCgkJCQk8ZGVzYz5scjwvZGVz%0D%0AYz4NCgkJCQk8djp0ZXh0QmxvY2sgdjptYXJnaW5zPSJyZWN0KDEsMSwxLDEpIiB2OnRhYlNwYWNl%0D%0APSI0Mi41MTk3Ii8+DQoJCQkJPHY6dGV4dFJlY3QgY3g9IjM1LjQzMzEiIGN5PSIyNTEuMzEyIiB3%0D%0AaWR0aD0iNzAuODciIGhlaWdodD0iMTgiLz4NCgkJCQk8cmVjdCB4PSIwIiB5PSIyNDIuMzEyIiB3%0D%0AaWR0aD0iNzAuODY2MSIgaGVpZ2h0PSIxOCIgY2xhc3M9InN0MyIvPg0KCQkJCTx0ZXh0IHg9IjMx%0D%0ALjQzIiB5PSIyNTMuNzEiIGNsYXNzPSJzdDQiIHY6bGFuZ0lEPSIxMDMzIj48djpwYXJhZ3JhcGgg%0D%0Adjpob3JpekFsaWduPSIxIi8+PHY6dGFiTGlzdC8+bHI8L3RleHQ+CQkJPC9nPg0KCQkJPGcgaWQ9%0D%0AInNoYXBlMTMtMjYiIHY6bUlEPSIxMyIgdjpncm91cENvbnRleHQ9InNoYXBlIiB0cmFuc2Zvcm09%0D%0AInRyYW5zbGF0ZSgwLC05MCkiPg0KCQkJCTx0aXRsZT7lt6XkvZzooaguMTM8L3RpdGxlPg0KCQkJ%0D%0ACTxkZXNjPnBjPC9kZXNjPg0KCQkJCTx2OnRleHRCbG9jayB2Om1hcmdpbnM9InJlY3QoMSwxLDEs%0D%0AMSkiIHY6dGFiU3BhY2U9IjQyLjUxOTciLz4NCgkJCQk8djp0ZXh0UmVjdCBjeD0iMzUuNDMzMSIg%0D%0AY3k9IjI1MS4zMTIiIHdpZHRoPSI3MC44NyIgaGVpZ2h0PSIxOCIvPg0KCQkJCTxyZWN0IHg9IjAi%0D%0AIHk9IjI0Mi4zMTIiIHdpZHRoPSI3MC44NjYxIiBoZWlnaHQ9IjE4IiBjbGFzcz0ic3QzIi8+DQoJ%0D%0ACQkJPHRleHQgeD0iMzEuNDMiIHk9IjI1My43MSIgY2xhc3M9InN0NCIgdjpsYW5nSUQ9IjEwMzMi%0D%0APjx2OnBhcmFncmFwaCB2Omhvcml6QWxpZ249IjEiLz48djp0YWJMaXN0Lz5wYzwvdGV4dD4JCQk8%0D%0AL2c+DQoJCQk8ZyBpZD0ic2hhcGUxNC0yOSIgdjptSUQ9IjE0IiB2Omdyb3VwQ29udGV4dD0ic2hh%0D%0AcGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTcyKSI+DQoJCQkJPHRpdGxlPuW3peS9nOihqC4x%0D%0ANDwvdGl0bGU+DQoJCQkJPGRlc2M+bG9jYWwgdmFycy4uLjwvZGVzYz4NCgkJCQk8djp0ZXh0Qmxv%0D%0AY2sgdjptYXJnaW5zPSJyZWN0KDEsMSwxLDEpIiB2OnRhYlNwYWNlPSI0Mi41MTk3Ii8+DQoJCQkJ%0D%0APHY6dGV4dFJlY3QgY3g9IjM1LjQzMzEiIGN5PSIyNTEuMzEyIiB3aWR0aD0iNzAuODciIGhlaWdo%0D%0AdD0iMTgiLz4NCgkJCQk8cmVjdCB4PSIwIiB5PSIyNDIuMzEyIiB3aWR0aD0iNzAuODY2MSIgaGVp%0D%0AZ2h0PSIxOCIgY2xhc3M9InN0NSIvPg0KCQkJCTx0ZXh0IHg9IjkuNDMiIHk9IjI1My43MSIgY2xh%0D%0Ac3M9InN0NCIgdjpsYW5nSUQ9IjEwMzMiPjx2OnBhcmFncmFwaCB2Omhvcml6QWxpZ249IjEiLz48%0D%0Adjp0YWJMaXN0Lz5sb2NhbCB2YXJzLi4uPC90ZXh0PgkJCTwvZz4NCgkJCTxnIGlkPSJzaGFwZTE1%0D%0ALTMyIiB2Om1JRD0iMTUiIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSIgdHJhbnNmb3JtPSJ0cmFuc2xh%0D%0AdGUoMCwtNTQpIj4NCgkJCQk8dGl0bGU+5bel5L2c6KGoLjE1PC90aXRsZT4NCgkJCQk8ZGVzYz5m%0D%0AcDwvZGVzYz4NCgkJCQk8djp0ZXh0QmxvY2sgdjptYXJnaW5zPSJyZWN0KDEsMSwxLDEpIiB2OnRh%0D%0AYlNwYWNlPSI0Mi41MTk3Ii8+DQoJCQkJPHY6dGV4dFJlY3QgY3g9IjM1LjQzMzEiIGN5PSIyNTEu%0D%0AMzEyIiB3aWR0aD0iNzAuODciIGhlaWdodD0iMTgiLz4NCgkJCQk8cmVjdCB4PSIwIiB5PSIyNDIu%0D%0AMzEyIiB3aWR0aD0iNzAuODY2MSIgaGVpZ2h0PSIxOCIgY2xhc3M9InN0NSIvPg0KCQkJCTx0ZXh0%0D%0AIHg9IjMxLjQzIiB5PSIyNTMuNzEiIGNsYXNzPSJzdDQiIHY6bGFuZ0lEPSIxMDMzIj48djpwYXJh%0D%0AZ3JhcGggdjpob3JpekFsaWduPSIxIi8+PHY6dGFiTGlzdC8+ZnA8L3RleHQ+CQkJPC9nPg0KCQkJ%0D%0APGcgaWQ9InNoYXBlMTYtMzUiIHY6bUlEPSIxNiIgdjpncm91cENvbnRleHQ9InNoYXBlIiB0cmFu%0D%0Ac2Zvcm09InRyYW5zbGF0ZSgwLC0zNikiPg0KCQkJCTx0aXRsZT7lt6XkvZzooaguMTY8L3RpdGxl%0D%0APg0KCQkJCTxkZXNjPnNwPC9kZXNjPg0KCQkJCTx2OnRleHRCbG9jayB2Om1hcmdpbnM9InJlY3Qo%0D%0AMSwxLDEsMSkiIHY6dGFiU3BhY2U9IjQyLjUxOTciLz4NCgkJCQk8djp0ZXh0UmVjdCBjeD0iMzUu%0D%0ANDMzMSIgY3k9IjI1MS4zMTIiIHdpZHRoPSI3MC44NyIgaGVpZ2h0PSIxOCIvPg0KCQkJCTxyZWN0%0D%0AIHg9IjAiIHk9IjI0Mi4zMTIiIHdpZHRoPSI3MC44NjYxIiBoZWlnaHQ9IjE4IiBjbGFzcz0ic3Q1%0D%0AIi8+DQoJCQkJPHRleHQgeD0iMzEuNDMiIHk9IjI1My43MSIgY2xhc3M9InN0NCIgdjpsYW5nSUQ9%0D%0AIjEwMzMiPjx2OnBhcmFncmFwaCB2Omhvcml6QWxpZ249IjEiLz48djp0YWJMaXN0Lz5zcDwvdGV4%0D%0AdD4JCQk8L2c+DQoJCQk8ZyBpZD0ic2hhcGUxNy0zOCIgdjptSUQ9IjE3IiB2Omdyb3VwQ29udGV4%0D%0AdD0ic2hhcGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTE4KSI+DQoJCQkJPHRpdGxlPuW3peS9%0D%0AnOihqC4xNzwvdGl0bGU+DQoJCQkJPGRlc2M+bHI8L2Rlc2M+DQoJCQkJPHY6dGV4dEJsb2NrIHY6%0D%0AbWFyZ2lucz0icmVjdCgxLDEsMSwxKSIgdjp0YWJTcGFjZT0iNDIuNTE5NyIvPg0KCQkJCTx2OnRl%0D%0AeHRSZWN0IGN4PSIzNS40MzMxIiBjeT0iMjUxLjMxMiIgd2lkdGg9IjcwLjg3IiBoZWlnaHQ9IjE4%0D%0AIi8+DQoJCQkJPHJlY3QgeD0iMCIgeT0iMjQyLjMxMiIgd2lkdGg9IjcwLjg2NjEiIGhlaWdodD0i%0D%0AMTgiIGNsYXNzPSJzdDUiLz4NCgkJCQk8dGV4dCB4PSIzMS40MyIgeT0iMjUzLjcxIiBjbGFzcz0i%0D%0Ac3Q0IiB2OmxhbmdJRD0iMTAzMyI+PHY6cGFyYWdyYXBoIHY6aG9yaXpBbGlnbj0iMSIvPjx2OnRh%0D%0AYkxpc3QvPmxyPC90ZXh0PgkJCTwvZz4NCgkJCTxnIGlkPSJzaGFwZTE4LTQxIiB2Om1JRD0iMTgi%0D%0AIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSI+DQoJCQkJPHRpdGxlPuW3peS9nOihqC4xODwvdGl0bGU+%0D%0ADQoJCQkJPGRlc2M+cGM8L2Rlc2M+DQoJCQkJPHY6dGV4dEJsb2NrIHY6bWFyZ2lucz0icmVjdCgx%0D%0ALDEsMSwxKSIgdjp0YWJTcGFjZT0iNDIuNTE5NyIvPg0KCQkJCTx2OnRleHRSZWN0IGN4PSIzNS40%0D%0AMzMxIiBjeT0iMjUxLjMxMiIgd2lkdGg9IjcwLjg3IiBoZWlnaHQ9IjE4Ii8+DQoJCQkJPHJlY3Qg%0D%0AeD0iMCIgeT0iMjQyLjMxMiIgd2lkdGg9IjcwLjg2NjEiIGhlaWdodD0iMTgiIGNsYXNzPSJzdDUi%0D%0ALz4NCgkJCQk8dGV4dCB4PSIzMS40MyIgeT0iMjUzLjcxIiBjbGFzcz0ic3Q0IiB2OmxhbmdJRD0i%0D%0AMTAzMyI+PHY6cGFyYWdyYXBoIHY6aG9yaXpBbGlnbj0iMSIvPjx2OnRhYkxpc3QvPnBjPC90ZXh0%0D%0APgkJCTwvZz4NCgkJPC9nPg0KCQk8ZyBpZD0ic2hhcGUyMC00NCIgdjptSUQ9IjIwIiB2Omdyb3Vw%0D%0AQ29udGV4dD0ic2hhcGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIwNi44NzksLTk5LjEyKSI+DQoJ%0D%0ACQk8dGl0bGU+5aCG5qCI5oyH6ZKIPC90aXRsZT4NCgkJCTx2OnVzZXJEZWZzPg0KCQkJCTx2OnVk%0D%0AIHY6bmFtZVU9InZpc1ZlcnNpb24iIHY6dmFsPSJWVDAoMTUpOjI2Ii8+DQoJCQk8L3Y6dXNlckRl%0D%0AZnM+DQoJCQk8cGF0aCBkPSJNMCAyMDYuMzEgTDE4Ljk5IDIwNi4zMSBMMTguOTkgMjYwLjMxIEw1%0D%0ALjUyIDI2MC4zMSIgY2xhc3M9InN0NiIvPg0KCQk8L2c+DQoJCTxnIGlkPSJzaGFwZTIxLTUwIiB2%0D%0AOm1JRD0iMjEiIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjA2%0D%0ALjg3OSwtMjcuMTIpIj4NCgkJCTx0aXRsZT7loIbmoIjmjIfpkoguMjE8L3RpdGxlPg0KCQkJPHY6%0D%0AdXNlckRlZnM+DQoJCQkJPHY6dWQgdjpuYW1lVT0idmlzVmVyc2lvbiIgdjp2YWw9IlZUMCgxNSk6%0D%0AMjYiLz4NCgkJCTwvdjp1c2VyRGVmcz4NCgkJCTxwYXRoIGQ9Ik0wIDExNi4zMSBMMjQuOTQgMTE2%0D%0ALjMxIEwyNC45NCAyNjAuMzEgTDUuNTIgMjYwLjMxIiBjbGFzcz0ic3Q2Ii8+DQoJCTwvZz4NCgkJ%0D%0APGcgaWQ9InNoYXBlNDEtNTUiIHY6bUlEPSI0MSIgdjpncm91cENvbnRleHQ9InNoYXBlIiB0cmFu%0D%0Ac2Zvcm09InRyYW5zbGF0ZSg3Ni43Njg3LC0yMjIuODQxKSI+DQoJCQk8dGl0bGU+5bel5L2c6KGo%0D%0ALjQxPC90aXRsZT4NCgkJCTxkZXNjPnJlZ2lzdGVyczwvZGVzYz4NCgkJCTx2OnRleHRCbG9jayB2%0D%0AOm1hcmdpbnM9InJlY3QoNCw0LDQsNCkiIHY6dGFiU3BhY2U9IjQyLjUxOTciLz4NCgkJCTx2OnRl%0D%0AeHRSZWN0IGN4PSIyNi4wNzg3IiBjeT0iMjU1LjA2OCIgd2lkdGg9IjUyLjE2IiBoZWlnaHQ9IjEw%0D%0ALjQ4ODIiLz4NCgkJCTxyZWN0IHg9IjAiIHk9IjI0OS44MjQiIHdpZHRoPSI1Mi4xNTc1IiBoZWln%0D%0AaHQ9IjEwLjQ4ODIiIGNsYXNzPSJzdDgiLz4NCgkJCTx0ZXh0IHg9IjguMDgiIHk9IjI1Ny40NyIg%0D%0AY2xhc3M9InN0NCIgdjpsYW5nSUQ9IjIwNTIiPjx2OnBhcmFncmFwaCB2Omhvcml6QWxpZ249IjEi%0D%0ALz48djp0YWJMaXN0Lz5yZWdpc3RlcnM8L3RleHQ+CQk8L2c+DQoJCTxnIGlkPSJzaGFwZTQzLTU4%0D%0AIiB2Om1JRD0iNDMiIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUo%0D%0AMTQ1LjM2NywtMjIwLjk5OSkiPg0KCQkJPHRpdGxlPuW3peS9nOihqC40MzwvdGl0bGU+DQoJCQk8%0D%0AZGVzYz5zdGFjazwvZGVzYz4NCgkJCTx2OnRleHRCbG9jayB2Om1hcmdpbnM9InJlY3QoNCw0LDQs%0D%0ANCkiIHY6dGFiU3BhY2U9IjQyLjUxOTciLz4NCgkJCTx2OnRleHRSZWN0IGN4PSIyNi4wNzg3IiBj%0D%0AeT0iMjU1LjA2OCIgd2lkdGg9IjUyLjE2IiBoZWlnaHQ9IjEwLjQ4ODIiLz4NCgkJCTxyZWN0IHg9%0D%0AIjAiIHk9IjI0OS44MjQiIHdpZHRoPSI1Mi4xNTc1IiBoZWlnaHQ9IjEwLjQ4ODIiIGNsYXNzPSJz%0D%0AdDgiLz4NCgkJCTx0ZXh0IHg9IjE2LjA4IiB5PSIyNTcuNDciIGNsYXNzPSJzdDQiIHY6bGFuZ0lE%0D%0APSIyMDUyIj48djpwYXJhZ3JhcGggdjpob3JpekFsaWduPSIxIi8+PHY6dGFiTGlzdC8+c3RhY2s8%0D%0AL3RleHQ+CQk8L2c+DQoJCTxnIGlkPSJncm91cDQ1LTYxIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgt%0D%0AMTg4LjA3OSwyMzIuNDk1KSByb3RhdGUoLTkwKSIgdjptSUQ9IjQ1IiB2Omdyb3VwQ29udGV4dD0i%0D%0AZ3JvdXAiPg0KCQkJPHY6dXNlckRlZnM+DQoJCQkJPHY6dWQgdjpuYW1lVT0idmlzVmVyc2lvbiIg%0D%0Adjp2YWw9IlZUMCgxNSk6MjYiLz4NCgkJCTwvdjp1c2VyRGVmcz4NCgkJCTx0aXRsZT7lvIDmlL7l%0D%0AvI/kuIDnu7TljZXlkJHnrq3lpLQ8L3RpdGxlPg0KCQkJPGcgaWQ9InNoYXBlNDYtNjIiIHY6bUlE%0D%0APSI0NiIgdjpncm91cENvbnRleHQ9InNoYXBlIj4NCgkJCQk8dGl0bGU+5bel5L2c6KGoLjQ2PC90%0D%0AaXRsZT4NCgkJCQk8cGF0aCBkPSJNLTIuMjUgMjU2Ljc3IEwxNzMuNjIgMjU2Ljc3IEwxNzMuNjIg%0D%0AMjYwLjMxIEwxNzcuMTcgMjUzLjIzIEwxNzMuNjIgMjQ2LjE0IEwxNzMuNjIgMjQ5LjY4IEwtMi4y%0D%0ANSAyNDkuNjggTC0yLjI1DQoJCQkJCQkJIDI1Ni43NyBaIiBjbGFzcz0ic3Q5Ii8+DQoJCQkJPHBh%0D%0AdGggZD0iTS0yLjI1IDI1Ni43NyBMMTczLjYyIDI1Ni43NyBMMTczLjYyIDI2MC4zMSBMMTc3LjE3%0D%0AIDI1My4yMyBMMTczLjYyIDI0Ni4xNCBMMTczLjYyIDI0OS42OCBMLTIuMjUgMjQ5LjY4Ig0KCQkJ%0D%0ACQkJY2xhc3M9InN0MTAiLz4NCgkJCTwvZz4NCgkJCTxnIGlkPSJzaGFwZTQ3LTY1IiB2Om1JRD0i%0D%0ANDciIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSI+DQoJCQkJPHRpdGxlPuW3peS9nOihqC40NzwvdGl0%0D%0AbGU+DQoJCQkJPHBhdGggZD0iTTAgMjU2Ljc3IEwxNzMuNjIgMjU2Ljc3IEwxNzMuNjIgMjYwLjMx%0D%0AIEwxNzcuMTcgMjUzLjIzIEwxNzMuNjIgMjQ2LjE0IEwxNzMuNjIgMjQ5LjY4IEwwIDI0OS42OCIN%0D%0ACgkJCQkJCWNsYXNzPSJzdDExIi8+DQoJCQk8L2c+DQoJCQk8ZyBpZD0ic2hhcGU0OC02OCIgdjpt%0D%0ASUQ9IjQ4IiB2Omdyb3VwQ29udGV4dD0ic2hhcGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjAx%0D%0AMTY1LC0zLjc4MzMxKSI+DQoJCQkJPHRpdGxlPuW3peS9nOihqC40ODwvdGl0bGU+DQoJCQkJPHJl%0D%0AY3QgeD0iMCIgeT0iMjUzLjcwNSIgd2lkdGg9IjAuNDgiIGhlaWdodD0iNi42MDY2MSIgY2xhc3M9%0D%0AInN0MTIiLz4NCgkJCTwvZz4NCgkJPC9nPg0KCQk8ZyBpZD0ic2hhcGU1My03MCIgdjptSUQ9IjUz%0D%0AIiB2Omdyb3VwQ29udGV4dD0ic2hhcGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIyLjYyNywtMjcu%0D%0AODE3NSkiPg0KCQkJPHRpdGxlPuW3peS9nOihqC41MzwvdGl0bGU+DQoJCQk8ZGVzYz5oaWdoIGFk%0D%0AZHJlc3M8L2Rlc2M+DQoJCQk8djp0ZXh0QmxvY2sgdjptYXJnaW5zPSJyZWN0KDQsNCw0LDQpIiB2%0D%0AOnRhYlNwYWNlPSI0Mi41MTk3Ii8+DQoJCQk8djp0ZXh0UmVjdCBjeD0iMTguNDI1MiIgY3k9IjI1%0D%0ANS4yMSIgd2lkdGg9IjM2Ljg2IiBoZWlnaHQ9IjEwLjIwNDciLz4NCgkJCTxyZWN0IHg9IjAiIHk9%0D%0AIjI1MC4xMDciIHdpZHRoPSIzNi44NTA0IiBoZWlnaHQ9IjEwLjIwNDciIGNsYXNzPSJzdDgiLz4N%0D%0ACgkJCTx0ZXh0IHg9IjEwLjQyIiB5PSIyNTIuODEiIGNsYXNzPSJzdDQiIHY6bGFuZ0lEPSIyMDUy%0D%0AIj48djpwYXJhZ3JhcGggdjpob3JpekFsaWduPSIxIi8+PHY6dGFiTGlzdC8+aGlnaCA8dHNwYW4g%0D%0AeD0iNC40MiINCgkJCQkJCWR5PSIxLjJlbSIgY2xhc3M9InN0MTMiPmFkZHJlc3M8L3RzcGFuPjwv%0D%0AdGV4dD4JCTwvZz4NCgkJPGcgaWQ9InNoYXBlNTUtNzQiIHY6bUlEPSI1NSIgdjpncm91cENvbnRl%0D%0AeHQ9InNoYXBlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDAuNTgsLTE4OS4xMikiPg0KCQkJPHRp%0D%0AdGxlPuaMh+mSiCjkuIDnu7QpPC90aXRsZT4NCgkJCTxkZXNjPnNwPC9kZXNjPg0KCQkJPHY6dXNl%0D%0AckRlZnM+DQoJCQkJPHY6dWQgdjpuYW1lVT0idmlzVmVyc2lvbiIgdjp2YWw9IlZUMCgxNSk6MjYi%0D%0ALz4NCgkJCTwvdjp1c2VyRGVmcz4NCgkJCTx2OnRleHRCbG9jayB2Om1hcmdpbnM9InJlY3QoMSwx%0D%0ALDEsMSkiIHY6dGFiU3BhY2U9IjQyLjUxOTciLz4NCgkJCTx2OnRleHRSZWN0IGN4PSIxNy43MTY1%0D%0AIiBjeT0iMjUzLjIyNSIgd2lkdGg9IjM1LjQ0IiBoZWlnaHQ9IjAiLz4NCgkJCTxwYXRoIGQ9Ik0x%0D%0ALjcxIDI2MC4zMSBMMi4wNyAyNjAuMzEgTDI5LjkxIDI2MC4zMSIgY2xhc3M9InN0MTQiLz4NCgkJ%0D%0ACTxyZWN0IHY6cmVjdENvbnRleHQ9InRleHRCa2duZCIgeD0iMTMuNzE2NCIgeT0iMjQ4LjQyNSIg%0D%0Ad2lkdGg9IjguMDAwMjQiIGhlaWdodD0iOS41OTk4NSIgY2xhc3M9InN0MTUiLz4NCgkJCTx0ZXh0%0D%0AIHg9IjEzLjcyIiB5PSIyNTUuNjMiIGNsYXNzPSJzdDQiIHY6bGFuZ0lEPSIyMDUyIj48djpwYXJh%0D%0AZ3JhcGggdjpob3JpekFsaWduPSIxIi8+PHY6dGFiTGlzdC8+c3A8L3RleHQ+CQk8L2c+DQoJCTxn%0D%0AIGlkPSJzaGFwZTU2LTg0IiB2Om1JRD0iNTYiIHY6Z3JvdXBDb250ZXh0PSJzaGFwZSIgdHJhbnNm%0D%0Ab3JtPSJ0cmFuc2xhdGUoMTAwLjU4LC0xMTcuMTIpIj4NCgkJCTx0aXRsZT7mjIfpkogo5LiA57u0%0D%0AKS41NjwvdGl0bGU+DQoJCQk8ZGVzYz5mcDwvZGVzYz4NCgkJCTx2OnVzZXJEZWZzPg0KCQkJCTx2%0D%0AOnVkIHY6bmFtZVU9InZpc1ZlcnNpb24iIHY6dmFsPSJWVDAoMTUpOjI2Ii8+DQoJCQk8L3Y6dXNl%0D%0AckRlZnM+DQoJCQk8djp0ZXh0QmxvY2sgdjptYXJnaW5zPSJyZWN0KDEsMSwxLDEpIiB2OnRhYlNw%0D%0AYWNlPSI0Mi41MTk3Ii8+DQoJCQk8djp0ZXh0UmVjdCBjeD0iMTcuNzE2NSIgY3k9IjI1My4yMjUi%0D%0AIHdpZHRoPSIzNS40NCIgaGVpZ2h0PSIwIi8+DQoJCQk8cGF0aCBkPSJNMS43MSAyNjAuMzEgTDIu%0D%0AMDcgMjYwLjMxIEwyOS45MSAyNjAuMzEiIGNsYXNzPSJzdDE0Ii8+DQoJCQk8cmVjdCB2OnJlY3RD%0D%0Ab250ZXh0PSJ0ZXh0QmtnbmQiIHg9IjEzLjcxNjQiIHk9IjI0OC40MjUiIHdpZHRoPSI4LjAwMDI0%0D%0AIiBoZWlnaHQ9IjkuNTk5ODUiIGNsYXNzPSJzdDE1Ii8+DQoJCQk8dGV4dCB4PSIxMy43MiIgeT0i%0D%0AMjU1LjYzIiBjbGFzcz0ic3Q0IiB2OmxhbmdJRD0iMjA1MiI+PHY6cGFyYWdyYXBoIHY6aG9yaXpB%0D%0AbGlnbj0iMSIvPjx2OnRhYkxpc3QvPmZwPC90ZXh0PgkJPC9nPg0KCQk8ZyBpZD0ic2hhcGU1Ny05%0D%0AMyIgdjptSUQ9IjU3IiB2Omdyb3VwQ29udGV4dD0ic2hhcGUiIHRyYW5zZm9ybT0idHJhbnNsYXRl%0D%0AKDE4LjM3NSwtMTkyLjc5NCkiPg0KCQkJPHRpdGxlPuW3peS9nOihqC41NzwvdGl0bGU+DQoJCQk8%0D%0AZGVzYz5sb3cgYWRkcmVzczwvZGVzYz4NCgkJCTx2OnRleHRCbG9jayB2Om1hcmdpbnM9InJlY3Qo%0D%0ANCw0LDQsNCkiIHY6dGFiU3BhY2U9IjQyLjUxOTciLz4NCgkJCTx2OnRleHRSZWN0IGN4PSIxOC40%0D%0AMjUyIiBjeT0iMjU1LjIxIiB3aWR0aD0iMzYuODYiIGhlaWdodD0iMTAuMjA0NyIvPg0KCQkJPHJl%0D%0AY3QgeD0iMCIgeT0iMjUwLjEwNyIgd2lkdGg9IjM2Ljg1MDQiIGhlaWdodD0iMTAuMjA0NyIgY2xh%0D%0Ac3M9InN0OCIvPg0KCQkJPHRleHQgeD0iMTIuNDIiIHk9IjI1Mi44MSIgY2xhc3M9InN0NCIgdjps%0D%0AYW5nSUQ9IjIwNTIiPjx2OnBhcmFncmFwaCB2Omhvcml6QWxpZ249IjEiLz48djp0YWJMaXN0Lz5s%0D%0Ab3cgPHRzcGFuIHg9IjQuNDIiDQoJCQkJCQlkeT0iMS4yZW0iIGNsYXNzPSJzdDEzIj5hZGRyZXNz%0D%0APC90c3Bhbj48L3RleHQ+CQk8L2c+DQoJPC9nPg0KPC9zdmc+DQo=)

通常情况下,arm的调用栈大致结构与x86相同,都是从高地址向低地址扩张。上图是其中一种内存分布。

pc, lr, sp, fp是处理器的寄存器,其含义如下:

  • pc, program counter,程序计数器。程序当前运行的指令会放入到pc寄存器中
  • fp, 即frame pointer,帧指针。通常指向一个函数的栈帧底部,表示一个函数栈的开始位置。
  • sp, stack pointer,栈顶指针。指向当前栈空间的顶部位置,当进行push和pop时会一起移动。
  • lr, link register。在进行函数调用时,会将函数返回后要执行的下一条指令放入lr中,对应x86架构下的返回地址。

调用栈从高地址向低地址增长,当函数调用时,分别将分别将pc, lr, ip和 fp寄存器压入栈中,然后移动sp指针,为当前程序开辟栈空间。

arm官方手册描述如下:

一个arm程序,在任一时刻都存在十五个通用寄存器,这取决于当前的处理器模式。 它们分别是 r0-r12、sp、lr。
sp(或 r13)是堆栈指针。 C 和 C++ 编译器始终将 sp 用作堆栈指针。 在 Thumb-2 中,sp 被严格定义为堆栈指针,因此许多对堆栈操作无用而又使用了 sp 的指令会产生不可预测的结果。 建议您不要将 sp 用作通用寄存器。
在用户模式下,lr(或 r14)用作链接寄存器 (lr),用于存储调用子例程时的返回地址。 如果返回地址存储在堆栈上,则也可将 r14 用作通用寄存器。
在异常处理模式下,lr 存放异常的返回地址;如果在一个异常内执行了子例程调用,则 lr 存放子例程的返回地址。如果返回地址存储在堆栈上,则可将 lr 用作通用寄存器。

除了官方手册中描述的sp,lr寄存器,通常r12还会作为fp寄存器。fp寄存器对于程序的运行没有帮助,主要用于对栈帧的回溯。因为sp时刻指向的栈顶,通过fp得知上一个栈帧的起始位置。

上图的调用栈对应的汇编代码如下。

  1. 8514行将当前的sp保存在ip中(ip只是个通用寄存器,用来在函数间分析和调用时暂存数据,通常为r12);
  2. 8518行将4个寄存器从右向左依次压栈。
  3. 851c行将保存的ip减4,得到当前被调用函数的fp地址,即指向栈里的pc位置。
  4. 8520行将sp减8,为栈空间开辟出8个字节的大小,用于存放局部便令。
00008514 <func1>:
     8514:   e1a0c00d    mov ip, sp
     8518:   e92dd800    push    {fp, ip, lr, pc}
     851c:   e24cb004    sub fp, ip, #4
     8520:   e24dd008    sub sp, sp, #8
     8524:   e3a03000    mov r3, #0
     8528:   e50b3010    str r3, [fp, #-16]
     852c:   e30805dc    movw    r0, #34268  ; 0x85dc
     8530:   e3400000    movt    r0, #0
     8534:   ebffff9d    bl  83b0 <puts@plt>
     8538:   e51b3010    ldr r3, [fp, #-16]
     853c:   e12fff33    blx r3
     8540:   e3a03000    mov r3, #0
     8544:   e1a00003    mov r0, r3
     8548:   e24bd00c    sub sp, fp, #12
     854c:   e89da800    ldm sp, {fp, sp, pc}

-mapcs-frame编译选项

在第一节中,程序压栈的寄存器有{fp, ip, lr, pc} 4个,这是在gcc带有-mapcs-frame的编译选项下编译出来的。而gcc默认情况下的参数为mno-apcs-frame。关于该选项,gcc的手册描述为,

Generate a stack frame that is compliant with the ARM Procedure Call Standard for all functions, even if this is not strictly necessary for correct execution of the code. Specifying -fomit-frame-pointer with this option causes the stack frames not to be generated for leaf functions. The default is -mno-apcs-frame. This option is deprecated.

也就是说,该编译选项会产生(push {fp, ip, lr, pc}),保证栈帧的格式。如果没有-mapcs-frame,则不保证帧格式和当前帧格式,GCC生成的指令可能会发生各种变化。在AAPCS发布之后[附录1],1993年的APCS就已经太旧了,所以
在gcc5.0之后,该选项已经被废弃。gcc5.0的更新记录写到:

The options -mapcs, -mapcs-frame, -mtpcs-frame and -mtpcs-leaf-frame which are only applicable to the old ABI have been deprecated.
至于该参数在将来是否会被gcc移除,那就不知道了。

将第一节中的程序重新使用默认编译选项,用4.7版本的gcc编译,结果如下。这时,fp还在,调用栈push了fp和lr到栈空间,新的fp指向了lr在栈中的位置。

00008514 <func1>:
     8514:   e92d4800    push    {fp, lr}
     8518:   e28db004    add fp, sp, #4
     851c:   e24dd008    sub sp, sp, #8
     8520:   e3a03000    mov r3, #0
     8524:   e50b3008    str r3, [fp, #-8]
     8528:   e30805d4    movw    r0, #34260  ; 0x85d4
     852c:   e3400000    movt    r0, #0
     8530:   ebffff9e    bl  83b0 <puts@plt>
     8534:   e51b3008    ldr r3, [fp, #-8]
     8538:   e12fff33    blx r3
     853c:   e3a03000    mov r3, #0
     8540:   e1a00003    mov r0, r3
     8544:   e24bd004    sub sp, fp, #4
     8548:   e8bd8800    pop {fp, pc}

 0000854c <main>:
     854c:   e92d4800    push    {fp, lr}
     8550:   e28db004    add fp, sp, #4
     8554:   ebffffee    bl  8514 <func1>
     8558:   e1a00003    mov r0, r3
     855c:   e8bd8800    pop {fp, pc}

使用gcc-7.3默认选项编译结果如下,fp已经不在了,虽然这里仍然可能通过r7得知上个栈帧的位置,但是已经没法使用fp获取栈帧了。此时是不保证栈帧保存在栈中的。所以依赖栈帧内容进行恢复已经非常不可靠。那么既然无法依赖fp,那该怎么进行栈帧回溯呢,gnu说使用unwind方法回溯,这节暂时不会介绍unwind方法。

000103c8 <func1>:
    103c8:   b580        push    {r7, lr}
    103ca:   b082        sub sp, #8
    103cc:   af00        add r7, sp, #0
    103ce:   2300        movs    r3, #0
    103d0:   607b        str r3, [r7, #4]
    103d2:   f240 4048   movw    r0, #1096   ; 0x448
    103d6:   f2c0 0001   movt    r0, #1
    103da:   f7ff ef7e   blx 102d8 <puts@plt>
    103de:   687b        ldr r3, [r7, #4]
    103e0:   4798        blx r3
    103e2:   2300        movs    r3, #0
    103e4:   4618        mov r0, r3
    103e6:   3708        adds    r7, #8
    103e8:   46bd        mov sp, r7
    103ea:   bd80        pop {r7, pc}

 000103ec <main>:
    103ec:   b580        push    {r7, lr}
    103ee:   af00        add r7, sp, #0
    103f0:   f7ff ffea   bl  103c8 <func1>
    103f4:   2300        movs    r3, #0
    103f6:   4618        mov r0, r3
    103f8:   bd80        pop {r7, pc}

使用栈帧进行回溯

这一节使用gcc4.7版本,默认编译选项编译出来的程序,演示调用栈回溯。该编译选项下,压栈的寄存器为{fp, lr}。

下边的内容是一段core dump中的寄存器和调用栈,本节将对这段内容进行回溯。

Reg:         r9, Val = 0xf7578000;  Reg:        r10, Val = 0x00000001;  
Reg:         fp, Val = 0x827d3104;  Reg:         ip, Val = 0xf7578ae0;  
Reg:         sp, Val = 0x827d30e0;  Reg:         lr, Val = 0xf7549990;  
Reg:         pc, Val = 0xf7548c20;  Reg:       cpsr, Val = 0x60000210;

0x827d30e0:	0x00000031	0x827d31a0	0x00000001	0xd5dff060	
0x827d30f0:	0xd5e0e6b1	0xd5dec134	0xf7578000	0xf7577c40	
0x827d3100:	0x827d313c	0xf7549990		
0x827d3140:	0x00000000	0xd5dec104	0xf7568514	0x00000002	
0x827d3150:	0xd5dec104	0xf7577c40	0xf7577c38	0xd5de9224	
0x827d3160:	0x827d31a0	0xf757a084	0xf7577c40	0xd5df6dd4	
0x827d3170:	0x827d3194	0x00000001	0xd5e0e678	0xd5dec104	
0x827d3180:	0xd5de9224	0xf7568548	0x00000000	0xf7568550	
  1. 当前sp地址为0x827d30e0,fp地址为0x827d3104,从而得知当前函数frame0的栈帧。fp指向的地址0x827d3104为frame1的lr,0x827d3100为上一个栈帧的fp。
0x827d30e0:	0x00000031	0x827d31a0	0x00000001	0xd5dff060	
0x827d30f0:	0xd5e0e6b1	0xd5dec134	0xf7578000	0xf7577c40	
0x827d3100:	0x827d313c(fp)	0xf7549990(lr)
  1. 从frame0的fp地址0x827d313c可知,frame1的调用栈起始地址,去掉frame0的内容,得到frame1的栈帧。
                                                                        0x827d312c	0xf7530c14	
0x827d3110:	0xd5dff060	0x0000002c	0xd5e0e6b1	0xd5e0e6b1	
0x827d3120:	0x00000001	0xd5e0e6b1	0xd5dff060	0xd5dec134	
0x827d3130:	0xf7578000	0xf7577c40	0x827d3194(fp)	0xf754ad0c(lr)
  1. 依次类推,依次得到frame2、frame3...的栈帧。

当汇编代码的函数调用使用push {fp, ip, lr, pc}时,则上一个栈帧的fp2在当前栈帧的(fp - #4)位置。栈帧的回溯要结合程序的汇编代码具体分析,有可能程序并不使用fp指针,也有可能栈中根本没有保存fp。

unwind方法回溯

TODO

附录1-函数调用标准缩略语

  • PCS Procedure Call Standard.
  • AAPCS Procedure Call Standard for the ARM Architecture (this standard).
  • APCS ARM Procedure Call Standard (obsolete).
  • TPCS Thumb Procedure Call Standard (obsolete).
  • ATPCS ARM-Thumb Procedure Call Standard (precursor to this standar

参考资料

  1. ARM 体系结构概述
  2. Procedure Call Standard for the ARM® Architecture
  3. GCC 5 Release Series
posted @ 2018-09-25 10:20  your2b  阅读(3592)  评论(0编辑  收藏  举报