int dlfo_eh_count; /* Number of exception handling entries. */
unsigned int __dlfo_eh_count_pad;
# endif
- __extension__ unsigned long long int __dflo_reserved[7];
+ void *dlfo_sframe; /* SFrame stack trace data of the object. */
+#if __WORDSIZE == 32
+ unsigned int __dlfo_sframe_pad;
+#endif
+ __extension__ unsigned long long int __dlfo_reserved[6];
};
/* If ADDRESS is found in an object, fill in *RESULT and return 0.
Otherwise, return -1. */
int _dl_find_object (void *__address, struct dl_find_object *__result) __THROW;
-#endif /* __USE_GNU */
+/* SFrame stack trace data is valid. */
+#define DLFO_FLAG_SFRAME (1ULL << 0)
+#endif /* __USE_GNU */
__END_DECLS
#if DLFO_STRUCT_HAS_EH_COUNT
int eh_count;
#endif
+ void *sframe;
};
/* Create a copy of *SOURCE in *COPY using relaxed MO loads and
atomic_store_relaxed (©->eh_count,
atomic_load_relaxed (&source->eh_count));
#endif
+ atomic_store_relaxed (©->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_flags = 0;
external->dlfo_map_start = (void *) internal->map_start;
external->dlfo_map_end = (void *) internal->map_end;
external->dlfo_link_map = internal->map;
# 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
_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);
atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]);
#endif
- for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum;
- ph < ph_end; ++ph)
- if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
- {
- atomic_store_relaxed (&result->eh_frame,
- (void *) (ph->p_vaddr + l->l_addr));
+ /* 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, ph->p_memsz / 8);
+ atomic_store_relaxed (&result->eh_count, 0);
#endif
- return;
- }
- /* Object has no exception handling segment. */
- atomic_store_relaxed (&result->eh_frame, NULL);
+ 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, 0);
+ 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
@table @code
@item unsigned long long int dlfo_flags
-Currently unused and always 0.
+Bit zero signals if SFrame stack data is valid. See
+@code{DLFO_FLAG_SFRAME} below.
@item void *dlfo_map_start
The start address of the inspected mapping. This information comes from
This member contains a pointer to the exception handling data of the
object. See @code{DLFO_EH_SEGMENT_TYPE} below.
+@item void *dlfo_sframe
+This member points to the SFrame stack trace data associated with the
+object. It is valid only when @code{DLFO_FLAG_SFRAME} is set in
+@code{dlfo_flags}; otherwise, it may be null or undefined.
+
@end table
This structure is a GNU extension.
This function is a GNU extension.
@end deftypefun
+The following flag masks are defined for use with @code{dlfo_flags}:
+
+@table @code
+@item DLFO_FLAG_SFRAME
+A bit mask used to signal that the object contains SFrame data. See
+@code{dlfo_sframe} above.
+
+@end table
+
@node Dynamic Linker Hardening
@section Avoiding Unexpected Issues With Dynamic Linking