Hi all, Infinity is a platform-independent system for executables and shared libraries to expose functionality to debug, monitoring, and analysis tooling. Executable and shared library files contain platform- independent debugging functions that tools like GDB can load and execute. I've written a prototype libthread_db that uses Infinity functions. Implementation-specific details such as structure offsets and other constants are held with the implementation (specifically, in libpthread.so and ld.so) which means that one libthread_db.so can support any correctly-annotated system, regardless of architecture or operating system, and without recompilation. You can, for example, debug a core file from an aarch64 system running Debian on your x86_64 laptop that's running Fedora. You can try this out right now, there's instructions at: https://infinitynotes.org/wiki/Third_Eye This series adds proc_service functionality that the Infinity libthread_db.so needs. The series isn't polished, but I'm mailing it now to get feedback on the two new proc_service functions I'm proposing in patch 4. Specifically I'd like feedback on the API, I'd like to know it's going to be acceptable and make any required changes now. The things Infinity needs that the existing proc_service API doesn't provide are: 1) The ability to get the contents of a registers in a cross-platform environment. proc_service has ps_lgetregs, but it's not suitable. proc_service has no way to determine the inferior's architecture, so there's no way to determine the size of the register set you're going to get, and no way to determine where in that register set the register values you want are. I've handled this by adding ps_get_register, which returns the contents of a single register, referenced by its DWARF register number. 2) The ability to fetch .note.infinity sections from the inferior's executable and shared libraries. With proc_service as it stands, you can sort of find the binaries in some cases, but you can't find them in all cases GDB supports: if they're in a sysroot, for example. The only way I could think of to reliably solve this in all cases GDB supports is to have GDB extract the sections itself and supply them to the library via a callback. It's further complicated by the fact that .note.infinity sections contain addresses that require relocation. I've handled this with the ps_foreach_infinity_note function. I'm not 100% happy with how complex this part of the API is, but I can't see a simpler way :/ Thanks, Gary -- https://infinitynotes.org/
This commit defines NT_GNU_INFINITY, the ELF note type used for Infinity notes. Note that the current value is not final. include/ChangeLog: * elf/common.h: Add NT_GNU_INFINITY. --- include/ChangeLog | 4 ++++ include/elf/common.h | 1 + 2 files changed, 5 insertions(+) diff --git a/include/elf/common.h b/include/elf/common.h index 484cb48..fee6d1a 100644 --- a/include/elf/common.h +++ b/include/elf/common.h @@ -673,6 +673,7 @@ #define NT_GNU_BUILD_ID 3 /* Generated by ld --build-id. */ #define NT_GNU_GOLD_VERSION 4 /* Generated by gold. */ #define NT_GNU_PROPERTY_TYPE_0 5 /* Generated by gcc. */ +#define NT_GNU_INFINITY 8995 /* Generated by i8c. */ #define NT_GNU_BUILD_ATTRIBUTE_OPEN 0x100 #define NT_GNU_BUILD_ATTRIBUTE_FUNC 0x101 -- 1.8.3.1
This commit adds support for Infinity notes in ELF .note.infinity sections. A list of found notes is built and its head pointer stored as infinity_note_head in struct elf_obj_tdata. bfd/ChangeLog: * elf-bfd.h (struct elf_infinity_note): New structure. (struct elf_obj_tdata): Add new field infinity_note_head. * elf.c (elfobj_grok_gnu_infinity): New function. (elfobj_grok_gnu_note): Call the above. --- bfd/ChangeLog | 7 +++++++ bfd/elf-bfd.h | 14 ++++++++++++++ bfd/elf.c | 23 +++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index af377ee..9da3d53 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1694,6 +1694,15 @@ struct sdt_note bfd_byte data[1]; }; +/* An Infinity note. */ +struct elf_infinity_note +{ + struct elf_infinity_note *next; + bfd_vma fileoffset; + size_t size; + bfd_byte data[0]; +}; + /* tdata information grabbed from an elf core file. */ struct core_elf_obj_tdata { @@ -1856,6 +1865,11 @@ struct elf_obj_tdata in the list. */ struct sdt_note *sdt_note_head; + /* Linked list containing information about every Infinity note + found in the object file. Each note corresponds to one entry + in the list. */ + struct elf_infinity_note *infinity_note_head; + Elf_Internal_Shdr **group_sect_ptr; int num_group; diff --git a/bfd/elf.c b/bfd/elf.c index 18b4bbe..420773e 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -9756,6 +9756,26 @@ elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note) } static bfd_boolean +elfobj_grok_gnu_infinity (bfd *abfd, Elf_Internal_Note *note) +{ + struct elf_infinity_note *cur; + + if (note->descsz == 0) + return FALSE; + + cur = bfd_alloc (abfd, sizeof (struct elf_infinity_note) + note->descsz); + + cur->next = elf_tdata (abfd)->infinity_note_head; + cur->fileoffset = note->descpos; + cur->size = note->descsz; + memcpy (cur->data, note->descdata, note->descsz); + + elf_tdata (abfd)->infinity_note_head = cur; + + return TRUE; +} + +static bfd_boolean elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note) { switch (note->type) @@ -9768,6 +9788,9 @@ elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note) case NT_GNU_BUILD_ID: return elfobj_grok_gnu_build_id (abfd, note); + + case NT_GNU_INFINITY: + return elfobj_grok_gnu_infinity (abfd, note); } } -- 1.8.3.1
This commit allows the registers FS_BASE and GS_BASE to be accessed from DWARF on amd64 systems. gdb/ChangeLog: * amd64-tdep.c (amd64_dwarf_regmap): Add AMD64_FSBASE_REGNUM and AMD64_GSBASE_REGNUM. --- gdb/ChangeLog | 5 +++++ gdb/amd64-tdep.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index 9ff7dfc..437bbac 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -228,8 +228,8 @@ static int amd64_dwarf_regmap[] = -1, /* Segment Base Address Registers. */ - -1, - -1, + AMD64_FSBASE_REGNUM, + AMD64_GSBASE_REGNUM, -1, -1, -- 1.8.3.1
This commit adds declarations for the two new proc_service functions required by Infinity libthread_db.so. gdb/ChangeLog: * gdb_proc_service.h (ps_infinity_reloc_f): New typedef. (ps_visit_infinity_note_f): Likewise. (ps_get_register): New declaration. (ps_foreach_infinity_note): Likewise. --- gdb/ChangeLog | 7 +++++++ gdb/gdb_proc_service.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/gdb/gdb_proc_service.h b/gdb/gdb_proc_service.h index 734fcb2..59b8d6e 100644 --- a/gdb/gdb_proc_service.h +++ b/gdb/gdb_proc_service.h @@ -175,6 +175,52 @@ typedef gdb_fpregset_t gdb_prfpregset_t; typedef prfpregset_t gdb_prfpregset_t; #endif +/* XXX need to check for ps_get_register and ps_foreach_infinity_note + in ./configure if HAVE_PROC_SERVICE_H and only define them here if + we don't already have them. */ + +EXTERN_C_PUSH + +/* Get the contents of a single register. */ +extern ps_err_e ps_get_register (struct ps_prochandle *ph, + lwpid_t lwpid, int dwarf_regnum, + psaddr_t *result); + +/* Callback to relocate addresses in Infinity notes. */ +typedef ps_err_e ps_infinity_reloc_f (void *rf_arg, + psaddr_t unrelocated, + psaddr_t *result); + +/* Callback for iteration over Infinity notes. Should return PS_OK to + indicate success, or any other value to indicate failure. CB_ARG + is whatever was passed as CB_ARG to ps_foreach_infinity_note. BUF + is is a pointer to a buffer of BUFSIZ bytes containing the encoded + note. SRCNAME is an identifier used to construct error messages, + typically a filename, and may be NULL if unset. SRCOFFSET is the + offset into SRCNAME of the start of BUF, and may be -1 if unset. + RF is a function that should be used to relocate addresses in this + notes, and RF_ARG is an argument that should be passed as to RF. */ +typedef ps_err_e ps_visit_infinity_note_f (void *cb_arg, + const char *buf, + size_t bufsiz, + const char *srcname, + ssize_t srcoffset, + ps_infinity_reloc_f *rf, + void *rf_arg); + +/* Call the callback CB for each Infinity note in the process. The + callback should return PS_OK to indicate that iteration should + continue, or any other value to indicate that iteration should stop + and that ps_foreach_infinity_note should return the non-PS_OK value + that the callback returned. Return PS_OK if the callback returned + PS_OK for all Infinity notes, or if there are no Infinity notes in + the process. */ +extern ps_err_e ps_foreach_infinity_note (struct ps_prochandle *ph, + ps_visit_infinity_note_f *cb, + void *cb_arg); + +EXTERN_C_POP + /* GDB specific structure that identifies the target process. */ struct ps_prochandle { -- 1.8.3.1
This commit implements the two new Infinity proc-service functions in GDB. gdb/ChangeLog: * proc-service.c (ps_get_register): New function. (ps_foreach_infinity_note): Likewise. (ps_infinity_relocate_addr): New static function. * proc-service.list: Add ps_get_register and ps_foreach_infinity_note. --- gdb/ChangeLog | 8 +++++ gdb/proc-service.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/proc-service.list | 2 ++ 3 files changed, 104 insertions(+) diff --git a/gdb/proc-service.c b/gdb/proc-service.c index 415ba0a..c3f5b013 100644 --- a/gdb/proc-service.c +++ b/gdb/proc-service.c @@ -25,6 +25,7 @@ #include "target.h" #include "regcache.h" #include "objfiles.h" +#include "elf-bfd.h" #include "gdb_proc_service.h" @@ -218,6 +219,31 @@ ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, return PS_OK; } +/* See gdb_proc_service.h. */ + +ps_err_e +ps_get_register (struct ps_prochandle *ph, lwpid_t lwpid, + int dwarf_reg, psaddr_t *result) +{ + struct gdbarch *gdbarch = target_gdbarch (); + ptid_t lwp_ptid; + struct regcache *regcache; + int reg;enum register_status status; + + reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_reg); + if (reg == -1) + { + warning (_("Bad DWARF register number %d"), dwarf_reg); + return PS_ERR; + } + + lwp_ptid = ptid_build (ptid_get_pid (ph->ptid), lwpid, 0); + regcache = get_thread_arch_regcache (lwp_ptid, gdbarch); + status = regcache_raw_read (regcache, reg, (gdb_byte *) result); + + return status == REG_VALID ? PS_OK : PS_ERR; +} + /* Return overall process id of the target PH. Special for GNU/Linux -- not used on Solaris. */ @@ -227,6 +253,74 @@ ps_getpid (gdb_ps_prochandle_t ph) return ptid_get_pid (ph->ptid); } +/* Callback for ps_foreach_infinity_note to relocate addresses in + Infinity notes. */ + +static ps_err_e +ps_infinity_relocate_addr (void *objfile_p, psaddr_t unrelocated_p, + psaddr_t *result_p) +{ + struct objfile *objfile = (struct objfile *) objfile_p; + CORE_ADDR unrelocated = ps_addr_to_core_addr (unrelocated_p); + struct obj_section *osect; + + ALL_OBJFILE_OSECTIONS (objfile, osect) + { + struct bfd_section *sect = osect->the_bfd_section; + bfd_vma section_vma = bfd_get_section_vma (objfile->obfd, sect); + + if (unrelocated < section_vma + || unrelocated >= (section_vma + bfd_get_section_size (sect))) + continue; + + *result_p = core_addr_to_ps_addr (unrelocated - section_vma + + obj_section_addr (osect)); + + return PS_OK; + } + + return PS_ERR; +} + +/* See gdb_proc_service.h. */ + +ps_err_e +ps_foreach_infinity_note (struct ps_prochandle *ph, + ps_visit_infinity_note_f *callback, + void *cb_arg) +{ + struct cleanup *old_chain = save_current_program_space (); + struct inferior *inf = find_inferior_ptid (ph->ptid); + struct objfile *objfile; + ps_err_e result = PS_OK; + + set_current_program_space (inf->pspace); + + ALL_OBJFILES (objfile) + { + struct elf_infinity_note *note; + + if (objfile->obfd == NULL + || bfd_get_flavour (objfile->obfd) != bfd_target_elf_flavour) + continue; + + for (note = elf_tdata (objfile->obfd)->infinity_note_head; + note != NULL; note = note->next) + { + result = callback (cb_arg, + (const char *) note->data, note->size, + objfile_name (objfile), note->fileoffset, + ps_infinity_relocate_addr, objfile); + + if (result != PS_OK) + break; + } + } + + do_cleanups (old_chain); + return result; +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_proc_service; diff --git a/gdb/proc-service.list b/gdb/proc-service.list index 79c2e5b..903c0d5 100644 --- a/gdb/proc-service.list +++ b/gdb/proc-service.list @@ -37,4 +37,6 @@ ps_pstop; ps_ptread; ps_ptwrite; + ps_foreach_infinity_note; + ps_get_register; }; -- 1.8.3.1