1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-08 17:42:12 +03:00
Files
glibc/elf/dl-find_object.h
Claudiu Zissulescu 0ebe4fba88 elf: Add SFrame support to _dl_find_object function
The SFrame provides information to be able to do stack trace is now
well defined and implemented in Binutils 2.41.  The format simply
contains enough information to be able to do stack trace given a
program counter (PC) value, the stack pointer, and the frame pointer.
The SFrame information is stored in a .sframe ELF section, which is
loaded into its own PT_GNU_SFRAME segment. We consider for this support
SFrame version 2.

This patch adds the bits to _dl_find_object to recognize and store in
struct dl_find_object the necessary info about SFrame section.

Signed-off-by: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
2025-07-14 10:56:35 +01:00

168 lines
5.9 KiB
C

/* Locating objects in the process image. ld.so implementation.
Copyright (C) 2021-2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _DL_FIND_EH_FRAME_H
#define _DL_FIND_EH_FRAME_H
#include <assert.h>
#include <atomic.h>
#include <dlfcn.h>
#include <ldsodefs.h>
#include <stdbool.h>
#include <stdint.h>
/* Internal version of struct dl_find_object. Does not include the
(yet unused) flags member. We need to make a copy of data also in
struct link_map to support non-contiguous mappings, and to support
software transactional memory (the link map is not covered by
transactions). */
struct dl_find_object_internal
{
uintptr_t map_start;
uintptr_t map_end; /* Set to map_start by dlclose. */
struct link_map *map; /* Set to NULL by dlclose. */
void *eh_frame;
#if DLFO_STRUCT_HAS_EH_DBASE
void *eh_dbase;
#endif
#if DLFO_STRUCT_HAS_EH_COUNT
int eh_count;
#endif
void *sframe;
};
/* Create a copy of *SOURCE in *COPY using relaxed MO loads and
stores. */
static inline void
_dl_find_object_internal_copy (const struct dl_find_object_internal *source,
struct dl_find_object_internal *copy)
{
atomic_store_relaxed (&copy->map_start,
atomic_load_relaxed (&source->map_start));
atomic_store_relaxed (&copy->map_end,
atomic_load_relaxed (&source->map_end));
atomic_store_relaxed (&copy->map,
atomic_load_relaxed (&source->map));
atomic_store_relaxed (&copy->eh_frame,
atomic_load_relaxed (&source->eh_frame));
#if DLFO_STRUCT_HAS_EH_DBASE
atomic_store_relaxed (&copy->eh_dbase,
atomic_load_relaxed (&source->eh_dbase));
#endif
#if DLFO_STRUCT_HAS_EH_COUNT
atomic_store_relaxed (&copy->eh_count,
atomic_load_relaxed (&source->eh_count));
#endif
atomic_store_relaxed (&copy->sframe,
atomic_load_relaxed (&source->sframe));
}
static inline void
_dl_find_object_to_external (struct dl_find_object_internal *internal,
struct dl_find_object *external)
{
external->dlfo_map_start = (void *) internal->map_start;
external->dlfo_map_end = (void *) internal->map_end;
external->dlfo_link_map = internal->map;
external->dlfo_eh_frame = internal->eh_frame;
# if DLFO_STRUCT_HAS_EH_DBASE
external->dlfo_eh_dbase = internal->eh_dbase;
# endif
# if DLFO_STRUCT_HAS_EH_COUNT
external->dlfo_eh_count = internal->eh_count;
# endif
external->dlfo_sframe = internal->sframe;
if (internal->sframe != NULL)
external->dlfo_flags = DLFO_FLAG_SFRAME;
else
external->dlfo_flags = 0;
}
/* Extract the object location data from a link map and writes it to
*RESULT using relaxed MO stores. */
static void __attribute__ ((unused))
_dl_find_object_from_map (struct link_map *l,
struct dl_find_object_internal *result)
{
/* A mask to find out which segment has been read out. */
unsigned int read_seg = 0;
atomic_store_relaxed (&result->map_start, (uintptr_t) l->l_map_start);
atomic_store_relaxed (&result->map_end, (uintptr_t) l->l_map_end);
atomic_store_relaxed (&result->map, l);
#if DLFO_STRUCT_HAS_EH_DBASE
atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]);
#endif
/* Initialize object's exception handling segment and SFrame segment
data. */
atomic_store_relaxed (&result->sframe, NULL);
atomic_store_relaxed (&result->eh_frame, NULL);
#if DLFO_STRUCT_HAS_EH_COUNT
atomic_store_relaxed (&result->eh_count, 0);
#endif
for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum;
ph < ph_end; ++ph)
{
switch (ph->p_type)
{
case DLFO_EH_SEGMENT_TYPE:
atomic_store_relaxed (&result->eh_frame,
(void *) (ph->p_vaddr + l->l_addr));
#if DLFO_STRUCT_HAS_EH_COUNT
atomic_store_relaxed (&result->eh_count, ph->p_memsz / 8);
#endif
read_seg |= 1;
break;
case PT_GNU_SFRAME:
atomic_store_relaxed (&result->sframe,
(void *) (ph->p_vaddr + l->l_addr));
read_seg |= 2;
/* Fall through. */
default:
break;
}
if (read_seg == 3)
return;
}
}
/* Called by the dynamic linker to set up the data structures for the
initially loaded objects. This creates a few persistent
allocations, so it should be called with the minimal malloc. */
void _dl_find_object_init (void) attribute_hidden;
/* Called by dlopen/dlmopen to add new objects to the DWARF EH frame
data structures. NEW_MAP is the dlopen'ed link map. Link maps on
the l_next list are added if l_object_processed is 0. Needs to
be protected by loader write lock. Returns true on success, false
on malloc failure. */
bool _dl_find_object_update (struct link_map *new_map) attribute_hidden;
/* Called by dlclose to remove the link map from the DWARF EH frame
data structures. Needs to be protected by loader write lock. */
void _dl_find_object_dlclose (struct link_map *l) attribute_hidden;
/* Called from __libc_freeres to deallocate malloc'ed memory. */
void _dl_find_object_freeres (void) attribute_hidden;
#endif /* _DL_FIND_OBJECT_H */