Using as: Gnu Assembler(GAS) Directives CFI

Debugging using DWARF

CFI: Call Frame Information
CFI macros are used to generate dwarf2 unwind information for better backtraces. They don't change any code. If you find yourself in the position of combining C++ with assembly language routines, you can incorporate exception handling support by using the Call Frame Information directives. These directives generate stack unwinding information, such that any routines written in assembler will integrate nicely with C++ and other high-level languages.

Modern ABIs don't require frame pointers to be used in functions. However missing FPs bring difficulties when doing a backtrace. One solution is to provide Dwarf-2 CFI data for each such function. This can be easily done for example by GCC in it's output, but isn't that easy to write by hand for pure assembler functions.

With the help of these .cfi_* directives one can add appropriate unwind info into his asm source without too much trouble.

The call frame is identified by an address on the stack. We refer to this address as the Canonical Frame Address or CFA. Typically, the CFA is defined to be the value of the stack pointer at the call site in the previous frame (which may be different from its value on entry to the current frame).

下面是一些有用的链接:

http://www.ibm.com/developerworks/systems/library/es-gnutool/

http://www.logix.cz/michal/devel/gas-cfi/

http://dwarfstd.org/doc/DWARF4.pdf 

下面的链接对CFA的解释比较透彻:

http://stackoverflow.com/questions/7534420/gas-explanation-of-cfi-def-cfa-offset

 

arch/x86/include/asm/dwarf2.h

#ifdef CONFIG_AS_CFI

#define CFI_STARTPROC .cfi_startproc
#define CFI_ENDPROC .cfi_endproc
#define CFI_DEF_CFA .cfi_def_cfa
#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
#define CFI_OFFSET .cfi_offset
#define CFI_REL_OFFSET .cfi_rel_offset
#define CFI_REGISTER .cfi_register
#define CFI_RESTORE .cfi_restore
#define CFI_REMEMBER_STATE .cfi_remember_state
#define CFI_RESTORE_STATE .cfi_restore_state
#define CFI_UNDEFINED .cfi_undefined
#define CFI_ESCAPE .cfi_escape

#ifdef CONFIG_AS_CFI_SIGNAL_FRAME
#define CFI_SIGNAL_FRAME .cfi_signal_frame
#else
#define CFI_SIGNAL_FRAME
#endif

  

.cfi_startproc

.cfi_startproc is used at the beginning of each function that should have an entry in .eh_frame. It initializes some internal data structures and emits architecture dependent initial CFI instructions. Don't forget to close the function by .cfi_endproc.

.cfi_endproc

.cfi_endproc is used at the end of a function where it closes its unwind entry previously opened by .cfi_startproc. and emits it to.eh_frame.

.cfi_def_cfa registeroffset

.cfi_def_cfa defines a rule for computing CFA as: take address from register and add offset to it.

.cfi_def_cfa_register register

.cfi_def_cfa_register modifies a rule for computing CFA. From now on register will be used instead of the old one. Offset remains the same.

.cfi_def_cfa_offset offset

.cfi_def_cfa_offset modifies a rule for computing CFA. Register remains the same, but offset is new. Note that it is the absolute offset that will be added to a defined register to compute CFA address.

.cfi_adjust_cfa_offset offset

Same as .cfi_def_cfa_offset but offset is a relative value that is added/substracted from the previous offset.

.cfi_offset registeroffset

Previous value of register is saved at offset offset from CFA.

.cfi_rel_offset registeroffset

Previous value of register is saved at offset offset from the current CFA register. This is transformed to .cfi_offset using the known displacement of the CFA register from the CFA. This is often easier to use, because the number will match the code it's annotating.

.cfi_window_save

SPARC register window has been saved.

.cfi_escapeexpression[, …]

Allows the user to add arbitrary bytes to the unwind info. One might use this to add OS-specific CFI opcodes, or generic CFI opcodes that GAS does not yet support.

 

posted @ 2012-11-08 09:36  godjesse  阅读(1477)  评论(2编辑  收藏  举报