mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-07 03:38:31 +00:00
Add support for symbol table in .com files
This change fixes minor bugs and adds a feature, which lets us store the ELF symbol table, inside the ZIP directory. We use the path /zip/.symtab which can be safely removed using a zip editing tool, to make the binary smaller after compilation. This supplements the existing method of using a separate .com.dbg file, which is still supported. The intent is people don't always know that it's a good idea to download the debug file. It's not great having someone's first experience be a crash report, that only has numbers rather than symbols. This will help fix that!
This commit is contained in:
parent
393ca4be40
commit
23b72eb617
61 changed files with 963 additions and 510 deletions
|
@ -80,13 +80,6 @@ cosmo: push %rbp
|
|||
.init.start 306,_init_ftrace
|
||||
push %rdi
|
||||
push %rsi
|
||||
mov %r12d,%edi
|
||||
mov %r13,%rsi
|
||||
mov %r14,%rdx
|
||||
mov %r15,%rcx
|
||||
call program_executable_name_init
|
||||
mov %r12d,%edi
|
||||
mov %r13,%rsi
|
||||
call ftrace_init
|
||||
mov %eax,%r12d
|
||||
pop %rsi
|
||||
|
@ -99,10 +92,6 @@ cosmo: push %rbp
|
|||
.init.start 307,_init_printargs
|
||||
push %rdi
|
||||
push %rsi
|
||||
mov %r12d,%edi
|
||||
mov %r13,%rsi
|
||||
mov %r14,%rdx
|
||||
mov %r15,%rcx
|
||||
call __printargs
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
|
|
|
@ -39,7 +39,7 @@ const char *FindComBinary(void) {
|
|||
const char *p;
|
||||
if (!g_findcombinary.once) {
|
||||
g_findcombinary.once = true;
|
||||
if ((p = program_executable_name) &&
|
||||
if ((p = GetProgramExecutableName()) &&
|
||||
(len = strlen(p)) < ARRAYLEN(g_findcombinary.buf)) {
|
||||
g_findcombinary.res = memcpy(g_findcombinary.buf, p, len + 1);
|
||||
if (len > 4 && memcmp(&g_findcombinary.buf[len - 4], ".dbg", 4) == 0) {
|
||||
|
|
|
@ -35,7 +35,7 @@ const char *FindDebugBinary(void) {
|
|||
size_t n;
|
||||
if (!once) {
|
||||
if (!(res = getenv("COMDBG"))) {
|
||||
p = program_executable_name;
|
||||
p = GetProgramExecutableName();
|
||||
n = strlen(p);
|
||||
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
|
||||
res = p;
|
||||
|
|
|
@ -291,7 +291,7 @@ textwindows int sys_fork_nt(void) {
|
|||
args = args2;
|
||||
}
|
||||
#endif
|
||||
if (ntspawn(program_executable_name, args, environ, forkvar,
|
||||
if (ntspawn(GetProgramExecutableName(), args, environ, forkvar,
|
||||
&kNtIsInheritable, NULL, true, 0, NULL, &startinfo,
|
||||
&procinfo) != -1) {
|
||||
CloseHandle(reader);
|
||||
|
|
|
@ -102,18 +102,13 @@ privileged noinstrument noasan noubsan void ftracer(void) {
|
|||
}
|
||||
|
||||
textstartup void ftrace_install(void) {
|
||||
const char *path;
|
||||
if ((path = FindDebugBinary())) {
|
||||
if ((g_symbols = OpenSymbolTable(path))) {
|
||||
laststamp = kStartTsc;
|
||||
g_lastsymbol = -1;
|
||||
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
|
||||
ftrace_enabled = 1;
|
||||
__hook(ftrace_hook, g_symbols);
|
||||
} else {
|
||||
kprintf("error: --ftrace failed to open symbol table\r\n");
|
||||
}
|
||||
if ((g_symbols = GetSymbolTable())) {
|
||||
laststamp = kStartTsc;
|
||||
g_lastsymbol = -1;
|
||||
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
|
||||
ftrace_enabled = 1;
|
||||
__hook(ftrace_hook, g_symbols);
|
||||
} else {
|
||||
kprintf("error: --ftrace needs concomitant .com.dbg binary\r\n");
|
||||
kprintf("error: --ftrace failed to open symbol table\r\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,8 +52,8 @@ char *GetInterpreterExecutableName(char *p, size_t n) {
|
|||
if (n < 2) {
|
||||
errno = ENAMETOOLONG;
|
||||
} else if (IsWindows()) {
|
||||
if (strlen(program_executable_name) < n) {
|
||||
strcpy(p, program_executable_name);
|
||||
if (strlen(GetProgramExecutableName()) < n) {
|
||||
strcpy(p, GetProgramExecutableName());
|
||||
return p;
|
||||
}
|
||||
errno = ENAMETOOLONG;
|
||||
|
|
133
libc/runtime/getsymboltable.c
Normal file
133
libc/runtime/getsymboltable.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/undeflate.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/zip.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Looks for `.symtab` in zip central directory.
|
||||
*/
|
||||
noasan static ssize_t FindSymtabInZip(struct Zipos *zipos) {
|
||||
size_t i, n, c;
|
||||
c = GetZipCdirOffset(zipos->cdir);
|
||||
n = GetZipCdirRecords(zipos->cdir);
|
||||
for (i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(zipos->map + c)) {
|
||||
if (ZIP_CFILE_NAMESIZE(zipos->map + c) == 7 &&
|
||||
READ32LE(ZIP_CFILE_NAME(zipos->map + c + 0)) == READ32LE(".sym") &&
|
||||
READ16LE(ZIP_CFILE_NAME(zipos->map + c + 4)) == READ16LE("ta") &&
|
||||
*ZIP_CFILE_NAME(zipos->map + c + 6) == 'b') {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads symbol table from zip directory.
|
||||
* @note This code can't depend on dlmalloc()
|
||||
*/
|
||||
noasan static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) {
|
||||
ssize_t cf, lf;
|
||||
size_t size, size2;
|
||||
struct DeflateState ds;
|
||||
struct SymbolTable *res = 0;
|
||||
if ((cf = FindSymtabInZip(zipos)) != -1) {
|
||||
lf = GetZipCfileOffset(zipos->map + cf);
|
||||
size = GetZipLfileUncompressedSize(zipos->map + lf);
|
||||
size2 = ROUNDUP(size, FRAMESIZE);
|
||||
if ((res = mapanon(size2))) {
|
||||
switch (ZIP_LFILE_COMPRESSIONMETHOD(zipos->map + lf)) {
|
||||
case kZipCompressionNone:
|
||||
memcpy(res, (void *)ZIP_LFILE_CONTENT(zipos->map + lf), size);
|
||||
break;
|
||||
case kZipCompressionDeflate:
|
||||
if (undeflate(res, size, (void *)ZIP_LFILE_CONTENT(zipos->map + lf),
|
||||
GetZipLfileCompressedSize(zipos->map + lf),
|
||||
&ds) == -1) {
|
||||
munmap(res, size2);
|
||||
res = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
munmap(res, size2);
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
STRACE("GetSymbolTableFromZip() → %p", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads symbol table from .com.dbg file.
|
||||
* @note This code can't depend on dlmalloc()
|
||||
*/
|
||||
noasan static struct SymbolTable *GetSymbolTableFromElf(void) {
|
||||
return OpenSymbolTable(FindDebugBinary());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns symbol table singleton.
|
||||
*
|
||||
* This uses multiple strategies to find the symbol table. The first
|
||||
* strategy, depends on whether or not the following is linked:
|
||||
*
|
||||
* STATIC_YOINK("__zipos_get");
|
||||
*
|
||||
* In that case, the symbol table may be read from `/zip/.symtab` which
|
||||
* is generated by `o//tool/build/symtab.com`. The second strategy is to
|
||||
* look for the concomitant `.com.dbg` executable, which may very well
|
||||
* be the one currently executing, or it could be placed in the same
|
||||
* folder as your `.com` binary, or lastly, it could be explicitly
|
||||
* specified via the `COMDBG` environment variable.
|
||||
*
|
||||
* Function tracing is disabled throughout the duration of this call.
|
||||
* Backtraces and other core runtime functionality depend on this.
|
||||
*
|
||||
* @return symbol table, or NULL w/ errno on first call
|
||||
*/
|
||||
noasan struct SymbolTable *GetSymbolTable(void) {
|
||||
struct Zipos *z;
|
||||
static struct SymbolTable *t;
|
||||
if (!t) {
|
||||
++g_ftrace;
|
||||
if (weaken(__zipos_get) && (z = weaken(__zipos_get)())) {
|
||||
if ((t = GetSymbolTableFromZip(z))) {
|
||||
t->names = (uint32_t *)((char *)t + t->names_offset);
|
||||
t->name_base = (char *)((char *)t + t->name_base_offset);
|
||||
}
|
||||
}
|
||||
if (!t) {
|
||||
t = GetSymbolTableFromElf();
|
||||
}
|
||||
--g_ftrace;
|
||||
}
|
||||
return t;
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
|
|
@ -18,6 +18,7 @@ extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
|
|||
extern const uintptr_t __fini_array_start[] __attribute__((__weak__));
|
||||
|
||||
void _init(void) hidden;
|
||||
void __restorewintty(void) hidden;
|
||||
void *__cxa_finalize(void *) hidden;
|
||||
void cosmo(int, char **, char **, long (*)[2]) hidden wontreturn;
|
||||
void __stack_chk_fail(void) wontreturn relegated;
|
||||
|
|
|
@ -110,11 +110,11 @@ noasan struct SymbolTable *OpenSymbolTable(const char *filename) {
|
|||
void *map;
|
||||
long *stp;
|
||||
struct stat st;
|
||||
size_t n, m, tsz;
|
||||
unsigned i, j, x;
|
||||
const Elf64_Ehdr *elf;
|
||||
const char *name_base;
|
||||
struct SymbolTable *t;
|
||||
size_t n, m, tsz, size;
|
||||
const Elf64_Sym *symtab, *sym;
|
||||
ptrdiff_t names_offset, name_base_offset, stp_offset;
|
||||
map = MAP_FAILED;
|
||||
|
@ -136,13 +136,19 @@ noasan struct SymbolTable *OpenSymbolTable(const char *filename) {
|
|||
tsz += m;
|
||||
tsz = ROUNDUP(tsz, FRAMESIZE);
|
||||
stp_offset = tsz;
|
||||
size = tsz;
|
||||
tsz += sizeof(const Elf64_Sym *) * n;
|
||||
tsz = ROUNDUP(tsz, FRAMESIZE);
|
||||
t = mmap(0, tsz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (t == MAP_FAILED) goto SystemError;
|
||||
t->mapsize = tsz;
|
||||
t->names = (unsigned *)((char *)t + names_offset);
|
||||
t->name_base = (char *)((char *)t + name_base_offset);
|
||||
t->magic = SYMBOLS_MAGIC;
|
||||
t->abi = SYMBOLS_ABI;
|
||||
t->size = size;
|
||||
t->mapsize = size;
|
||||
t->names_offset = names_offset;
|
||||
t->name_base_offset = name_base_offset;
|
||||
t->names = (uint32_t *)((char *)t + t->names_offset);
|
||||
t->name_base = (char *)((char *)t + t->name_base_offset);
|
||||
GetImageRange(elf, &t->addr_base, &t->addr_end);
|
||||
memcpy(t->name_base, name_base, m);
|
||||
--t->addr_end;
|
||||
|
|
|
@ -75,25 +75,24 @@ static const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
textstartup void __printargs(int argc, char **argv, char **envp,
|
||||
intptr_t *auxv) {
|
||||
textstartup void __printargs(void) {
|
||||
#ifdef SYSDEBUG
|
||||
long key;
|
||||
char **env;
|
||||
unsigned i;
|
||||
intptr_t *auxp;
|
||||
uintptr_t *auxp;
|
||||
char path[PATH_MAX];
|
||||
struct AuxiliaryValue *auxinfo;
|
||||
STRACE("ARGUMENTS (%p)", argv);
|
||||
for (i = 0; i < argc; ++i) {
|
||||
STRACE(" ☼ %s", argv[i]);
|
||||
STRACE("ARGUMENTS (%p)", __argv);
|
||||
for (i = 0; i < __argc; ++i) {
|
||||
STRACE(" ☼ %s", __argv[i]);
|
||||
}
|
||||
STRACE("ENVIRONMENT (%p)", envp);
|
||||
for (env = envp; *env; ++env) {
|
||||
STRACE("ENVIRONMENT (%p)", __envp);
|
||||
for (env = __envp; *env; ++env) {
|
||||
STRACE(" ☼ %s", *env);
|
||||
}
|
||||
STRACE("AUXILIARY (%p)", auxv);
|
||||
for (auxp = auxv; *auxp; auxp += 2) {
|
||||
STRACE("AUXILIARY (%p)", __auxv);
|
||||
for (auxp = __auxv; *auxp; auxp += 2) {
|
||||
if ((auxinfo = DescribeAuxv(auxp[0]))) {
|
||||
ksnprintf(path, sizeof(path), auxinfo->fmt, auxp[1]);
|
||||
STRACE(" ☼ %16s[%4ld] = %s", auxinfo->name, auxp[0], path);
|
||||
|
@ -105,7 +104,8 @@ textstartup void __printargs(int argc, char **argv, char **envp,
|
|||
STRACE(" ☼ %30s = %#s", "kTmpPath", kTmpPath);
|
||||
STRACE(" ☼ %30s = %#s", "kNtSystemDirectory", kNtSystemDirectory);
|
||||
STRACE(" ☼ %30s = %#s", "kNtWindowsDirectory", kNtWindowsDirectory);
|
||||
STRACE(" ☼ %30s = %#s", "program_executable_name", program_executable_name);
|
||||
STRACE(" ☼ %30s = %#s", "program_executable_name",
|
||||
GetProgramExecutableName());
|
||||
STRACE(" ☼ %30s = %#s", "GetInterpreterExecutableName()",
|
||||
GetInterpreterExecutableName(path, sizeof(path)));
|
||||
STRACE(" ☼ %30s = %p", "RSP", __builtin_frame_address(0));
|
||||
|
|
|
@ -9,10 +9,10 @@ COSMOPOLITAN_C_START_
|
|||
typedef long jmp_buf[8] forcealign(CACHELINE);
|
||||
|
||||
extern char **environ; /* CRT */
|
||||
extern const int __argc; /* CRT */
|
||||
extern char **const __argv; /* CRT */
|
||||
extern char **const __envp; /* CRT */
|
||||
extern unsigned long *const __auxv; /* CRT */
|
||||
extern int __argc; /* CRT */
|
||||
extern char **__argv; /* CRT */
|
||||
extern char **__envp; /* CRT */
|
||||
extern unsigned long *__auxv; /* CRT */
|
||||
extern intptr_t __oldstack; /* CRT */
|
||||
extern char program_executable_name[]; /* RII */
|
||||
extern char *program_invocation_name; /* RII */
|
||||
|
@ -98,6 +98,7 @@ int OpenExecutable(void);
|
|||
void ftrace_install(void);
|
||||
long GetResourceLimit(int);
|
||||
long GetMaxFd(void);
|
||||
char *GetProgramExecutableName(void);
|
||||
char *GetInterpreterExecutableName(char *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -18,11 +18,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Enables plaintext system call logging if `--strace` flag is passed.
|
||||
|
@ -33,5 +31,5 @@ textstartup int __strace_init(int argc, char **argv, char **envp, long *auxv) {
|
|||
__atoul(nulltoempty(__getenv(envp, "STRACE")))) {
|
||||
++__strace;
|
||||
}
|
||||
return argc;
|
||||
return (__argc = argc);
|
||||
}
|
||||
|
|
|
@ -1,21 +1,30 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_SYMBOLS_H_
|
||||
#define COSMOPOLITAN_LIBC_SYMBOLS_H_
|
||||
#include "libc/bits/bits.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define SYMBOLS_MAGIC READ32LE("SYMT")
|
||||
#define SYMBOLS_ABI 1
|
||||
|
||||
struct Symbol {
|
||||
unsigned x; /* start (relative to addr_base) */
|
||||
unsigned y; /* start + size - 1 (inclusive) */
|
||||
};
|
||||
|
||||
struct SymbolTable {
|
||||
size_t count; /* of `symbols` */
|
||||
size_t mapsize; /* of this object */
|
||||
intptr_t addr_base; /* IMAGE_BASE_VIRTUAL */
|
||||
intptr_t addr_end; /* _end - 1 */
|
||||
unsigned *names; /* relative to `name_base` */
|
||||
char *name_base; /* double-nul terminated w/ empty first */
|
||||
struct Symbol symbols[]; /* sorted and non-overlapping intervals */
|
||||
uint32_t magic; /* 0xFEEDABEE little endian */
|
||||
uint32_t abi; /* 1 */
|
||||
uint64_t count; /* of `symbols` */
|
||||
uint64_t size; /* file size */
|
||||
uint64_t mapsize; /* of this object */
|
||||
int64_t addr_base; /* IMAGE_BASE_VIRTUAL */
|
||||
int64_t addr_end; /* _end - 1 */
|
||||
uint32_t *names; /* relative to `name_base` */
|
||||
char *name_base; /* double-nul terminated w/ empty first */
|
||||
uint32_t names_offset; /* for file loading */
|
||||
uint32_t name_base_offset; /* for file loading */
|
||||
struct Symbol symbols[]; /* sorted and non-overlapping intervals */
|
||||
};
|
||||
|
||||
struct SymbolTable *GetSymbolTable(void);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue