Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i#7046: Add register values to the output of X64 Linux dr_create_memory_dump(). #7088

Merged
merged 16 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion api/docs/release.dox
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ changes:

Further non-compatibility-affecting changes include:
- Added X64 Linux support to dr_create_memory_dump(). This API has the same
restriction as dr_suspend_all_other_threads_ex().
restriction as dr_suspend_all_other_threads_ex(). For X86_64 platform, the feature is
supported only when fast FP save and restore is supported. And mixed mode is not
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved
supported.
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved

**************************************************
<hr>
Expand Down
2 changes: 1 addition & 1 deletion core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ if (UNIX)
set(OS_SRCS ${OS_SRCS} unix/loader_android.c)
else ()
set(OS_SRCS ${OS_SRCS} unix/loader_linux.c)
if (X64)
if (AARCH64 OR (X86 AND X64))
set(OS_SRCS ${OS_SRCS} unix/coredump.c)
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved
endif ()
endif ()
Expand Down
11 changes: 8 additions & 3 deletions core/lib/instrument.c
Original file line number Diff line number Diff line change
Expand Up @@ -2498,9 +2498,14 @@ dr_create_memory_dump(dr_memory_dump_spec_t *spec)
#ifdef WINDOWS
if (TEST(DR_MEMORY_DUMP_LDMP, spec->flags))
return os_dump_core_live(spec->label, spec->ldmp_path, spec->ldmp_path_size);
#elif defined(LINUX) && defined(X64)
if (TEST(DR_MEMORY_DUMP_ELF, spec->flags))
return os_dump_core_live();
#elif defined(LINUX) && ((defined(X64) && defined(X86)) || defined(AARCH64))
if (TEST(DR_MEMORY_DUMP_ELF, spec->flags)) {
priv_mcontext_t mc;
dcontext_t *dcontext = get_thread_private_dcontext();
if (!dr_get_mcontext_priv(dcontext, NULL, &mc))
return false;
return os_dump_core_live(dcontext, &mc);
}
#endif
return false;
}
Expand Down
68 changes: 39 additions & 29 deletions core/unix/coredump.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,38 @@
#include "../os_shared.h"
#include "../synch.h"
#include "../utils.h"
#include "../ir/decode.h"
#include "../lib/dr_ir_utils.h"
#include "../lib/globals_api.h"
#include "../lib/globals_shared.h"
#include "../lib/instrument.h"

#include "dr_tools.h"
#include "elf_defines.h"
#include "memquery.h"

/* Only X64 is supported. */
#ifndef X64
# error Unsupported architecture
#endif

