From 319e1b85d278bad90caeb5b13c41a0f4ca81cb00 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 19 Apr 2026 13:42:26 +0900 Subject: [PATCH 1/7] Use lib->base directly --- src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp | 2 +- src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c | 1 - src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp index 28eb92a285f2e..8ce0046fdb732 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp @@ -334,7 +334,7 @@ bool DwarfParser::process_dwarf(const uintptr_t pc) { uint32_t id = *(reinterpret_cast(_buf)); _buf += 4; if (id != 0) { // FDE - uintptr_t pc_begin = get_decoded_value() + _lib->eh_frame.library_base_addr; + uintptr_t pc_begin = get_decoded_value() + _lib->base; uintptr_t pc_end = pc_begin + get_pc_range(); if ((pc >= pc_begin) && (pc < pc_end)) { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c index 815902045cff8..52d2ad5f404d0 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c @@ -231,7 +231,6 @@ bool read_eh_frame(struct ps_prochandle* ph, lib_info* lib) { for (cnt = 0, sh = shbuf; cnt < ehdr.e_shnum; cnt++, sh++) { if (strcmp(".eh_frame", sh->sh_name + strtab) == 0) { - lib->eh_frame.library_base_addr = lib->base; lib->eh_frame.v_addr = sh->sh_addr; lib->eh_frame.data = read_section_data(lib->fd, &ehdr, sh); lib->eh_frame.size = sh->sh_size; diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h index d5aa74e73ad74..be0b584108b85 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h @@ -36,7 +36,6 @@ // .eh_frame data typedef struct eh_frame_info { - uintptr_t library_base_addr; uintptr_t v_addr; unsigned char* data; int size; From 0682a312f8202592e2ad6bc2210b27f5190c4ce0 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 19 Apr 2026 14:53:10 +0900 Subject: [PATCH 2/7] Move debuginfo related code to salibelf from symtab --- .../linux/native/libsaproc/salibelf.c | 249 +++++++++++++++++ .../linux/native/libsaproc/salibelf.h | 12 + .../linux/native/libsaproc/symtab.c | 260 +----------------- 3 files changed, 268 insertions(+), 253 deletions(-) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c index 6e39b95e7eca5..ee8db71d754b6 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c @@ -29,6 +29,255 @@ extern void print_debug(const char*,...); +// Directory that contains global debuginfo files. In theory it +// should be possible to change this, but in a Java environment there +// is no obvious place to put a user interface to do it. Maybe this +// could be set with an environment variable. +static const char debug_file_directory[] = "/usr/lib/debug"; + +/* The CRC used in gnu_debuglink, retrieved from + http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. */ +unsigned int gnu_debuglink_crc32 (unsigned int crc, + unsigned char *buf, size_t len) +{ + static const unsigned int crc32_table[256] = + { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d + }; + unsigned char *end; + + crc = ~crc & 0xffffffff; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc & 0xffffffff; +} + +/* Open a debuginfo file and check its CRC. If it exists and the CRC + matches return its fd. */ +static int +open_debug_file (const char *pathname, unsigned int crc) +{ + unsigned int file_crc = 0; + unsigned char buffer[8 * 1024]; + + int fd = pathmap_open(pathname); + + if (fd < 0) + return -1; + + lseek(fd, 0, SEEK_SET); + + for (;;) { + int len = read(fd, buffer, sizeof buffer); + if (len <= 0) + break; + file_crc = gnu_debuglink_crc32(file_crc, buffer, len); + } + + if (crc == file_crc) + return fd; + else { + close(fd); + return -1; + } +} + +/* Look for a ".gnu_debuglink" section. If one exists, try to open a + suitable debuginfo file. */ +static int open_debuginfo_from_debug_link(const char *name, + int fd, + ELF_EHDR *ehdr, + struct elf_section *scn_cache) +{ + int debug_fd; + struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr, + scn_cache); + if (debug_link == NULL) + return -1; + char *debug_filename = debug_link->c_data; + int offset = (strlen(debug_filename) + 4) >> 2; + static unsigned int crc; + crc = ((unsigned int*)debug_link->c_data)[offset]; + char *debug_pathname = malloc(strlen(debug_filename) + + strlen(name) + + strlen(".debug/") + + strlen(debug_file_directory) + + 2); + if (debug_pathname == NULL) { + return -1; + } + strcpy(debug_pathname, name); + char *last_slash = strrchr(debug_pathname, '/'); + if (last_slash == NULL) { + free(debug_pathname); + return -1; + } + + /* Look in the same directory as the object. */ + strcpy(last_slash+1, debug_filename); + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + /* Look in a subdirectory named ".debug". */ + strcpy(last_slash+1, ".debug/"); + strcat(last_slash, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + /* Look in /usr/lib/debug + the full pathname. */ + strcpy(debug_pathname, debug_file_directory); + strcat(debug_pathname, name); + last_slash = strrchr(debug_pathname, '/'); + strcpy(last_slash+1, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + free(debug_pathname); + return -1; +} + +static char* build_id_to_debug_filename (size_t size, unsigned char* data) { + char *filename, *s; + + filename = malloc(strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 + + 2 * size + (sizeof ".debug" - 1) + 1); + if (filename == NULL) { + return NULL; + } + s = filename + sprintf (filename, "%s/.build-id/", debug_file_directory); + if (size > 0) { + size--; + s += sprintf (s, "%02x", *data++); + } + if (size > 0) { + *s++ = '/'; + } + while (size-- > 0) { + s += sprintf (s, "%02x", *data++); + } + strcpy (s, ".debug"); + + return filename; +} + +static int open_debuginfo_from_build_id(ELF_SHDR* shbuf, ELF_EHDR* ehdr, struct elf_section* scn_cache) { +#ifdef NT_GNU_BUILD_ID + int cnt = 0; + ELF_SHDR* cursct = NULL; + + // First we look for a Build ID + for (cursct = shbuf, cnt = 0; cnt < ehdr->e_shnum; cnt++) { + if (cursct->sh_type == SHT_NOTE) { + Elf64_Nhdr *note = (Elf64_Nhdr *)scn_cache[cnt].c_data; + if (note->n_type == NT_GNU_BUILD_ID) { + unsigned char *bytes = (unsigned char*)(note+1) + note->n_namesz; + char *filename = build_id_to_debug_filename(note->n_descsz, bytes); + if (filename != NULL) { + int fd = pathmap_open(filename); + free(filename); + return fd; + } + } + } + cursct++; + } +#endif + return -1; +} + +int open_debuginfo(const char* filename, int fd) { + // prepare (load ELF sections) + ELF_EHDR ehdr; + read_elf_header(fd, &ehdr); + ELF_SHDR* shbuf = read_section_header_table(fd, &ehdr); + struct elf_section *scn_cache = (struct elf_section *)calloc(ehdr.e_shnum, sizeof(struct elf_section)); + for (int cnt = 0; cnt < ehdr.e_shnum; cnt++) { + scn_cache[cnt].c_shdr = &shbuf[cnt]; + if (shbuf[cnt].sh_type == SHT_NOTE || shbuf[cnt].sh_type == SHT_STRTAB) { + scn_cache[cnt].c_data = read_section_data(fd, &ehdr, &shbuf[cnt]); + } + } + + // attempt to open debuginfo + int debug_fd = open_debuginfo_from_debug_link(filename, fd, &ehdr, scn_cache); + if (debug_fd == -1) { + // try again with build id. + debug_fd = open_debuginfo_from_build_id(shbuf, &ehdr, scn_cache); + } + + // cleanup + for (int cnt = 0; cnt < ehdr.e_shnum; cnt++) { + if (shbuf[cnt].sh_type == SHT_NOTE) { + free(scn_cache[cnt].c_data); + } + } + free(scn_cache); + free(shbuf); + + return debug_fd; +} + // ELF file parsing helpers. Note that we do *not* use libelf here. int read_elf_header(int fd, ELF_EHDR* ehdr) { if (pread(fd, ehdr, sizeof (ELF_EHDR), 0) != sizeof (ELF_EHDR) || diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h index 59b5039416e85..a675b6f92e304 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h @@ -34,6 +34,13 @@ struct elf_section { void *c_data; }; +#ifdef __cplusplus +extern "C" { +#endif + +// open debuginfo +int open_debuginfo(const char* filename, int fd); + // read ELF file header. int read_elf_header(int fd, ELF_EHDR* ehdr); @@ -60,4 +67,9 @@ struct elf_section *find_section_by_name(char *name, int fd, ELF_EHDR *ehdr, struct elf_section *scn_cache); + +#ifdef __cplusplus +} +#endif + #endif /* _SALIBELF_H_ */ diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c index 8f8ce28be1e78..153ea1e73139d 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c @@ -49,245 +49,20 @@ typedef struct symtab { } symtab_t; -// Directory that contains global debuginfo files. In theory it -// should be possible to change this, but in a Java environment there -// is no obvious place to put a user interface to do it. Maybe this -// could be set with an environment variable. -static const char debug_file_directory[] = "/usr/lib/debug"; - -/* The CRC used in gnu_debuglink, retrieved from - http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. */ -unsigned int gnu_debuglink_crc32 (unsigned int crc, - unsigned char *buf, size_t len) -{ - static const unsigned int crc32_table[256] = - { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, - 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, - 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, - 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, - 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, - 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, - 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, - 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, - 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, - 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, - 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, - 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, - 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, - 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, - 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, - 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, - 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, - 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, - 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, - 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, - 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, - 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, - 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, - 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, - 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, - 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, - 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, - 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, - 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, - 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, - 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, - 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, - 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, - 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, - 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, - 0x2d02ef8d - }; - unsigned char *end; - - crc = ~crc & 0xffffffff; - for (end = buf + len; buf < end; ++buf) - crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); - return ~crc & 0xffffffff; -} - -/* Open a debuginfo file and check its CRC. If it exists and the CRC - matches return its fd. */ -static int -open_debug_file (const char *pathname, unsigned int crc) -{ - unsigned int file_crc = 0; - unsigned char buffer[8 * 1024]; - - int fd = pathmap_open(pathname); - - if (fd < 0) - return -1; - - lseek(fd, 0, SEEK_SET); - - for (;;) { - int len = read(fd, buffer, sizeof buffer); - if (len <= 0) - break; - file_crc = gnu_debuglink_crc32(file_crc, buffer, len); - } - - if (crc == file_crc) - return fd; - else { - close(fd); - return -1; - } -} - -/* Look for a ".gnu_debuglink" section. If one exists, try to open a - suitable debuginfo file. */ -static int open_file_from_debug_link(const char *name, - int fd, - ELF_EHDR *ehdr, - struct elf_section *scn_cache) -{ - int debug_fd; - struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr, - scn_cache); - if (debug_link == NULL) - return -1; - char *debug_filename = debug_link->c_data; - int offset = (strlen(debug_filename) + 4) >> 2; - static unsigned int crc; - crc = ((unsigned int*)debug_link->c_data)[offset]; - char *debug_pathname = malloc(strlen(debug_filename) - + strlen(name) - + strlen(".debug/") - + strlen(debug_file_directory) - + 2); - if (debug_pathname == NULL) { - return -1; - } - strcpy(debug_pathname, name); - char *last_slash = strrchr(debug_pathname, '/'); - if (last_slash == NULL) { - free(debug_pathname); - return -1; - } - - /* Look in the same directory as the object. */ - strcpy(last_slash+1, debug_filename); - debug_fd = open_debug_file(debug_pathname, crc); - if (debug_fd >= 0) { - free(debug_pathname); - return debug_fd; - } - - /* Look in a subdirectory named ".debug". */ - strcpy(last_slash+1, ".debug/"); - strcat(last_slash, debug_filename); - - debug_fd = open_debug_file(debug_pathname, crc); - if (debug_fd >= 0) { - free(debug_pathname); - return debug_fd; - } - - /* Look in /usr/lib/debug + the full pathname. */ - strcpy(debug_pathname, debug_file_directory); - strcat(debug_pathname, name); - last_slash = strrchr(debug_pathname, '/'); - strcpy(last_slash+1, debug_filename); - - debug_fd = open_debug_file(debug_pathname, crc); - if (debug_fd >= 0) { - free(debug_pathname); - return debug_fd; - } - - free(debug_pathname); - return -1; -} - static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo); -/* Look for a ".gnu_debuglink" section. If one exists, try to open a - suitable debuginfo file and read a symbol table from it. */ -static struct symtab *build_symtab_from_debug_link(const char *name, - int fd, - ELF_EHDR *ehdr, - struct elf_section *scn_cache) -{ - fd = open_file_from_debug_link(name, fd, ehdr, scn_cache); - - if (fd >= 0) { - struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); - close(fd); +/* Try to open a suitable debuginfo file and read a symbol table from it. */ +static struct symtab *build_symtab_from_debuginfo(const char* filename, int fd) { + int debug_fd = open_debuginfo(filename, fd); + if (debug_fd >= 0) { + struct symtab *symtab = build_symtab_internal(debug_fd, NULL, /* try_debuginfo */ false); + close(debug_fd); return symtab; } return NULL; } -// Given a build_id, find the associated debuginfo file -static char * -build_id_to_debug_filename (size_t size, unsigned char *data) -{ - char *filename, *s; - - filename = malloc(strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 - + 2 * size + (sizeof ".debug" - 1) + 1); - if (filename == NULL) { - return NULL; - } - s = filename + sprintf (filename, "%s/.build-id/", debug_file_directory); - if (size > 0) - { - size--; - s += sprintf (s, "%02x", *data++); - } - if (size > 0) - *s++ = '/'; - while (size-- > 0) - s += sprintf (s, "%02x", *data++); - strcpy (s, ".debug"); - - return filename; -} - -// Read a build ID note. Try to open any associated debuginfo file -// and return its symtab -static struct symtab* build_symtab_from_build_id(Elf64_Nhdr *note) -{ - int fd; - struct symtab *symtab = NULL; - - unsigned char *bytes - = (unsigned char*)(note+1) + note->n_namesz; - char *filename - = (build_id_to_debug_filename (note->n_descsz, bytes)); - if (filename == NULL) { - return NULL; - } - fd = pathmap_open(filename); - if (fd >= 0) { - symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); - close(fd); - } - free(filename); - - return symtab; -} - // read symbol table from given fd. If try_debuginfo) is true, also // try to open an associated debuginfo file static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo) { @@ -464,28 +239,7 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t // the debuginfo file. We stash a copy of the old symtab in case // there is no debuginfo. struct symtab* prev_symtab = symtab; - symtab = NULL; - -#ifdef NT_GNU_BUILD_ID - // First we look for a Build ID - for (cursct = shbuf, cnt = 0; - symtab == NULL && cnt < ehdr.e_shnum; - cnt++) { - if (cursct->sh_type == SHT_NOTE) { - Elf64_Nhdr *note = (Elf64_Nhdr *)scn_cache[cnt].c_data; - if (note->n_type == NT_GNU_BUILD_ID) { - symtab = build_symtab_from_build_id(note); - } - } - cursct++; - } -#endif - - // Then, if that doesn't work, the debug link - if (symtab == NULL) { - symtab = build_symtab_from_debug_link(filename, fd, &ehdr, - scn_cache); - } + symtab = build_symtab_from_debuginfo(filename, fd); // If we still haven't found a symtab, use the object's own symtab. if (symtab != NULL) { From 662b373f316eeb920dc7b6a0df155a5b7c852ef1 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 19 Apr 2026 14:54:30 +0900 Subject: [PATCH 3/7] Rename "eh_frame_info" to "frame_info" --- src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp | 10 +++++----- src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp | 2 +- .../linux/native/libsaproc/libproc_impl.c | 10 +++++----- .../linux/native/libsaproc/libproc_impl.h | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp index 8ce0046fdb732..85fe67c5d6098 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp @@ -268,14 +268,14 @@ uint32_t DwarfParser::get_decoded_value() { // https://gcc.gnu.org/ml/gcc-help/2010-09/msg00166.html #if defined(_LP64) if (size == 8) { - result += _lib->eh_frame.v_addr + static_cast(_buf - _lib->eh_frame.data); + result += _lib->frame.v_addr + static_cast(_buf - _lib->frame.data); size = 4; } else #endif if ((_encoding & 0x70) == 0x10) { // 0x10 = DW_EH_PE_pcrel - result += _lib->eh_frame.v_addr + static_cast(_buf - _lib->eh_frame.data); + result += _lib->frame.v_addr + static_cast(_buf - _lib->frame.data); } else if (size == 2) { - result = static_cast(result) + _lib->eh_frame.v_addr + static_cast(_buf - _lib->eh_frame.data); + result = static_cast(result) + _lib->frame.v_addr + static_cast(_buf - _lib->frame.data); size = 4; } @@ -322,8 +322,8 @@ unsigned int DwarfParser::get_pc_range() { bool DwarfParser::process_dwarf(const uintptr_t pc) { // https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html - _buf = _lib->eh_frame.data; - unsigned char *end = _lib->eh_frame.data + _lib->eh_frame.size; + _buf = _lib->frame.data; + unsigned char *end = _lib->frame.data + _lib->frame.size; while (_buf <= end) { uint64_t length = get_entry_length(); if (length == 0L) { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp index 2bfdba65a78f7..33b18f91f1d1f 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp @@ -93,7 +93,7 @@ class DwarfParser { } bool is_parseable() { - return _lib->eh_frame.data != NULL; + return _lib->frame.data != NULL; } }; diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c index 52d2ad5f404d0..cc8f956bb0c17 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c @@ -128,7 +128,7 @@ static void destroy_lib_info(struct ps_prochandle* ph) { if (lib->symtab) { destroy_symtab(lib->symtab); } - free(lib->eh_frame.data); + free(lib->frame.data); free(lib); lib = next; } @@ -231,9 +231,9 @@ bool read_eh_frame(struct ps_prochandle* ph, lib_info* lib) { for (cnt = 0, sh = shbuf; cnt < ehdr.e_shnum; cnt++, sh++) { if (strcmp(".eh_frame", sh->sh_name + strtab) == 0) { - lib->eh_frame.v_addr = sh->sh_addr; - lib->eh_frame.data = read_section_data(lib->fd, &ehdr, sh); - lib->eh_frame.size = sh->sh_size; + lib->frame.v_addr = sh->sh_addr; + lib->frame.data = read_section_data(lib->fd, &ehdr, sh); + lib->frame.size = sh->sh_size; break; } } @@ -241,7 +241,7 @@ bool read_eh_frame(struct ps_prochandle* ph, lib_info* lib) { free(strtab); free(shbuf); lseek(lib->fd, current_pos, SEEK_SET); - return lib->eh_frame.data != NULL; + return lib->frame.data != NULL; } lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h index be0b584108b85..44dc902d7c030 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h @@ -34,12 +34,12 @@ #define BUF_SIZE (PATH_MAX + NAME_MAX + 1) -// .eh_frame data -typedef struct eh_frame_info { +// frame data (.eh_frame / .debug_frame) +typedef struct frame_info { uintptr_t v_addr; unsigned char* data; int size; -} eh_frame_info; +} frame_info; // list of shared objects typedef struct lib_info { @@ -48,7 +48,7 @@ typedef struct lib_info { uintptr_t end; uintptr_t exec_start; uintptr_t exec_end; - eh_frame_info eh_frame; + frame_info frame; struct symtab* symtab; int fd; // file descriptor for lib struct lib_info* next; From 0e4477ac9bc95026283c1ad085c1bbb43b399ef0 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 19 Apr 2026 15:07:37 +0900 Subject: [PATCH 4/7] Use .debug_frame if DWARF parser could not find PC from .eh_frame --- .../linux/native/libsaproc/dwarf.cpp | 70 +++++++++++++++---- .../linux/native/libsaproc/dwarf.hpp | 2 +- .../linux/native/libsaproc/libproc_impl.c | 27 +++---- .../linux/native/libsaproc/libproc_impl.h | 9 +++ .../linux/native/libsaproc/ps_proc.c | 5 -- 5 files changed, 82 insertions(+), 31 deletions(-) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp index 85fe67c5d6098..d21eb3c5d881e 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp @@ -23,10 +23,12 @@ * */ +#include #include #include #include "dwarf.hpp" +#include "salibelf.h" #include "libproc_impl.h" DwarfParser::DwarfParser(lib_info *lib) : _lib(lib), @@ -75,7 +77,7 @@ uintptr_t DwarfParser::read_leb(bool sign) { uint64_t DwarfParser::get_entry_length() { uint64_t length = *(reinterpret_cast(_buf)); _buf += 4; - if (length == 0xffffffff) { + if (!_lib->frame.is_debug_frame && length == 0xffffffff) { length = *(reinterpret_cast(_buf)); _buf += 8; } @@ -84,7 +86,11 @@ uint64_t DwarfParser::get_entry_length() { bool DwarfParser::process_cie(unsigned char *start_of_entry, uint32_t id) { unsigned char *orig_pos = _buf; - _buf = start_of_entry - id; + + // CIE pointer means the offset from FDE in .eh_frame. + // In .debug_frame, CIE pointer means the offset from start of .debug_frame . + _buf = _lib->frame.is_debug_frame ? _lib->frame.data + id + : start_of_entry - id; uint64_t length = get_entry_length(); if (length == 0L) { @@ -92,8 +98,8 @@ bool DwarfParser::process_cie(unsigned char *start_of_entry, uint32_t id) { } unsigned char *end = _buf + length; - _buf += 4; // Skip ID (This value of CIE would be always 0) - _buf++; // Skip version (assume to be "1") + _buf += 4; // Skip ID (This value of CIE would be always 0 in .eh_frame / 0xffffffff in .debug_frame) + _buf++; // Skip version char *augmentation_string = reinterpret_cast(_buf); bool has_ehdata = (strcmp("eh", augmentation_string) == 0); @@ -327,15 +333,28 @@ bool DwarfParser::process_dwarf(const uintptr_t pc) { while (_buf <= end) { uint64_t length = get_entry_length(); if (length == 0L) { - return false; + break; // it means "terminator" in .eh_frame, so go through to .debug_frame } unsigned char *next_entry = _buf + length; unsigned char *start_of_entry = _buf; uint32_t id = *(reinterpret_cast(_buf)); _buf += 4; - if (id != 0) { // FDE - uintptr_t pc_begin = get_decoded_value() + _lib->base; - uintptr_t pc_end = pc_begin + get_pc_range(); + // ID for CIE is 0 in .eh_frame, 0xffffffff in .debug_frame + bool is_fde = (_lib->frame.is_debug_frame ? 0xffffffff : 0) != id; + if (is_fde) { + uintptr_t begin_ofs = 0L; + uintptr_t inst_sz = 0L; + if (_lib->frame.is_debug_frame) { + begin_ofs = *(reinterpret_cast(_buf)); + _buf += sizeof(void*); + inst_sz = *(reinterpret_cast(_buf)); + _buf += sizeof(void*); + } else { + begin_ofs = get_decoded_value(); + inst_sz = get_pc_range(); + } + uintptr_t pc_begin = begin_ofs + _lib->base; + uintptr_t pc_end = pc_begin + inst_sz; if ((pc >= pc_begin) && (pc < pc_end)) { // Process CIE @@ -343,9 +362,11 @@ bool DwarfParser::process_dwarf(const uintptr_t pc) { return false; } - // Skip Augumenation - uintptr_t augmentation_length = read_leb(false); - _buf += augmentation_length; // skip + // Skip Augumenation if .eh_frame + if (!_lib->frame.is_debug_frame) { + uintptr_t augmentation_length = read_leb(false); + _buf += augmentation_length; // skip + } // Process FDE parse_dwarf_instructions(pc_begin, pc, next_entry); @@ -356,5 +377,30 @@ bool DwarfParser::process_dwarf(const uintptr_t pc) { _buf = next_entry; } - return false; + bool result = false; + // try again with .debug_frame section if it hasn't been tried yet. + if (!_lib->frame.tried_debug_frame && _lib->fd != -1) { + // attempts to load .debug_frame from executables. + frame_info frame = {}; + if (!read_frame(".debug_frame", _lib->fd, &frame)) { + // attempts again to load .debug_frame from debuginfo if it could not be loaded from executables. + int debug_fd = open_debuginfo(_lib->name, _lib->fd); + if (debug_fd != -1 && read_frame(".debug_frame", debug_fd, &frame)) { + close(debug_fd); + } + } + frame.tried_debug_frame = true; + _lib->frame.tried_debug_frame = true; + + // try process_dwarf() again with .debug_frame. + if (frame.data != NULL) { + if (_lib->frame.data != NULL) { + free(_lib->frame.data); + } + memcpy(&_lib->frame, &frame, sizeof(frame_info)); + result = process_dwarf(pc); + } + } + + return result; } diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp index 33b18f91f1d1f..130efe37aaeb7 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp @@ -61,7 +61,7 @@ struct DwarfState { */ class DwarfParser { private: - const lib_info *_lib; + lib_info *_lib; unsigned char *_buf; unsigned char _encoding; unsigned int _code_factor; diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c index cc8f956bb0c17..d6542c2219f23 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c @@ -214,7 +214,7 @@ static bool fill_addr_info(lib_info* lib) { return (lib->end != -1L) && (lib->exec_start != -1L) && (lib->exec_end != -1L); } -bool read_eh_frame(struct ps_prochandle* ph, lib_info* lib) { +bool read_frame(const char* section, int fd, frame_info* frame) { off_t current_pos = -1; ELF_EHDR ehdr; ELF_SHDR* shbuf = NULL; @@ -222,26 +222,27 @@ bool read_eh_frame(struct ps_prochandle* ph, lib_info* lib) { char* strtab = NULL; int cnt; - current_pos = lseek(lib->fd, (off_t)0L, SEEK_CUR); - lseek(lib->fd, (off_t)0L, SEEK_SET); + current_pos = lseek(fd, (off_t)0L, SEEK_CUR); + lseek(fd, (off_t)0L, SEEK_SET); - read_elf_header(lib->fd, &ehdr); - shbuf = read_section_header_table(lib->fd, &ehdr); - strtab = read_section_data(lib->fd, &ehdr, &shbuf[ehdr.e_shstrndx]); + read_elf_header(fd, &ehdr); + shbuf = read_section_header_table(fd, &ehdr); + strtab = read_section_data(fd, &ehdr, &shbuf[ehdr.e_shstrndx]); for (cnt = 0, sh = shbuf; cnt < ehdr.e_shnum; cnt++, sh++) { - if (strcmp(".eh_frame", sh->sh_name + strtab) == 0) { - lib->frame.v_addr = sh->sh_addr; - lib->frame.data = read_section_data(lib->fd, &ehdr, sh); - lib->frame.size = sh->sh_size; + if (strcmp(section, sh->sh_name + strtab) == 0) { + frame->v_addr = sh->sh_addr; + frame->data = read_section_data(fd, &ehdr, sh); + frame->size = sh->sh_size; + frame->is_debug_frame = strcmp(section, ".debug_frame") == 0; break; } } free(strtab); free(shbuf); - lseek(lib->fd, current_pos, SEEK_SET); - return lib->frame.data != NULL; + lseek(fd, current_pos, SEEK_SET); + return frame->data != NULL; } lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { @@ -285,7 +286,7 @@ lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, } if (fill_addr_info(newlib)) { - if (!read_eh_frame(ph, newlib)) { + if (!read_frame(".eh_frame", newlib->fd, &newlib->frame)) { print_debug("Could not find .eh_frame section in %s\n", newlib->name); } } else { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h index 44dc902d7c030..0e7feaf0b23bc 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h @@ -39,6 +39,12 @@ typedef struct frame_info { uintptr_t v_addr; unsigned char* data; int size; + + // Following fields should be declared as int instead of bool + // because "bool" would be defined as int in C in libproc.h. + // It causes unexpected memory access. + int is_debug_frame; // true if this info comes from .debug_frame + int tried_debug_frame; // true if .debug_frame was tried to load. } frame_info; // list of shared objects @@ -130,6 +136,9 @@ void print_debug(const char* format,...); void print_error(const char* format,...); bool is_debug(); +// read frame information for unwinding from specified ELF section. +bool read_frame(const char* section, int fd, frame_info* frame); + // deletes a thread from the thread list void delete_thread_info(struct ps_prochandle* ph, thread_info* thr); diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c index 9cbde7319f016..530d1abd1822c 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c @@ -408,11 +408,6 @@ static bool read_lib_info(struct ps_prochandle* ph) { #endif if ((lib = add_lib_info(ph, word[5], (uintptr_t)base)) == NULL) continue; // ignore, add_lib_info prints error - - // we don't need to keep the library open, symtab is already - // built. Only for core dump we need to keep the fd open. - close(lib->fd); - lib->fd = -1; } } fclose(fp); From ec4a08d3d4457c1bb70bb1a73e9978fd018eab1a Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 19 Apr 2026 15:10:06 +0900 Subject: [PATCH 5/7] Validate sender SP before to return sender frame in LinuxAMD64CFrame.java --- .../jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index e58e2facdd7c9..35af269196710 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -79,6 +79,11 @@ private Address getSenderCFA(DwarfParser senderDwarf, Address senderSP, Address }; } + // In SysV AMD64, the stack must be consumed because return address would be stored on the stack. + protected boolean isValidFrame(Address senderCFA, Address senderFP, Address senderSP) { + return super.isValidFrame(senderCFA, senderFP) && sp().lessThan(senderSP); + } + @Override public CFrame sender(ThreadProxy th, Address senderSP, Address senderFP, Address senderPC) { if (linuxDbg().isSignalTrampoline(pc())) { @@ -118,7 +123,7 @@ public CFrame sender(ThreadProxy th, Address senderSP, Address senderFP, Address try { Address senderCFA = getSenderCFA(senderDwarf, senderSP, senderFP); - return isValidFrame(senderCFA, senderFP) + return isValidFrame(senderCFA, senderFP, senderSP) ? new LinuxAMD64CFrame(linuxDbg(), senderSP, senderFP, senderCFA, senderPC, senderDwarf, fallback) : null; } catch (DebuggerException e) { From de27835d7ae58bc7547f25fefe1613af47757c82 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 19 Apr 2026 15:13:01 +0900 Subject: [PATCH 6/7] Re-enable mixed jstack tests on musl C --- test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java | 4 ---- .../jtreg/serviceability/sa/TestJhsdbJstackMixed.java | 6 ------ .../jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java | 5 ----- .../serviceability/sa/TestJhsdbJstackMixedWithXComp.java | 7 ------- .../serviceability/sa/TestJhsdbJstackPrintVMLocks.java | 6 ------ 5 files changed, 28 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java index 6921a7ec0ca34..51738be355462 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java @@ -54,10 +54,6 @@ public class ClhsdbPstack { public static void main(String[] args) throws Exception { - if (Platform.isMusl()) { - throw new SkippedException("This test does not work on musl libc."); - } - boolean withCore = Boolean.parseBoolean(args[0]); System.out.println("Starting ClhsdbPstack test: withCore==" + withCore); diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java index a5750edf360fc..e3808aa670628 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java @@ -33,8 +33,6 @@ import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; - /** * @test * @key randomness @@ -176,10 +174,6 @@ private static void runJstackMixedInLoop(LingeredApp app) throws Exception { } public static void main(String... args) throws Exception { - if (Platform.isMusl()) { - throw new SkippedException("This test does not work on musl libc."); - } - SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. LingeredApp app = null; diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java index 99232ed981315..55107727b2bb6 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedCore.java @@ -26,7 +26,6 @@ import jdk.test.lib.JDKToolFinder; import jdk.test.lib.JDKToolLauncher; -import jdk.test.lib.Platform; import jdk.test.lib.SA.SATestUtils; import jdk.test.lib.Utils; import jdk.test.lib.apps.LingeredApp; @@ -72,10 +71,6 @@ private static void runJstackMixed(String coreFileName) throws Exception { } public static void main(String... args) throws Throwable { - if (Platform.isMusl()) { - throw new SkippedException("This test does not work on musl libc."); - } - // Check whether the symbol of signal trampoline is available. var libc = SATestUtils.getLibCPath(); diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java index 70a9e67e40601..b264258701dd4 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java @@ -27,14 +27,11 @@ import java.util.List; import jdk.test.lib.JDKToolLauncher; -import jdk.test.lib.Platform; import jdk.test.lib.SA.SATestUtils; import jdk.test.lib.Utils; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; - /** * @test id=xcomp * @bug 8370176 @@ -114,10 +111,6 @@ private static void runJstack(LingeredApp app) throws Exception { } public static void main(String... args) throws Exception { - if (Platform.isMusl()) { - throw new SkippedException("This test does not work on musl libc."); - } - SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. LingeredApp app = null; diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java index e0774917f8076..c0a6f4faf5415 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java @@ -22,11 +22,9 @@ */ import jdk.test.lib.JDKToolLauncher; -import jdk.test.lib.Platform; import jdk.test.lib.SA.SATestUtils; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; /** * @test @@ -44,10 +42,6 @@ public class TestJhsdbJstackPrintVMLocks { final static int MAX_ATTEMPTS = 5; public static void main(String[] args) throws Exception { - if (Platform.isMusl()) { - throw new SkippedException("This test does not work on musl libc."); - } - SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. LingeredApp theApp = null; From 2dc4f1dfa101f511a0305ede04aed027eb87c1f0 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 19 Apr 2026 17:12:54 +0900 Subject: [PATCH 7/7] Update copyright year --- src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c | 2 +- src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c index ee8db71d754b6..a63e95e439dd9 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h index a675b6f92e304..d82bf794af262 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it