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得知上一个栈帧的起始位置。
上图的调用栈对应的汇编代码如下。
- 8514行将当前的sp保存在ip中(ip只是个通用寄存器,用来在函数间分析和调用时暂存数据,通常为r12);
- 8518行将4个寄存器从右向左依次压栈。
- 851c行将保存的ip减4,得到当前被调用函数的fp地址,即指向栈里的pc位置。
- 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
- 当前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)
- 从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)
- 依次类推,依次得到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