#define MAX_SECTION_HEADERS 300
#define MAX_SECTION_NAME_BUFFER_SIZE 8192
#define SECTION_HEADER_TABLE ".shstrtab"
#define VVAR_SECTION "[vvar]"
#define VSYSCALL_SECTION "[vsyscall]"
// The name of the note owner including the terminating null character needs to
// be 4 byte aligned.
/*
* The length of the name has to be a multiple of eight (for X64) to ensure the next
* field (descriptor) is 8-byte aligned. Null characters are added at the end as
* padding to increase the length to eight. The name CORE is used following the example
* of core dump files.
*/
#define NOTE_OWNER "CORE\0\0\0\0"
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved
#define NOTE_OWNER_LENGTH 8
// Two notes, NT_PRSTATUS (prstatus structure) and NT_FPREGSET (floating point registers),
// are written to the output file.
/*
* Two notes, NT_PRSTATUS (prstatus structure) and NT_FPREGSET (floating point registers),
* are written to the output file.
*/
#define PROGRAM_HEADER_NOTE_LENGTH \
(sizeof(ELF_NOTE_HEADER_TYPE) + NOTE_OWNER_LENGTH + sizeof(struct elf_prstatus) + \
sizeof(ELF_NOTE_HEADER_TYPE) + NOTE_OWNER_LENGTH + sizeof(elf_fpregset_t))
Expand Down Expand Up @@ -198,7 +211,7 @@ write_section_header(DR_PARAM_IN file_t elf_file,
* Copy dr_mcontext_t register values to user_regs_struct.
*/
static void
mcontext_to_user_regs(DR_PARAM_IN dr_mcontext_t *mcontext,
mcontext_to_user_regs(DR_PARAM_IN priv_mcontext_t *mcontext,
DR_PARAM_OUT struct user_regs_struct *regs)
{
#ifdef DR_HOST_NOT_TARGET
Expand Down Expand Up @@ -256,6 +269,8 @@ mcontext_to_user_regs(DR_PARAM_IN dr_mcontext_t *mcontext,
regs->regs[30] = mcontext->r30;
regs->sp = mcontext->sp;
regs->pc = (uint64_t)mcontext->pc;
#else
# error Unsupported architecture
#endif
}

Expand All @@ -264,17 +279,11 @@ mcontext_to_user_regs(DR_PARAM_IN dr_mcontext_t *mcontext,
* the file, false otherwise.
*/
static bool
write_prstatus_note(DR_PARAM_IN file_t elf_file)
write_prstatus_note(DR_PARAM_IN priv_mcontext_t *mc, DR_PARAM_IN file_t elf_file)
{
void *drcontext = dr_get_current_drcontext();
dr_mcontext_t mcontext;
mcontext.size = sizeof(mcontext);
mcontext.flags = DR_MC_ALL;
dr_get_mcontext(drcontext, &mcontext);

struct elf_prstatus prstatus;
struct user_regs_struct *regs = (struct user_regs_struct *)&prstatus.pr_reg;
mcontext_to_user_regs(&mcontext, regs);
mcontext_to_user_regs(mc, regs);

ELF_NOTE_HEADER_TYPE nhdr;
// Add one to include the terminating null character.
Expand All @@ -295,14 +304,20 @@ write_prstatus_note(DR_PARAM_IN file_t elf_file)
* X86, copy the floating point registers from the output of fxsave64.
*/
static bool
get_floating_point_registers(DR_PARAM_IN dr_mcontext_t *mc,
get_floating_point_registers(DR_PARAM_IN dcontext_t *dcontext,
DR_PARAM_IN priv_mcontext_t *mc,
DR_PARAM_OUT elf_fpregset_t *regs)
{
#ifdef DR_HOST_NOT_TARGET
return false;
#elif defined(X86)
// Fast FP save and restore support is required.
ASSERT(proc_has_feature(FEATURE_FXSR));
// Mixed mode is not supported.
ASSERT(X64_MODE_DC(dcontext));
byte fpstate_buf[MAX_FP_STATE_SIZE];
fxsave64_map_t *fpstate = (fxsave64_map_t *)ALIGN_FORWARD(fpstate_buf, 16);
fxsave64_map_t *fpstate =
(fxsave64_map_t *)ALIGN_FORWARD(fpstate_buf, DR_FPSTATE_ALIGN);
if (proc_save_fpstate((byte *)fpstate) != DR_FPSTATE_BUF_SIZE) {
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved
return false;
}
Expand Down Expand Up @@ -339,16 +354,11 @@ get_floating_point_registers(DR_PARAM_IN dr_mcontext_t *mc,
* the file, false otherwise.
*/
static bool
write_fpregset_note(DR_PARAM_IN file_t elf_file)
write_fpregset_note(DR_PARAM_IN dcontext_t *dcontext, DR_PARAM_IN priv_mcontext_t *mc,
DR_PARAM_IN file_t elf_file)
{
void *drcontext = dr_get_current_drcontext();
dr_mcontext_t mcontext;
mcontext.size = sizeof(mcontext);
mcontext.flags = DR_MC_ALL;
dr_get_mcontext(drcontext, &mcontext);

elf_fpregset_t fpregset;
if (!get_floating_point_registers(&mcontext, &fpregset)) {
if (!get_floating_point_registers(dcontext, mc, &fpregset)) {
return false;
}

Expand All @@ -371,7 +381,7 @@ write_fpregset_note(DR_PARAM_IN file_t elf_file)
* false otherwise.
*/
static bool
os_dump_core_internal(void)
os_dump_core_internal(dcontext_t *dcontext, priv_mcontext_t *mc)
{
// Insert a null string at the beginning for sections with no comment.
char string_table[MAX_SECTION_NAME_BUFFER_SIZE];
Expand Down Expand Up @@ -475,7 +485,6 @@ os_dump_core_internal(void)
os_close(elf_file);
return false;
}
// TODO i#7046: Fill the program header with valid data.
if (!write_program_header(elf_file, PT_NOTE, /*flags=*/0,
/*offset=*/sizeof(ELF_HEADER_TYPE) +
sizeof(ELF_PROGRAM_HEADER_TYPE),
Expand All @@ -486,11 +495,11 @@ os_dump_core_internal(void)
os_close(elf_file);
return false;
}
if (!write_prstatus_note(elf_file)) {
if (!write_prstatus_note(mc, elf_file)) {
os_close(elf_file);
return false;
}
if (!write_fpregset_note(elf_file)) {
if (!write_fpregset_note(dcontext, mc, elf_file)) {
os_close(elf_file);
return false;
}
Expand Down Expand Up @@ -564,7 +573,7 @@ os_dump_core_internal(void)
* Returns true if a core dump file is written, false otherwise.
*/
bool
os_dump_core_live(void)
os_dump_core_live(dcontext_t *dcontext, priv_mcontext_t *mc)
{
#ifdef DR_HOST_NOT_TARGET
// Memory dump is supported only when the host and the target are the same.
Expand All @@ -584,7 +593,8 @@ os_dump_core_live(void)
return false;
}

const bool ret = os_dump_core_internal();
// TODO i#7046: Add support to save register values for all threads.
const bool ret = os_dump_core_internal(dcontext, mc);

end_synch_with_all_threads(threads, num_threads,
/*resume=*/true);
Expand Down
4 changes: 3 additions & 1 deletion core/unix/os_exports.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,10 @@ ushort
os_get_app_tls_reg_offset(reg_id_t seg);
void *
os_get_app_tls_base(dcontext_t *dcontext, reg_id_t seg);
#if defined(AARCH64) || (defined(X64) && defined(X86))
bool
os_dump_core_live(void);
os_dump_core_live(dcontext_t *dcontext, priv_mcontext_t *mc);
ivankyluk marked this conversation as resolved.
Show resolved Hide resolved
#endif

#if defined(AARCHXX) || defined(RISCV64)
bool
Expand Down
Loading