8377947: Test serviceability/sa/TestJhsdbJstackMixedCore.java failed on linux-x64

Reviewed-by: cjplummer, kevinw
This commit is contained in:
Yasumasa Suenaga 2026-02-25 23:02:07 +00:00
parent 8ba3de9834
commit 32cc7f1f57
3 changed files with 64 additions and 58 deletions

View File

@ -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<DwarfParser *>(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<DwarfParser *>(get_dwarf_context(env, this_obj));
return parser->get_bp_cfa_offset();
return parser->get_offset_from_cfa(RBP);
}

View File

@ -24,10 +24,32 @@
*/
#include <cstring>
#include <stack>
#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<enum DWARF_Register>(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<int>(read_leb(true));
_return_address_reg = static_cast<enum DWARF_Register>(*_buf++);
enum DWARF_Register initial_ra = static_cast<enum DWARF_Register>(*_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<uintptr_t>(-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<struct DwarfState> 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<enum DWARF_Register>(read_leb(false));
_cfa_offset = read_leb(false);
_state.cfa_reg = static_cast<enum DWARF_Register>(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<enum DWARF_Register>(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<enum DWARF_Register>(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<enum DWARF_Register>(read_leb(false));
case 0x0d: // DW_CFA_def_cfa_register
_state.cfa_reg = static_cast<enum DWARF_Register>(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<enum DWARF_Register>(opa);
_state.offset_from_cfa[reg] = _initial_state.offset_from_cfa[reg];
break;
}
default:
print_debug("DWARF: Unknown opcode: 0x%x\n", op);
return;

View File

@ -26,6 +26,8 @@
#ifndef _DWARF_HPP_
#define _DWARF_HPP_
#include <map>
#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<enum DWARF_Register, int> 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);