Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ SRCS := \
debug/gdbstub.c \
debug/gdbstub-reg.c \
debug/gdbstub-rsp.c \
debug/log.c
debug/log.c \
debug/syscall-hist.c

SRCS := $(addprefix src/,$(SRCS))
OBJS := $(patsubst src/%.c,$(BUILD_DIR)/%.o,$(SRCS))
Expand Down
18 changes: 8 additions & 10 deletions src/core/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,18 +348,16 @@ int elf_map_segments(const elf_info_t *info,
return -1;
}

/* Zero the full page-aligned segment extent (zero_len computed above
* with guest_size and infra_reserve checks). Linux guarantees
* zero-filled tail bytes in the last mapped page, and some dynamic
* linkers allocate from that page tail before they request more
* memory. Leaving stale bytes there leaks state across execve and
* corrupts the new image.
/* Zero only the tail beyond filesz: the BSS portion [filesz, memsz)
* plus the page-padding [memsz, zero_len) that Linux guarantees clean
* for dynamic linkers allocating from the last mapped page's tail.
* Skipping the file-data range avoids writing zeros that the fread
* below would immediately overwrite; for typical shared libraries that
* is a hundreds-of-KiB win per segment.
*/
memset((uint8_t *) guest_base + gpa, 0, zero_len);
if (zero_len > filesz)
memset((uint8_t *) guest_base + gpa + filesz, 0, zero_len - filesz);

/* Overlay initialized bytes after zeroing so BSS and page tail remain
* zero-filled.
*/
if (filesz > 0) {
if (fseek(f, (long) ph->p_offset, SEEK_SET) != 0) {
log_error("%s: seek failed for segment at 0x%llx", path,
Expand Down
38 changes: 37 additions & 1 deletion src/core/startup-trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@
* static inline so each translation unit can use them without pulling in a
* separate object; the getenv check resolves once per translation unit but
* the resolution itself is idempotent.
*
* Accepted env values:
* unset, "", "0" -> all tracing off
* "1", "steps" -> per-step VM bring-up timings (this header)
* "syscalls" -> per-syscall histogram (debug/syscall-hist.c)
* "all" -> both, comma-separated tokens also accepted
* "1" is preserved as a legacy alias for "steps" so old scripts keep
* working. The histogram mode never enables the step tracer and vice
* versa, so a user can ask for one without paying for the other.
*/

#ifndef ELFUSE_STARTUP_TRACE_H
Expand All @@ -30,10 +39,37 @@
static pthread_once_t startup_trace_once = PTHREAD_ONCE_INIT;
static bool startup_trace_value;

static inline bool startup_trace_env_has(const char *env, const char *tok)
{
if (!env || !env[0])
return false;
size_t toklen = strlen(tok);
const char *p = env;
while (*p) {
const char *comma = strchr(p, ',');
size_t len = comma ? (size_t) (comma - p) : strlen(p);
if (len == toklen && memcmp(p, tok, toklen) == 0)
return true;
if (!comma)
break;
p = comma + 1;
}
return false;
}

static inline void startup_trace_resolve(void)
{
const char *v = getenv("ELFUSE_STARTUP_TRACE");
startup_trace_value = v && v[0] && strcmp(v, "0") != 0;
if (!v || !v[0] || !strcmp(v, "0"))
return;
/* The legacy "1" knob enables steps. Recognize it both as the whole
* value and as a token so compound forms like "1,syscalls" still
* keep the step trace on alongside the histogram, instead of
* silently dropping it.
*/
if (!strcmp(v, "1") || startup_trace_env_has(v, "1") ||
startup_trace_env_has(v, "steps") || startup_trace_env_has(v, "all"))
startup_trace_value = true;
}

static inline bool startup_trace_enabled(void)
Expand Down
Loading
Loading