diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/DwarfParser.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/DwarfParser.cpp index 6c94992e1e2..62dbc84f88c 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/DwarfParser.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/DwarfParser.cpp @@ -205,7 +205,7 @@ extern "C" JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getReturnAddressOffsetFromCFA (JNIEnv *env, jobject this_obj) { DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); - return parser->get_ra_cfa_offset(); + return parser->get_offset_from_cfa(RA); } /* @@ -217,5 +217,5 @@ extern "C" JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getBasePointerOffsetFromCFA (JNIEnv *env, jobject this_obj) { DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); - return parser->get_bp_cfa_offset(); + return parser->get_offset_from_cfa(RBP); } diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp index 2636bdf691a..459e3cc57e9 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp @@ -24,10 +24,32 @@ */ #include +#include #include "dwarf.hpp" #include "libproc_impl.h" +DwarfParser::DwarfParser(lib_info *lib) : _lib(lib), + _buf(NULL), + _encoding(0), + _code_factor(0), + _data_factor(0), + _current_pc(0L) { + init_state(_initial_state); + init_state(_state); +} + +void DwarfParser::init_state(struct DwarfState& st) { + st.cfa_reg = MAX_VALUE; + st.return_address_reg = MAX_VALUE; + st.cfa_offset = 0; + + st.offset_from_cfa.clear(); + for (int reg = 0; reg < MAX_VALUE; reg++) { + st.offset_from_cfa[static_cast(reg)] = INT_MAX; + } +} + /* from read_leb128() in dwarf.c in binutils */ uintptr_t DwarfParser::read_leb(bool sign) { uintptr_t result = 0L; @@ -82,7 +104,7 @@ bool DwarfParser::process_cie(unsigned char *start_of_entry, uint32_t id) { _code_factor = read_leb(false); _data_factor = static_cast(read_leb(true)); - _return_address_reg = static_cast(*_buf++); + enum DWARF_Register initial_ra = static_cast(*_buf++); if (strpbrk(augmentation_string, "LP") != NULL) { // Language personality routine (P) and Language Specific Data Area (LSDA:L) @@ -99,14 +121,12 @@ bool DwarfParser::process_cie(unsigned char *start_of_entry, uint32_t id) { // Clear state _current_pc = 0L; - _cfa_reg = MAX_VALUE; - _return_address_reg = RA; - _cfa_offset = 0; - _ra_cfa_offset = 8; - _bp_cfa_offset = INT_MAX; + init_state(_state); + _state.return_address_reg = initial_ra; parse_dwarf_instructions(0L, static_cast(-1L), end); + _initial_state = _state; _buf = orig_pos; return true; } @@ -114,12 +134,7 @@ bool DwarfParser::process_cie(unsigned char *start_of_entry, uint32_t id) { void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const unsigned char *end) { uintptr_t operand1; _current_pc = begin; - - /* for remember state */ - enum DWARF_Register rem_cfa_reg = MAX_VALUE; - int rem_cfa_offset = 0; - int rem_ra_cfa_offset = 8; - int rem_bp_cfa_offset = INT_MAX; + std::stack remember_state; while ((_buf < end) && (_current_pc < pc)) { unsigned char op = *_buf++; @@ -138,21 +153,17 @@ void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const } break; case 0x0c: // DW_CFA_def_cfa - _cfa_reg = static_cast(read_leb(false)); - _cfa_offset = read_leb(false); + _state.cfa_reg = static_cast(read_leb(false)); + _state.cfa_offset = read_leb(false); break; case 0x80: {// DW_CFA_offset operand1 = read_leb(false); enum DWARF_Register reg = static_cast(opa); - if (reg == RBP) { - _bp_cfa_offset = operand1 * _data_factor; - } else if (reg == RA) { - _ra_cfa_offset = operand1 * _data_factor; - } + _state.offset_from_cfa[reg] = operand1 * _data_factor; break; } case 0xe: // DW_CFA_def_cfa_offset - _cfa_offset = read_leb(false); + _state.cfa_offset = read_leb(false); break; case 0x40: // DW_CFA_advance_loc if (_current_pc != 0L) { @@ -184,28 +195,28 @@ void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const } case 0x07: { // DW_CFA_undefined enum DWARF_Register reg = static_cast(read_leb(false)); - // We are only interested in BP here because CFA and RA should not be undefined. - if (reg == RBP) { - _bp_cfa_offset = INT_MAX; - } + _state.offset_from_cfa[reg] = INT_MAX; break; } - case 0x0d: {// DW_CFA_def_cfa_register - _cfa_reg = static_cast(read_leb(false)); + case 0x0d: // DW_CFA_def_cfa_register + _state.cfa_reg = static_cast(read_leb(false)); break; - } case 0x0a: // DW_CFA_remember_state - rem_cfa_reg = _cfa_reg; - rem_cfa_offset = _cfa_offset; - rem_ra_cfa_offset = _ra_cfa_offset; - rem_bp_cfa_offset = _bp_cfa_offset; + remember_state.push(_state); break; case 0x0b: // DW_CFA_restore_state - _cfa_reg = rem_cfa_reg; - _cfa_offset = rem_cfa_offset; - _ra_cfa_offset = rem_ra_cfa_offset; - _bp_cfa_offset = rem_bp_cfa_offset; + if (remember_state.empty()) { + print_debug("DWARF Error: DW_CFA_restore_state with empty stack.\n"); + return; + } + _state = remember_state.top(); + remember_state.pop(); break; + case 0xc0: {// DW_CFA_restore + enum DWARF_Register reg = static_cast(opa); + _state.offset_from_cfa[reg] = _initial_state.offset_from_cfa[reg]; + break; + } default: print_debug("DWARF: Unknown opcode: 0x%x\n", op); return; diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp index a2692738ce1..0a38c9a0f2e 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp @@ -26,6 +26,8 @@ #ifndef _DWARF_HPP_ #define _DWARF_HPP_ +#include + #include "libproc_impl.h" /* @@ -55,6 +57,13 @@ enum DWARF_Register { MAX_VALUE }; +struct DwarfState { + enum DWARF_Register cfa_reg; + enum DWARF_Register return_address_reg; + int cfa_offset; + std::map offset_from_cfa; +}; + /* * DwarfParser finds out CFA (Canonical Frame Address) from DWARF in ELF binary. * Also Return Address (RA) and Base Pointer (BP) are calculated from CFA. @@ -64,16 +73,14 @@ class DwarfParser { const lib_info *_lib; unsigned char *_buf; unsigned char _encoding; - enum DWARF_Register _cfa_reg; - enum DWARF_Register _return_address_reg; unsigned int _code_factor; int _data_factor; uintptr_t _current_pc; - int _cfa_offset; - int _ra_cfa_offset; - int _bp_cfa_offset; + struct DwarfState _initial_state; + struct DwarfState _state; + void init_state(struct DwarfState& st); uintptr_t read_leb(bool sign); uint64_t get_entry_length(); bool process_cie(unsigned char *start_of_entry, uint32_t id); @@ -82,24 +89,12 @@ class DwarfParser { unsigned int get_pc_range(); public: - DwarfParser(lib_info *lib) : _lib(lib), - _buf(NULL), - _encoding(0), - _cfa_reg(MAX_VALUE), - _return_address_reg(RA), - _code_factor(0), - _data_factor(0), - _current_pc(0L), - _cfa_offset(0), - _ra_cfa_offset(8), - _bp_cfa_offset(INT_MAX) {}; - + DwarfParser(lib_info *lib); ~DwarfParser() {} bool process_dwarf(const uintptr_t pc); - enum DWARF_Register get_cfa_register() { return _cfa_reg; } - int get_cfa_offset() { return _cfa_offset; } - int get_ra_cfa_offset() { return _ra_cfa_offset; } - int get_bp_cfa_offset() { return _bp_cfa_offset; } + enum DWARF_Register get_cfa_register() { return _state.cfa_reg; } + int get_cfa_offset() { return _state.cfa_offset; } + int get_offset_from_cfa(enum DWARF_Register reg) { return _state.offset_from_cfa[reg]; } bool is_in(long pc) { return (_lib->exec_start <= pc) && (pc < _lib->exec_end);