From 6d486afe3ed945ca46a4d3ff9c65baff7fa81533 Mon Sep 17 00:00:00 2001 From: Djordje Todorovic Date: Sat, 9 Mar 2019 13:51:16 +0100 Subject: [PATCH] [MIPS] Backport from master branch for reading PID from a core This includes: -BFD: Write Linux core PRSTATUS note into MIPS core file -BFD: Extract PID from MIPS core dump file -Add test for fetching TLS from core file On MIPS o32, n32 and n64 platforms information such as PID was not correctly written into core file from GDB. In addition, on MIPS o32, n32 and n64 platforms, PID information was not correctly propagated from core dump file to internal GDB structures. This patch fixes that behavior. A correct PID is needed by `libthread_db' library supplied with glibc repository revisions before commit c579f48edba8 ("Remove cached PID/TID in clone") or released versions before 2.25 for GDB to fetch value of TLS variable from core file. Those patches are develped by myself and accepted by community. --- bfd/elf32-mips.c | 46 +++++++++++++++++++++ bfd/elf64-mips.c | 46 +++++++++++++++++++++ bfd/elfn32-mips.c | 46 +++++++++++++++++++++ bfd/elfxx-mips.h | 1 + gdb/testsuite/gdb.threads/tls-core.c | 37 +++++++++++++++++ gdb/testsuite/gdb.threads/tls-core.exp | 56 ++++++++++++++++++++++++++ 6 files changed, 232 insertions(+) create mode 100644 gdb/testsuite/gdb.threads/tls-core.c create mode 100644 gdb/testsuite/gdb.threads/tls-core.exp diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 029de279..f91c9ae1 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -2353,6 +2353,8 @@ elf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return FALSE; case 128: /* Linux/MIPS elf_prpsinfo */ + elf_tdata (abfd)->core->pid + = bfd_get_32 (abfd, note->descdata + 16); elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); elf_tdata (abfd)->core->command @@ -2373,6 +2375,45 @@ elf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return TRUE; } + +/* Write Linux core PRSTATUS note into core file. */ + +static char * +elf32_mips_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, + ...) +{ + switch (note_type) + { + default: + return NULL; + + case NT_PRPSINFO: + BFD_FAIL (); + return NULL; + + case NT_PRSTATUS: + { + char data[256]; + va_list ap; + long pid; + int cursig; + const void *greg; + + va_start (ap, note_type); + memset (data, 0, 72); + pid = va_arg (ap, long); + bfd_put_32 (abfd, pid, data + 24); + cursig = va_arg (ap, int); + bfd_put_16 (abfd, cursig, data + 12); + greg = va_arg (ap, const void *); + memcpy (data + 72, greg, 180); + memset (data + 252, 0, 4); + va_end (ap); + return elfcore_write_note (abfd, buf, bufsiz, + "CORE", note_type, data, sizeof (data)); + } + } +} /* Depending on the target vector we generate some version of Irix executables or "normal" MIPS ELF ABI executables. */ @@ -2554,6 +2595,9 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { #define ELF_COMMONPAGESIZE 0x1000 #define elf32_bed elf32_tradbed +#undef elf_backend_write_core_note +#define elf_backend_write_core_note elf32_mips_write_core_note + /* Include the target file again for this target. */ #include "elf32-target.h" @@ -2575,6 +2619,8 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { #undef elf32_bed #define elf32_bed elf32_fbsd_tradbed +#undef elf_backend_write_core_note + #include "elf32-target.h" /* Implement elf_backend_final_write_processing for VxWorks. */ diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c index f04c4b5a..052bdc41 100644 --- a/bfd/elf64-mips.c +++ b/bfd/elf64-mips.c @@ -4308,6 +4308,8 @@ elf64_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return FALSE; case 136: /* Linux/MIPS - N64 kernel elf_prpsinfo */ + elf_tdata (abfd)->core->pid + = bfd_get_32 (abfd, note->descdata + 24); elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); elf_tdata (abfd)->core->command @@ -4328,6 +4330,45 @@ elf64_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return TRUE; } + +/* Write Linux core PRSTATUS note into core file. */ + +static char * +elf64_mips_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, + ...) +{ + switch (note_type) + { + default: + return NULL; + + case NT_PRPSINFO: + BFD_FAIL (); + return NULL; + + case NT_PRSTATUS: + { + char data[480]; + va_list ap; + long pid; + int cursig; + const void *greg; + + va_start (ap, note_type); + memset (data, 0, 112); + pid = va_arg (ap, long); + bfd_put_32 (abfd, pid, data + 32); + cursig = va_arg (ap, int); + bfd_put_16 (abfd, cursig, data + 12); + greg = va_arg (ap, const void *); + memcpy (data + 112, greg, 360); + memset (data + 472, 0, 8); + va_end (ap); + return elfcore_write_note (abfd, buf, bufsiz, + "CORE", note_type, data, sizeof (data)); + } + } +} /* ECOFF swapping routines. These are used when dealing with the .mdebug section, which is in the ECOFF debugging format. */ @@ -4538,6 +4579,9 @@ const struct elf_size_info mips_elf64_size_info = #define ELF_COMMONPAGESIZE 0x1000 #define elf64_bed elf64_tradbed +#undef elf_backend_write_core_note +#define elf_backend_write_core_note elf64_mips_write_core_note + /* Include the target file again for this target. */ #include "elf64-target.h" @@ -4560,4 +4604,6 @@ const struct elf_size_info mips_elf64_size_info = #undef elf64_bed #define elf64_bed elf64_fbsd_tradbed +#undef elf64_mips_write_core_note + #include "elf64-target.h" diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c index 734ebf63..a65456f5 100644 --- a/bfd/elfn32-mips.c +++ b/bfd/elfn32-mips.c @@ -3558,6 +3558,8 @@ elf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return FALSE; case 128: /* Linux/MIPS elf_prpsinfo */ + elf_tdata (abfd)->core->pid + = bfd_get_32 (abfd, note->descdata + 16); elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); elf_tdata (abfd)->core->command @@ -3590,6 +3592,45 @@ elf_n32_mips_irix_compat (bfd *abfd) else return ict_none; } + +/* Write Linux core PRSTATUS note into core file. */ + +static char * +elf32_mips_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, + ...) +{ + switch (note_type) + { + default: + return NULL; + + case NT_PRPSINFO: + BFD_FAIL (); + return NULL; + + case NT_PRSTATUS: + { + char data[440]; + va_list ap; + long pid; + int cursig; + const void *greg; + + va_start (ap, note_type); + memset (data, 0, 72); + pid = va_arg (ap, long); + bfd_put_32 (abfd, pid, data + 24); + cursig = va_arg (ap, int); + bfd_put_16 (abfd, cursig, data + 12); + greg = va_arg (ap, const void *); + memcpy (data + 72, greg, 360); + memset (data + 432, 0, 8); + va_end (ap); + return elfcore_write_note (abfd, buf, bufsiz, + "CORE", note_type, data, sizeof (data)); + } + } +} /* ECOFF swapping routines. These are used when dealing with the .mdebug section, which is in the ECOFF debugging format. */ @@ -3753,6 +3794,9 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { #define ELF_COMMONPAGESIZE 0x1000 #define elf32_bed elf32_tradbed +#undef elf_backend_write_core_note +#define elf_backend_write_core_note elf32_mips_write_core_note + /* Include the target file again for this target. */ #include "elf32-target.h" @@ -3775,4 +3819,6 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { #undef elf32_bed #define elf32_bed elf32_fbsd_tradbed +#undef elf_backend_write_core_note + #include "elf32-target.h" diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h index edbbd9f2..288eb1c4 100644 --- a/bfd/elfxx-mips.h +++ b/bfd/elfxx-mips.h @@ -21,6 +21,7 @@ #include "elf/common.h" #include "elf/internal.h" #include "elf/mips.h" +#include extern bfd_boolean _bfd_mips_elf_mkobject (bfd *); diff --git a/gdb/testsuite/gdb.threads/tls-core.c b/gdb/testsuite/gdb.threads/tls-core.c new file mode 100644 index 00000000..a92f7d83 --- /dev/null +++ b/gdb/testsuite/gdb.threads/tls-core.c @@ -0,0 +1,37 @@ +/* This test is part of GDB, the GNU debugger. + + Copyright 2017 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +int __thread foo = 0xdeadbeef; + +static void * +thread_proc (void *arg) +{ + return arg; +} + +int +main (void) +{ + pthread_t thread; + + pthread_create (&thread, NULL, thread_proc, NULL); + pthread_join (thread, NULL); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/tls-core.exp b/gdb/testsuite/gdb.threads/tls-core.exp new file mode 100644 index 00000000..896676ba --- /dev/null +++ b/gdb/testsuite/gdb.threads/tls-core.exp @@ -0,0 +1,56 @@ +# Copyright 2017 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +standard_testfile + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable { debug }] != "" } { + return -1 +} + + +clean_restart ${binfile} + +runto thread_proc + +# +# Generate corefile. +# +set corefile [standard_output_file gcore.test] +set core_supported [gdb_gcore_cmd "$corefile" "save a corefile"] +if {!$core_supported} { + return 0 +} + +# +# Restart gdb and load generated corefile. +# +clean_restart ${binfile} + +set core_loaded [gdb_core_cmd "$corefile" "load generated corefile"] +if { $core_loaded != 1 } { + # No use proceeding from here. + return 0 +} + +# This fails in cross-debugging due to the use of native `libthread_db'. +if {![string match $host_triplet $target_triplet]} { + setup_kfail "threads/22381" "*-*-*" +} +gdb_test "p/x foo" \ + "\\$\[0-9]+ = 0xdeadbeef" \ + "print thread-local storage variable" + +gdb_exit