diff --git a/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_segment_tracking.c b/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_segment_tracking.c index 20fae255f71e303f2379d555d6a5a1f126577f83..c65253afe997590a6af6ed375f0e93630ec74c14 100644 --- a/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_segment_tracking.c +++ b/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_segment_tracking.c @@ -1137,6 +1137,8 @@ void print_shadow_layout() { print_memory_partition(&mem_layout.global); DLOG(">>> TLS ----------------------\n"); print_memory_partition(&mem_layout.tls); + DLOG(">>> VDSO ---------------------\n"); + print_memory_partition(&mem_layout.vdso); # elif E_ACSL_OS_IS_WINDOWS DLOG(">>> TEXT ---------------------\n"); print_memory_partition(&mem_layout.text); diff --git a/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_shadow_layout.c b/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_shadow_layout.c index 9b910aaa18097903a66cdcd1844a72159be31db0..2a9a7a0063a7b61b113ffe8eb94ab58281ecad30 100644 --- a/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_shadow_layout.c +++ b/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_shadow_layout.c @@ -30,7 +30,13 @@ #if E_ACSL_OS_IS_LINUX +# include <fcntl.h> +# include <inttypes.h> +# include <stdio.h> +# include <string.h> +# include <sys/auxv.h> # include <sys/resource.h> +# include <unistd.h> /** Program stack information {{{ */ @@ -229,6 +235,93 @@ static void init_shadow_layout_tls() { # endif } +static void init_shadow_layout_vdso() { + // Retrieve the start address of the VDSO segment + uintptr_t vdso = getauxval(AT_SYSINFO_EHDR); + private_assert( + vdso != 0, + "Start address of VDSO segment not found in auxiliary vector.\n"); + + // Use /proc/self/maps to retrieve the end address of the VDSO segment + // (using open() instead of fopen() to avoid a dynamic allocation) + int maps_fd = open("/proc/self/maps", O_RDONLY); + private_assert(maps_fd >= 0, "Unable to open /proc/self/maps: %s\n", + strerror(errno)); + + int result; + uintptr_t start, end; + ssize_t count; + off_t offset; + char *newline; + // Buffer to read /proc/self/maps. 255 should be enough to read one line. + char buffer[255]; + while (1) { + count = read(maps_fd, buffer, sizeof(buffer) - 1); + if (count == 0) { + // If the VDSO segment has not been found, use 0 as start and end + // addresses + DVABORT("VDSO segment not found at address %a in /proc/self/maps\n", + vdso); + start = 0; + end = 0; + break; + } else if (count < 0) { + DVABORT("Reading /proc/self/maps failed: %s\n", strerror(errno)); + break; + } else { + // Scan the start and end addresses of the segment + buffer[count] = '\0'; + result = sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR, &start, &end); + DVASSERT(result == 2, + "Scanning for addresses in /proc/self/maps failed, expected 2 " + "addresses, found: %d, error: %s\n", + result, strerror(errno)); + + if (start <= vdso && vdso < end) { + break; + } + + // Set the file offset to the next line + do { + // Look for a newline character + buffer[count] = '\0'; + newline = strchr(buffer, '\n'); + if (newline != NULL) { + // Newline character found, set the file offset to the character + // after the newline + offset = count - (newline - buffer + 1); + offset = lseek(maps_fd, -offset, SEEK_CUR); + DVASSERT(offset != -1, + "Unable to move file offset of /proc/self/maps: %s\n", + strerror(errno)); + break; + } else { + // No newline found on the current buffer, continue reading the file + count = read(maps_fd, buffer, sizeof(buffer) - 1); + } + } while (count > 0); + } + } + + result = close(maps_fd); + DVASSERT(result == 0, "Unable to close /proc/self/maps: %s\n", + strerror(errno)); + + // Initialize the memory partition + memory_partition *pvdso = &mem_layout.vdso; + set_application_segment(&pvdso->application, start, end - start, "vdso", + NULL); + set_shadow_segment(&pvdso->primary, &pvdso->application, 1, "vdso_primary"); + set_shadow_segment(&pvdso->secondary, &pvdso->application, 1, + "vdso_secondary"); +# ifdef E_ACSL_TEMPORAL + set_shadow_segment(&pvdso->temporal_primary, &pvdso->application, 1, + "temporal_vdso_primary"); + set_shadow_segment(&pvdso->temporal_secondary, &pvdso->application, 1, + "temporal_vdso_secondary"); +# endif +} + static void init_shadow_layout_stack(int *argc_ref, char ***argv_ref) { memory_partition *pstack = &mem_layout.stack; set_application_segment(&pstack->application, @@ -489,6 +582,7 @@ void init_shadow_layout_pre_main() { #if E_ACSL_OS_IS_LINUX init_shadow_layout_global(); + init_shadow_layout_vdso(); init_shadow_layout_tls(); #elif E_ACSL_OS_IS_WINDOWS HANDLE module = GetModuleHandle(NULL); diff --git a/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_shadow_layout.h b/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_shadow_layout.h index f64825206dd86c8579ab4bb78b8ff16eb91e6996..9bdc0138ea97f61c70653e4c2a83da8e8131c8dc 100644 --- a/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_shadow_layout.h +++ b/src/plugins/e-acsl/share/e-acsl/observation_model/segment_model/e_acsl_shadow_layout.h @@ -70,9 +70,11 @@ Standard streams stdin, stdout and stderr are put here. Some libraries such as libxml use it quite a lot: it may occur that the given size is not enough, - in which case it MUST be increased. */ + in which case it MUST be increased. + However since the TLS is next to the VDSO segment in the program layout, the + default size is small enough so that both segments do not overlap. */ #ifndef PGM_TLS_SIZE -# define PGM_TLS_SIZE (64 * MB) +# define PGM_TLS_SIZE (2 * MB) #endif /*! \brief Mspace padding used by shadow segments. This is to make sure that @@ -191,6 +193,8 @@ struct memory_layout { memory_partition global; // The TLS is in a specific section and identifiable memory_partition tls; + // The VDSO is a small shared library used for some kernel functions + memory_partition vdso; #elif E_ACSL_OS_IS_WINDOWS // On windows // The text, bss and data segments are not necessarily contiguous so each one @@ -214,11 +218,9 @@ struct memory_layout mem_layout = { /*! \brief Array of used partitions */ memory_partition *mem_partitions[] = { - &mem_layout.heap, - &mem_layout.stack, + &mem_layout.heap, &mem_layout.stack, #if E_ACSL_OS_IS_LINUX - &mem_layout.global, - &mem_layout.tls, + &mem_layout.global, &mem_layout.tls, &mem_layout.vdso, #elif E_ACSL_OS_IS_WINDOWS &mem_layout.text, &mem_layout.bss, &mem_layout.data, &mem_layout.idata, &mem_layout.rdata, @@ -291,6 +293,8 @@ void clean_shadow_layout(); # define global_secondary_offset mem_layout.global.secondary.shadow_offset # define tls_primary_offset mem_layout.tls.primary.shadow_offset # define tls_secondary_offset mem_layout.tls.secondary.shadow_offset +# define vdso_primary_offset mem_layout.vdso.primary.shadow_offset +# define vdso_secondary_offset mem_layout.vdso.secondary.shadow_offset #elif E_ACSL_OS_IS_WINDOWS # define text_primary_offset mem_layout.text.primary.shadow_offset # define text_secondary_offset mem_layout.text.secondary.shadow_offset @@ -351,6 +355,14 @@ void clean_shadow_layout(); /*! \brief Convert a TLS address into its secondary shadow counterpart */ # define SECONDARY_TLS_SHADOW(_addr) SHADOW_ACCESS(_addr, tls_secondary_offset) + +/*! \brief Convert a VDSO address into its primary shadow counterpart */ +# define PRIMARY_VDSO_SHADOW(_addr) SHADOW_ACCESS(_addr, vdso_primary_offset) + +/*! \brief Convert a VDSO address into its secondary shadow counterpart */ +# define SECONDARY_VDSO_SHADOW(_addr) \ + SHADOW_ACCESS(_addr, vdso_secondary_offset) + #elif E_ACSL_OS_IS_WINDOWS /*! \brief Convert a text address into its primary shadow counterpart */ # define PRIMARY_TEXT_SHADOW(_addr) SHADOW_ACCESS(_addr, text_primary_offset) @@ -418,6 +430,7 @@ void clean_shadow_layout(); (IS_ON_STACK(_addr) ? _region##_STACK_SHADOW(_addr) \ : IS_ON_GLOBAL(_addr) ? _region##_GLOBAL_SHADOW(_addr) \ : IS_ON_TLS(_addr) ? _region##_TLS_SHADOW(_addr) \ + : IS_ON_VDSO(_addr) ? _region##_VDSO_SHADOW(_addr) \ : (intptr_t)0) // clang-format on #elif E_ACSL_OS_IS_WINDOWS @@ -462,10 +475,14 @@ void clean_shadow_layout(); /*! \brief Evaluate to true if _addr is a TLS address */ # define IS_ON_TLS(_addr) IS_ON(_addr, mem_layout.tls.application) +/*! \brief Evaluate to true if _addr is a VDSO address */ +# define IS_ON_VDSO(_addr) IS_ON(_addr, mem_layout.vdso.application) + /*! \brief Shortcut for evaluating an address via ::IS_ON_STACK, * ::IS_ON_GLOBAL or ::IS_ON_TLS */ # define IS_ON_STATIC(_addr) \ - (IS_ON_STACK(_addr) || IS_ON_GLOBAL(_addr) || IS_ON_TLS(_addr)) + (IS_ON_STACK(_addr) || IS_ON_GLOBAL(_addr) || IS_ON_TLS(_addr) \ + || IS_ON_VDSO(_addr)) #elif E_ACSL_OS_IS_WINDOWS /*! \brief Evaluate to true if `_addr` is a text address */ # define IS_ON_TEXT(_addr) IS_ON(_addr, mem_layout.text.application) @@ -529,6 +546,15 @@ void clean_shadow_layout(); /*! \brief Convert a TLS address into its secondary temporal shadow counterpart */ # define TEMPORAL_SECONDARY_TLS_SHADOW(_addr) \ SHADOW_ACCESS(_addr, mem_layout.tls.temporal_secondary.shadow_offset) + +/*! \brief Convert a VDSO address into its primary temporal shadow counterpart */ +# define TEMPORAL_PRIMARY_VDSO_SHADOW(_addr) \ + SHADOW_ACCESS(_addr, mem_layout.vdso.temporal_primary.shadow_offset) + +/*! \brief Convert a VDSO address into its secondary temporal shadow counterpart */ +# define TEMPORAL_SECONDARY_VDSO_SHADOW(_addr) \ + SHADOW_ACCESS(_addr, mem_layout.vdso.temporal_secondary.shadow_offset) + # elif E_ACSL_OS_IS_WINDOWS /*! \brief Convert a text address into its primary temporal shadow counterpart */ # define TEMPORAL_PRIMARY_TEXT_SHADOW(_addr) \