Validate privileged code relationships

- Work towards improving non-optimized build support
- Introduce MODE=zero which is -O0 without ASAN/UBSAN
- Use system GCC when ~/.cosmo.mk has USE_SYSTEM_TOOLCHAIN=1
- Have package.com check .privileged code doesn't call non-privileged
This commit is contained in:
Justine Tunney 2023-06-08 04:37:05 -07:00
parent 01fd655097
commit daf4454a06
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
82 changed files with 808 additions and 850 deletions

View file

@ -48,17 +48,17 @@ o/$(MODE)/tool/build/emubin/%.bin.dbg: \
$(TOOL_BUILD_EMUBIN_A) \
o/$(MODE)/tool/build/emubin/%.o \
$(TOOL_BUILD_EMUBIN_A).pkg
@$(ELFLINK) -e emucrt -z max-page-size=0x10
@$(ELFLINK) -e emucrt -z common-page-size=0x10 -z max-page-size=0x10
o/tiny/tool/build/emubin/spiral.bin.dbg: \
$(TOOL_BUILD_EMUBIN_DEPS) \
o/tiny/tool/build/emubin/spiral.real.o
@$(ELFLINK) -z max-page-size=0x10 -T tool/build/emucrt/real.lds
@$(ELFLINK) -z common-page-size=0x10 -z max-page-size=0x10 -T tool/build/emucrt/real.lds
o/tiny/tool/build/emubin/mdatest.bin.dbg: \
$(TOOL_BUILD_EMUBIN_DEPS) \
o/tiny/tool/build/emubin/mdatest.real.o
@$(ELFLINK) -z max-page-size=0x10 -T tool/build/emucrt/real.lds
@$(ELFLINK) -z common-page-size=0x10 -z max-page-size=0x10 -T tool/build/emucrt/real.lds
$(TOOL_BUILD_EMUBIN_OBJS): private \
CFLAGS += \

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
@ -26,9 +27,11 @@
#include "libc/elf/struct/sym.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
@ -41,20 +44,21 @@
* @fileoverview GCC Codegen Fixer-Upper.
*/
#define GETOPTS "h"
#define GETOPTS "ch"
#define USAGE \
"\
Usage: fixupobj.com [-h] ARGS...\n\
-?\n\
-h show help\n\
-c check-only mode\n\
"
#define COSMO_TLS_REG 28
#define MRS_TPIDR_EL0 0xd53bd040u
#define MOV_REG(DST, SRC) (0xaa0003e0u | (SRC) << 16 | (DST))
static const unsigned char kFatNops[8][8] = {
const unsigned char kFatNops[8][8] = {
{}, //
{0x90}, // nop
{0x66, 0x90}, // xchg %ax,%ax
@ -65,31 +69,43 @@ static const unsigned char kFatNops[8][8] = {
{0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}, // nopl 0x00000000(%rax)
};
void Write(const char *s, ...) {
int mode;
char *symstrs;
char *secstrs;
ssize_t esize;
Elf64_Sym *syms;
const char *epath;
Elf64_Xword symcount;
const Elf64_Ehdr *elf;
void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
write(2, s, strlen(s));
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
strlcat(buf, "\n", sizeof(buf));
write(fd, buf, strlen(buf));
va_end(va);
}
wontreturn void SysExit(int rc, const char *call, const char *thing) {
int err;
char ibuf[12];
const char *estr;
err = errno;
FormatInt32(ibuf, err);
estr = _strerdoc(err);
if (!estr) estr = "EUNKNOWN";
Write(thing, ": ", call, "() failed: ", estr, " (", ibuf, ")\n", NULL);
exit(rc);
wontreturn void SysExit(const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
Print(2, epath, ": ", func, " failed with ", errstr, "\n", NULL);
exit(1);
}
static void GetOpts(int argc, char *argv[]) {
void GetOpts(int argc, char *argv[]) {
int opt;
mode = O_RDWR;
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
switch (opt) {
case 'c':
mode = O_RDONLY;
break;
case 'h':
case '?':
write(1, USAGE, sizeof(USAGE) - 1);
@ -101,17 +117,56 @@ static void GetOpts(int argc, char *argv[]) {
}
}
Elf64_Shdr *FindElfSectionByName(const char *name) {
long i;
Elf64_Shdr *shdr;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (!strcmp(GetElfString(elf, esize, secstrs, shdr->sh_name), name)) {
return shdr;
}
}
return 0;
}
void CheckPrivilegedCrossReferences(void) {
long i, x;
Elf64_Shdr *shdr;
const char *secname;
Elf64_Rela *rela, *erela;
if (!(shdr = FindElfSectionByName(".rela.privileged"))) return;
rela = GetElfSectionAddress(elf, esize, shdr);
erela = rela + shdr->sh_size / sizeof(*rela);
for (; rela < erela; ++rela) {
if (!ELF64_R_TYPE(rela->r_info)) continue;
if (!(x = ELF64_R_SYM(rela->r_info))) continue;
if (syms[x].st_shndx == SHN_ABS) continue;
if (!syms[x].st_shndx) continue;
shdr = GetElfSectionHeaderAddress(elf, esize, syms[x].st_shndx);
if (~shdr->sh_flags & SHF_EXECINSTR) continue; // data reference
secname = GetElfString(elf, esize, secstrs, shdr->sh_name);
if (strcmp(".privileged", secname)) {
Print(2, epath,
": code in .privileged section "
"references symbol '",
GetElfString(elf, esize, symstrs, syms[x].st_name),
"' in unprivileged code section '", secname, "'\n", NULL);
exit(1);
}
}
}
// Modify ARM64 code to use x28 for TLS rather than tpidr_el0.
void RewriteTlsCode(Elf64_Ehdr *elf, size_t elfsize) {
void RewriteTlsCode(void) {
int i, dest;
Elf64_Shdr *shdr;
uint32_t *p, *pe;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, elfsize, i);
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (shdr->sh_type == SHT_PROGBITS && //
(shdr->sh_flags & SHF_ALLOC) && //
(shdr->sh_flags & SHF_EXECINSTR) && //
(p = GetElfSectionAddress(elf, elfsize, shdr))) {
(p = GetElfSectionAddress(elf, esize, shdr))) {
for (pe = p + shdr->sh_size / 4; p <= pe; ++p) {
if ((*p & -32) == MRS_TPIDR_EL0) {
*p = MOV_REG(*p & 31, COSMO_TLS_REG);
@ -131,19 +186,16 @@ void RewriteTlsCode(Elf64_Ehdr *elf, size_t elfsize) {
* In order for this to work, the function symbol must be declared as
* `STT_FUNC` and `st_size` must have the function's byte length.
*/
void OptimizePatchableFunctionEntries(Elf64_Ehdr *elf, size_t elfsize) {
void OptimizePatchableFunctionEntries(void) {
#ifdef __x86_64__
long i, n;
int nopcount;
Elf64_Sym *syms;
Elf64_Shdr *shdr;
Elf64_Xword symcount;
unsigned char *p, *pe;
CHECK_NOTNULL((syms = GetElfSymbolTable(elf, elfsize, &symcount)));
for (i = 0; i < symcount; ++i) {
if (ELF64_ST_TYPE(syms[i].st_info) == STT_FUNC && syms[i].st_size) {
shdr = GetElfSectionHeaderAddress(elf, elfsize, syms[i].st_shndx);
p = GetElfSectionAddress(elf, elfsize, shdr);
shdr = GetElfSectionHeaderAddress(elf, esize, syms[i].st_shndx);
p = GetElfSectionAddress(elf, esize, shdr);
p += syms[i].st_value;
pe = p + syms[i].st_size;
for (; p + 1 < pe; p += n) {
@ -159,27 +211,22 @@ void OptimizePatchableFunctionEntries(Elf64_Ehdr *elf, size_t elfsize) {
#endif /* __x86_64__ */
}
void OptimizeRelocations(Elf64_Ehdr *elf, size_t elfsize) {
char *strs;
void OptimizeRelocations(void) {
Elf64_Half i;
Elf64_Sym *syms;
Elf64_Rela *rela;
Elf64_Xword symcount;
unsigned char *code, *p;
Elf64_Shdr *shdr, *shdrcode;
CHECK_NOTNULL((strs = GetElfStringTable(elf, elfsize)));
CHECK_NOTNULL((syms = GetElfSymbolTable(elf, elfsize, &symcount)));
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, elfsize, i);
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (shdr->sh_type == SHT_RELA) {
CHECK_EQ(sizeof(struct Elf64_Rela), shdr->sh_entsize);
CHECK_NOTNULL(
(shdrcode = GetElfSectionHeaderAddress(elf, elfsize, shdr->sh_info)));
(shdrcode = GetElfSectionHeaderAddress(elf, esize, shdr->sh_info)));
if (!(shdrcode->sh_flags & SHF_EXECINSTR)) continue;
CHECK_NOTNULL((code = GetElfSectionAddress(elf, elfsize, shdrcode)));
for (rela = GetElfSectionAddress(elf, elfsize, shdr);
CHECK_NOTNULL((code = GetElfSectionAddress(elf, esize, shdrcode)));
for (rela = GetElfSectionAddress(elf, esize, shdr);
((uintptr_t)rela + shdr->sh_entsize <=
MIN((uintptr_t)elf + elfsize,
MIN((uintptr_t)elf + esize,
(uintptr_t)elf + shdr->sh_offset + shdr->sh_size));
++rela) {
@ -189,7 +236,7 @@ void OptimizeRelocations(Elf64_Ehdr *elf, size_t elfsize) {
* Then libc/runtime/ftrace.greg.c morphs it back at runtime.
*/
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCRELX &&
strcmp(GetElfString(elf, elfsize, strs,
strcmp(GetElfString(elf, esize, symstrs,
syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
@ -207,7 +254,7 @@ void OptimizeRelocations(Elf64_Ehdr *elf, size_t elfsize) {
*/
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
ELF64_R_TYPE(rela->r_info) == R_X86_64_PLT32) &&
strcmp(GetElfString(elf, elfsize, strs,
strcmp(GetElfString(elf, esize, symstrs,
syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
@ -223,45 +270,65 @@ void OptimizeRelocations(Elf64_Ehdr *elf, size_t elfsize) {
}
}
void RewriteObject(const char *path) {
void FixupObject(void) {
int fd;
struct stat st;
Elf64_Ehdr *elf;
if ((fd = open(path, O_RDWR)) == -1) {
SysExit(__COUNTER__ + 1, "open", path);
if ((fd = open(epath, mode)) == -1) {
SysExit("open");
}
if (fstat(fd, &st) == -1) {
SysExit(__COUNTER__ + 1, "fstat", path);
if ((esize = lseek(fd, 0, SEEK_END)) == -1) {
SysExit("lseek");
}
if (st.st_size >= 64) {
if ((elf = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
0)) == MAP_FAILED) {
SysExit(__COUNTER__ + 1, "mmap", path);
if (esize) {
if ((elf = mmap(0, esize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
MAP_FAILED) {
SysExit("mmap");
}
if (elf->e_machine == EM_NEXGEN32E) {
OptimizeRelocations(elf, st.st_size);
OptimizePatchableFunctionEntries(elf, st.st_size);
if (!IsElf64Binary(elf, esize)) {
Print(2, epath, ": not an elf64 binary\n", NULL);
exit(1);
}
if (elf->e_machine == EM_AARCH64) {
RewriteTlsCode(elf, st.st_size);
if (!(syms = GetElfSymbolTable(elf, esize, &symcount))) {
Print(2, epath, ": missing elf symbol table\n", NULL);
exit(1);
}
if (msync(elf, st.st_size, MS_ASYNC | MS_INVALIDATE)) {
SysExit(__COUNTER__ + 1, "msync", path);
if (!(secstrs = GetElfSectionNameStringTable(elf, esize))) {
Print(2, epath, ": missing elf section string table\n", NULL);
exit(1);
}
if (munmap(elf, st.st_size)) {
SysExit(__COUNTER__ + 1, "munmap", path);
if (!(symstrs = GetElfStringTable(elf, esize))) {
Print(2, epath, ": missing elf symbol string table\n", NULL);
exit(1);
}
CheckPrivilegedCrossReferences();
if (mode == O_RDWR) {
if (elf->e_machine == EM_NEXGEN32E) {
OptimizeRelocations();
OptimizePatchableFunctionEntries();
}
if (elf->e_machine == EM_AARCH64) {
RewriteTlsCode();
}
if (msync(elf, esize, MS_ASYNC | MS_INVALIDATE)) {
SysExit("msync");
}
}
if (munmap(elf, esize)) {
SysExit("munmap");
}
}
if (close(fd)) {
SysExit(__COUNTER__ + 1, "close", path);
SysExit("close");
}
}
int main(int argc, char *argv[]) {
int i, opt;
if (IsModeDbg()) ShowCrashReports();
if (!IsOptimized()) {
ShowCrashReports();
}
GetOpts(argc, argv);
for (i = optind; i < argc; ++i) {
RewriteObject(argv[i]);
epath = argv[i];
FixupObject();
}
}

View file

@ -1,120 +0,0 @@
/*-*- 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/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/intrin/bsr.h"
#include "libc/log/check.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/x/x.h"
#include "tool/build/lib/persist.h"
static bool IsWithin(size_t sz1, void *vp1, size_t sz2, void *vp2) {
char *p1 = vp1, *p2 = vp2;
return p1 >= p2 && p1 + sz1 <= p2 + sz2;
}
static bool IsOverlapping(void *vx1, void *vy1, void *vx2, void *vy2) {
char *x1 = vx1, *y1 = vy1, *x2 = vx2, *y2 = vy2;
return (x1 >= x2 && x1 <= y2) || (y1 >= x2 && y1 <= y2);
}
static bool IsOverlappingIov(struct iovec *a, struct iovec *b) {
char *ap = a->iov_base, *bp = b->iov_base;
return IsOverlapping(ap, ap + a->iov_len, bp, bp + b->iov_len);
}
/**
* Writes struct w/ dynamic arrays to mappable file, e.g.
*
* PersistObject(path, 64, &(struct ObjectParam){
* sizeof(*o), o, &o->magic, &o->abi,
* &(struct ObjectArrayParam){
* {&o->a1.i, sizeof(o->a1.p[0]), &o->a1.p},
* {&o->a2.i, sizeof(o->a2.p[0]), &o->a2.p},
* {0},
* }});
*
* @param obj->magic needs to be unique for struct
* @param obj->abi monotonically tracks breaking changes
* @param obj->arrays needs sentinel with item size of zero
* @note non-recursive i.e. array elements can't have pointers
* @see MapObject()
*/
void PersistObject(const char *path, size_t align,
const struct ObjectParam *obj) {
const char *pad;
struct iovec *iov;
int i, n, fd, iovlen;
long len, size, bytes, filesize;
unsigned char *hdr, *p1, *p2, **pp;
intptr_t arrayptroffset, arraydataoffset;
filesize = 0;
DCHECK_GE(align, 1);
CHECK_GT(*obj->magic, 0);
CHECK_GT(*obj->abi, 0);
CHECK(IsWithin(sizeof(*obj->magic), obj->magic, obj->size, obj->p));
CHECK(IsWithin(sizeof(*obj->abi), obj->abi, obj->size, obj->p));
for (n = i = 0; obj->arrays[i].size; ++i) ++n;
iovlen = (n + 1) * 2;
pad = _gc(xcalloc(align, 1));
hdr = _gc(xmalloc(obj->size));
iov = _gc(xcalloc(iovlen, sizeof(*iov)));
bytes = obj->size;
iov[0].iov_base = memcpy(hdr, obj->p, obj->size);
iov[0].iov_len = bytes;
iov[1].iov_base = pad;
iov[1].iov_len = ROUNDUP(bytes, align) - bytes;
filesize += ROUNDUP(bytes, align);
for (i = 0; i < n; ++i) {
pp = obj->arrays[i].pp;
len = obj->arrays[i].len;
size = obj->arrays[i].size;
if (!*pp || !len) continue;
p1 = obj->p;
p2 = obj->arrays[i].pp;
arrayptroffset = p2 - p1;
arraydataoffset = filesize;
CHECK((!len || _bsrl(len) + _bsrl(size) < 31),
"path=%s i=%d len=%,lu size=%,lu", path, i, len, size);
CHECK(IsWithin(sizeof(void *), pp, obj->size, obj->p));
CHECK(!IsOverlapping(pp, pp + sizeof(void *), obj->magic,
obj->magic + sizeof(*obj->magic)));
CHECK(!IsOverlapping(pp, pp + sizeof(void *), obj->abi,
obj->abi + sizeof(*obj->abi)));
memcpy(hdr + arrayptroffset, &arraydataoffset, sizeof(intptr_t));
CHECK_LT(filesize + arraydataoffset, 0x7ffff000);
bytes = len * size;
iov[(i + 1) * 2 + 0].iov_base = *pp;
iov[(i + 1) * 2 + 0].iov_len = bytes;
iov[(i + 1) * 2 + 1].iov_base = pad;
iov[(i + 1) * 2 + 1].iov_len = ROUNDUP(bytes, align) - bytes;
filesize += ROUNDUP(bytes, align);
CHECK(!IsOverlappingIov(&iov[(i + 0) * 2], &iov[(i + 1) * 2]),
"iov[%d]={%#p,%#x}, iov[%d]={%#p,%#x} path=%s", (i + 0) * 2,
iov[(i + 0) * 2].iov_base, iov[(i + 0) * 2].iov_len, (i + 1) * 2,
iov[(i + 1) * 2].iov_base, iov[(i + 1) * 2].iov_len, path);
}
CHECK_NE(-1, (fd = creat(path, 0644)), "%s", path);
CHECK_EQ(filesize, writev(fd, iov, iovlen));
CHECK_NE(-1, close(fd));
}

View file

@ -1,24 +0,0 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct ObjectArrayParam {
size_t len;
size_t size;
void *pp;
};
struct ObjectParam {
size_t size;
void *p;
uint32_t *magic;
int32_t *abi;
struct ObjectArrayParam * arrays;
};
void PersistObject(const char *, size_t, const struct ObjectParam *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_ */

View file

@ -17,14 +17,18 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/elf/elf.h"
#include "libc/elf/struct/rela.h"
#include "libc/elf/struct/shdr.h"
#include "libc/elf/struct/sym.h"
#include "libc/errno.h"
#include "libc/intrin/bswap.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/check.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/alg.h"
#include "libc/mem/arraylist.internal.h"
#include "libc/mem/mem.h"
@ -36,7 +40,8 @@
#include "third_party/getopt/getopt.h"
#include "third_party/xed/x86.h"
#include "tool/build/lib/getargs.h"
#include "tool/build/lib/persist.h"
STATIC_YOINK("realloc");
/**
* @fileoverview Build Package Script.
@ -67,7 +72,21 @@
*/
#define PACKAGE_MAGIC bswap_32(0xBEEFBEEFu)
#define PACKAGE_ABI 1
#define PACKAGE_ABI 2
struct ObjectArrayParam {
size_t len;
size_t size;
void *pp;
};
struct ObjectParam {
size_t size;
void *p;
uint32_t *magic;
int32_t *abi;
struct ObjectArrayParam *arrays;
};
struct Packages {
size_t i, n;
@ -77,7 +96,7 @@ struct Packages {
uint32_t path; // pkg->strings.p[path]
int64_t fd; // not persisted
void *addr; // not persisted
size_t size; // not persisted
ssize_t size; // not persisted
struct Strings {
size_t i, n;
char *p; // persisted as pkg+RVA
@ -86,28 +105,29 @@ struct Packages {
size_t i, n;
struct Object {
uint32_t path; // pkg->strings.p[path]
unsigned mode; // not persisted
struct Elf64_Ehdr *elf; // not persisted
size_t size; // not persisted
char *strs; // not persisted
Elf64_Sym *syms; // not persisted
Elf64_Xword symcount; // not persisted
struct Sections {
size_t i, n;
struct Section {
enum SectionKind {
kUndef,
kText,
kData,
kPiroRelo,
kPiroData,
kPiroBss,
kBss,
} kind;
} * p;
} sections; // not persisted
} * p; // persisted as pkg+RVA
int section_offset;
int section_count;
} * p;
} objects;
struct Sections {
size_t i, n;
struct Section {
int name;
enum SectionKind {
kUndef,
kText,
kPrivilegedText,
kData,
kBss,
kOther,
} kind;
} * p;
} sections;
struct Symbols {
size_t i, n;
struct Symbol {
@ -115,80 +135,223 @@ struct Packages {
enum SectionKind kind : 8;
uint8_t bind_ : 4;
uint8_t type : 4;
uint16_t object; // pkg->objects.p[object]
} * p; // persisted as pkg+RVA
} symbols, undefs; // TODO(jart): hash undefs?
} * *p; // persisted across multiple files
uint16_t object; // pkg->objects.p[object]
uint16_t section; // pkg->sections.p[section]
} * p; // persisted as pkg+RVA
} symbols, undefs; // TODO(jart): hash undefs?
} * *p; // persisted across multiple files
};
int CompareSymbolName(const struct Symbol *a, const struct Symbol *b,
const char *tab) {
struct Relas {
size_t i, n;
struct Strings s;
struct Rela {
const char *symbol_name;
const char *object_path;
} * p;
} prtu;
nullterminated() static void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
write(fd, buf, strlen(buf));
va_end(va);
}
static wontreturn void SysExit(const char *path, const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
Print(2, path, ": ", func, " failed with ", errstr, "\n", NULL);
exit(1);
}
static int CompareSymbolName(const struct Symbol *a, const struct Symbol *b,
const char *tab) {
return strcmp(tab + a->name, tab + b->name);
}
struct Package *LoadPackage(const char *path) {
static void PrintSymbols(struct Package *pkg, struct Symbols *syms,
const char *name) {
int i;
kprintf(" - %s=%d\n", name, syms->i);
for (i = 0; i < syms->i; ++i) {
kprintf(" - id=%d\n", i);
kprintf(" name=%d [%s]\n", syms->p[i].name,
pkg->strings.p + syms->p[i].name);
kprintf(" kind=%d\n", syms->p[i].kind);
kprintf(" bind=%d\n", syms->p[i].bind_);
kprintf(" type=%d\n", syms->p[i].type);
kprintf(" object=%d [%s]\n", syms->p[i].object,
pkg->strings.p + pkg->objects.p[syms->p[i].object].path);
kprintf(" section=%d [%s]\n", syms->p[i].section,
syms->p[i].section == SHN_ABS
? "SHN_ABS"
: pkg->strings.p + pkg->sections.p[syms->p[i].section].name);
}
}
static void PrintObject(struct Package *pkg, struct Object *obj) {
int i, o;
kprintf(" path=%d [%s]\n", obj->path, pkg->strings.p + obj->path);
kprintf(" sections=%d\n", obj->section_count);
for (i = 0; i < obj->section_count; ++i) {
o = obj->section_offset;
kprintf(" - id=%d %p (%d+%d)\n", i, pkg->sections.p, o, i);
kprintf(" name=%d [%s]\n", pkg->sections.p[o + i].name,
pkg->strings.p + pkg->sections.p[o + i].name);
kprintf(" kind=%d\n", pkg->sections.p[o + i].kind);
}
}
static void PrintPackage(struct Package *pkg) {
int i, j, o;
kprintf("- %s\n", pkg->strings.p + pkg->path);
kprintf(" objects=%d\n", pkg->objects.i);
for (i = 0; i < pkg->objects.i; ++i) {
kprintf(" - id=%d\n", i);
PrintObject(pkg, pkg->objects.p + i);
}
PrintSymbols(pkg, &pkg->symbols, "symbols");
PrintSymbols(pkg, &pkg->undefs, "undefs");
}
static void PrintPackages(struct Package *p, int n) {
int i;
for (i = 0; i < n; ++i) {
PrintPackage(p + i);
}
}
static struct Package *LoadPackage(const char *path) {
int fd;
ssize_t i;
struct stat st;
ssize_t i, size;
struct Package *pkg;
CHECK(fileexists(path), "%s: %s: %s\n", "error", path, "not found");
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
CHECK_NE(-1, fstat(fd, &st));
CHECK_NE(MAP_FAILED,
(pkg = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
fd, 0)),
"path=%s", path);
CHECK_NE(-1, close(fd));
CHECK_EQ(PACKAGE_MAGIC, pkg->magic, "corrupt package: %`'s", path);
pkg->strings.p = (char *)((intptr_t)pkg->strings.p + (intptr_t)pkg);
pkg->objects.p = (struct Object *)((intptr_t)pkg->objects.p + (intptr_t)pkg);
pkg->symbols.p = (struct Symbol *)((intptr_t)pkg->symbols.p + (intptr_t)pkg);
if ((fd = open(path, O_RDONLY)) == -1) {
SysExit(path, "open");
}
if ((size = lseek(fd, 0, SEEK_END)) == -1) {
SysExit(path, "lseek");
}
if ((pkg = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) ==
MAP_FAILED) {
SysExit(path, "mmap");
}
close(fd);
if (pkg->magic != PACKAGE_MAGIC) {
Print(2, path, ": not a cosmo .pkg file\n", NULL);
exit(1);
}
if (pkg->abi < PACKAGE_ABI) {
Print(2, path, ": package has old abi try running make clean\n", NULL);
exit(1);
}
pkg->strings.p = (void *)((uintptr_t)pkg->strings.p + (uintptr_t)pkg);
pkg->objects.p = (void *)((uintptr_t)pkg->objects.p + (uintptr_t)pkg);
pkg->symbols.p = (void *)((uintptr_t)pkg->symbols.p + (uintptr_t)pkg);
pkg->sections.p = (void *)((uintptr_t)pkg->sections.p + (uintptr_t)pkg);
pkg->addr = pkg;
pkg->size = st.st_size;
CHECK_NE(-1, mprotect(pkg, st.st_size, PROT_READ));
pkg->size = size;
if (mprotect(pkg, size, PROT_READ)) {
SysExit(path, "mprotect");
}
return pkg;
}
void AddDependency(struct Packages *deps, const char *path) {
static void AddDependency(struct Packages *deps, const char *path) {
struct Package *pkg;
pkg = LoadPackage(path);
CHECK_NE(-1, append(deps, &pkg));
append(deps, &pkg);
}
void WritePackage(struct Package *pkg) {
CHECK_NE(0, PACKAGE_MAGIC);
static void WritePackage(struct Package *pkg) {
int fd;
size_t n;
int64_t o;
const char *path;
pkg->magic = PACKAGE_MAGIC;
pkg->abi = PACKAGE_ABI;
DEBUGF("%s has %,ld objects, %,ld symbols, and a %,ld byte string table",
&pkg->strings.p[pkg->path], pkg->objects.i, pkg->symbols.i,
pkg->strings.i);
PersistObject(
&pkg->strings.p[pkg->path], 64,
&(struct ObjectParam){
sizeof(struct Package),
pkg,
&pkg->magic,
&pkg->abi,
(struct ObjectArrayParam[]){
{pkg->strings.i, sizeof(pkg->strings.p[0]), &pkg->strings.p},
{pkg->objects.i, sizeof(pkg->objects.p[0]), &pkg->objects.p},
{pkg->symbols.i, sizeof(pkg->symbols.p[0]), &pkg->symbols.p},
{0},
},
});
path = pkg->strings.p + pkg->path;
if ((fd = creat(path, 0644)) == -1) {
SysExit(path, "creat");
}
o = sizeof(*pkg);
// write objects
n = pkg->objects.i * sizeof(*pkg->objects.p);
if (pwrite(fd, pkg->objects.p, n, o) != n) {
SysExit(path, "pwrite");
}
pkg->objects.p = (void *)o;
o += n;
// write symbols
n = pkg->symbols.i * sizeof(*pkg->symbols.p);
if (pwrite(fd, pkg->symbols.p, n, o) != n) {
SysExit(path, "pwrite");
}
pkg->symbols.p = (void *)o;
o += n;
// write sections
n = pkg->sections.i * sizeof(*pkg->sections.p);
if (pwrite(fd, pkg->sections.p, n, o) != n) {
SysExit(path, "pwrite");
}
pkg->sections.p = (void *)o;
o += n;
// write strings
n = pkg->strings.i * sizeof(*pkg->strings.p);
pwrite(fd, pkg->strings.p, n, o);
pkg->strings.p = (void *)o;
// write header
if (pwrite(fd, pkg, sizeof(*pkg), 0) != sizeof(*pkg)) {
SysExit(path, "pwrite");
}
// we're done
if (close(fd) == -1) {
SysExit(path, "close");
}
}
void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
char *argv[]) {
static wontreturn void PrintUsage(int fd, int exitcode) {
Print(fd, "\
NAME\n\
\n\
Cosmopolitan Monorepo Packager\n\
\n\
SYNOPSIS\n\
\n\
",
program_invocation_name, " [FLAGS] OBJECT...\n\
\n\
DESCRIPTION\n\
\n\
This program verifies the well-formedness of symbolic references\n\
and package dependencies in the cosmopolitan monolithic repository.\n\
Validation happens incrementally and is granular to static libraries.\n\
Each .a file should have its own .pkg file too, created by this tool.\n\
\n\
FLAGS\n\
\n\
-h show this help\n\
-o PATH package output path\n\
-d PATH package dependency path [repeatable]\n\
\n\
",
NULL);
exit(exitcode);
}
static void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
char *argv[]) {
long i, si, opt;
const char *arg;
struct GetArgs ga;
pkg->path = -1;
while ((opt = getopt(argc, argv, "vho:d:")) != -1) {
while ((opt = getopt(argc, argv, "ho:d:")) != -1) {
switch (opt) {
case 'v':
__log_level = kLogDebug;
break;
case 'o':
pkg->path = concat(&pkg->strings, optarg, strlen(optarg) + 1);
break;
@ -196,72 +359,74 @@ void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
AddDependency(deps, optarg);
break;
case 'h':
exit(0);
PrintUsage(1, 0);
default:
fprintf(stderr, "%s: %s [%s %s] [%s %s] %s\n", "Usage",
program_invocation_name, "-o", "OUTPACKAGE", "-d", "DEPPACKAGE",
"OBJECT...");
exit(1);
PrintUsage(2, 1);
}
}
CHECK_NE(-1, pkg->path, "no packages passed to package.com");
CHECK_LT(optind, argc,
"no objects passed to package.com; "
"is your foo.mk $(FOO_OBJS) glob broken?");
if (pkg->path == -1) {
Print(2, "error: no packages passed to package.com\n", NULL);
exit(1);
}
if (optind == argc) {
Print(2,
"no objects passed to package.com; is your foo.mk $(FOO_OBJS) glob "
"broken?\n",
NULL);
exit(1);
}
getargs_init(&ga, argv + optind);
while ((arg = getargs_next(&ga))) {
CHECK_NE(-1, (si = concat(&pkg->strings, arg, strlen(arg) + 1)));
CHECK_NE(-1, append(&pkg->objects, (&(struct Object){si})));
struct Object obj = {0};
obj.path = concat(&pkg->strings, arg, strlen(arg) + 1);
append(&pkg->objects, &obj);
}
getargs_destroy(&ga);
}
void IndexSections(struct Object *obj) {
size_t i;
static void IndexSections(struct Package *pkg, struct Object *obj) {
int i;
const char *name;
const uint8_t *code;
struct Section sect;
const Elf64_Shdr *shdr;
struct XedDecodedInst xedd;
obj->section_offset = pkg->sections.i;
for (i = 0; i < obj->elf->e_shnum; ++i) {
bzero(&sect, sizeof(sect));
CHECK_NOTNULL((shdr = GetElfSectionHeaderAddress(obj->elf, obj->size, i)));
if (shdr->sh_type != SHT_NULL) {
CHECK_NOTNULL((name = GetElfSectionName(obj->elf, obj->size, shdr)));
if (_startswith(name, ".sort.")) name += 5;
if ((strcmp(name, ".piro.relo") == 0 ||
_startswith(name, ".piro.relo.")) ||
(strcmp(name, ".data.rel.ro") == 0 ||
_startswith(name, ".data.rel.ro."))) {
sect.kind = kPiroRelo;
} else if (strcmp(name, ".piro.data") == 0 ||
_startswith(name, ".piro.data.")) {
sect.kind = kPiroData;
} else if (strcmp(name, ".piro.bss") == 0 ||
_startswith(name, ".piro.bss.")) {
sect.kind = kPiroBss;
} else if (strcmp(name, ".data") == 0 || _startswith(name, ".data.")) {
sect.kind = kData;
} else if (strcmp(name, ".bss") == 0 || _startswith(name, ".bss.")) {
sect.kind = kBss;
} else {
shdr = GetElfSectionHeaderAddress(obj->elf, obj->size, i);
name = GetElfSectionName(obj->elf, obj->size, shdr);
if (shdr->sh_type == SHT_NULL) {
sect.kind = kUndef;
} else if (shdr->sh_type == SHT_NOBITS) {
sect.kind = kBss;
} else if (shdr->sh_type == SHT_PROGBITS &&
!(shdr->sh_flags & SHF_EXECINSTR)) {
sect.kind = kData;
} else if (shdr->sh_type == SHT_PROGBITS &&
(shdr->sh_flags & SHF_EXECINSTR)) {
if (strcmp(name, ".privileged")) {
sect.kind = kText;
} else {
sect.kind = kPrivilegedText;
}
} else {
sect.kind = kUndef; /* should always and only be section #0 */
sect.kind = kOther;
}
CHECK_NE(-1, append(&obj->sections, &sect));
sect.name = concat(&pkg->strings, name, strlen(name) + 1);
append(&pkg->sections, &sect);
++obj->section_count;
}
}
enum SectionKind ClassifySection(struct Object *obj, uint8_t type,
Elf64_Section shndx) {
static enum SectionKind ClassifySection(struct Package *pkg, struct Object *obj,
uint8_t type, Elf64_Section shndx) {
if (shndx == SHN_ABS) return kOther;
if (type == STT_COMMON) return kBss;
if (!obj->sections.i) return kText;
return obj->sections.p[min(max(0, shndx), obj->sections.i - 1)].kind;
return pkg->sections.p[obj->section_offset + shndx].kind;
}
void LoadSymbols(struct Package *pkg, uint32_t object) {
static void LoadSymbols(struct Package *pkg, uint32_t object) {
Elf64_Xword i;
const char *name;
struct Object *obj;
@ -269,57 +434,104 @@ void LoadSymbols(struct Package *pkg, uint32_t object) {
obj = &pkg->objects.p[object];
symbol.object = object;
for (i = 0; i < obj->symcount; ++i) {
symbol.section = obj->section_offset + obj->syms[i].st_shndx;
symbol.bind_ = ELF64_ST_BIND(obj->syms[i].st_info);
symbol.type = ELF64_ST_TYPE(obj->syms[i].st_info);
if (symbol.bind_ != STB_LOCAL &&
(symbol.type == STT_OBJECT || symbol.type == STT_FUNC ||
symbol.type == STT_COMMON || symbol.type == STT_NOTYPE)) {
name = GetElfString(obj->elf, obj->size, obj->strs, obj->syms[i].st_name);
DEBUGF("%s", name);
if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") != 0) {
symbol.kind = ClassifySection(obj, symbol.type, obj->syms[i].st_shndx);
CHECK_NE(-1,
(symbol.name = concat(&pkg->strings, name, strlen(name) + 1)));
CHECK_NE(-1,
append(symbol.kind != kUndef ? &pkg->symbols : &pkg->undefs,
&symbol));
if (strcmp(name, "_GLOBAL_OFFSET_TABLE_")) {
symbol.kind =
ClassifySection(pkg, obj, symbol.type, obj->syms[i].st_shndx);
symbol.name = concat(&pkg->strings, name, strlen(name) + 1);
append(symbol.kind != kUndef ? &pkg->symbols : &pkg->undefs, &symbol);
}
}
}
}
void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot,
int flags) {
static Elf64_Shdr *FindElfSectionByName(Elf64_Ehdr *elf, size_t esize,
const char *name) {
long i;
Elf64_Shdr *shdr;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (!strcmp(GetElfSectionName(elf, esize, shdr), name)) {
return shdr;
}
}
return 0;
}
static void LoadPriviligedRefsToUndefs(struct Package *pkg,
struct Object *obj) {
long x;
struct Rela r;
const char *s;
Elf64_Shdr *shdr;
Elf64_Rela *rela, *erela;
if ((shdr = FindElfSectionByName(obj->elf, obj->size, ".rela.privileged"))) {
rela = GetElfSectionAddress(obj->elf, obj->size, shdr);
erela = rela + shdr->sh_size / sizeof(*rela);
for (; rela < erela; ++rela) {
if (!ELF64_R_TYPE(rela->r_info)) continue;
if (!(x = ELF64_R_SYM(rela->r_info))) continue;
if (obj->syms[x].st_shndx) continue; // symbol is defined
if (ELF64_ST_BIND(obj->syms[x].st_info) != STB_WEAK &&
ELF64_ST_BIND(obj->syms[x].st_info) != STB_GLOBAL) {
Print(2, "warning: undefined symbol not global\n", NULL);
continue;
}
r.symbol_name = strdup(
GetElfString(obj->elf, obj->size, obj->strs, obj->syms[x].st_name));
r.object_path = strdup(pkg->strings.p + obj->path);
append(&prtu, &r);
}
}
}
static void OpenObject(struct Package *pkg, struct Object *obj, int oid) {
int fd;
struct stat st;
CHECK_NE(-1, (fd = open(&pkg->strings.p[obj->path], (obj->mode = mode))),
"path=%`'s", &pkg->strings.p[obj->path]);
CHECK_NE(-1, fstat(fd, &st));
CHECK_NE(
MAP_FAILED,
(obj->elf = mmap(NULL, (obj->size = st.st_size), prot, flags, fd, 0)),
"path=%`'s", &pkg->strings.p[obj->path]);
CHECK_NE(-1, close(fd));
CHECK(IsElf64Binary(obj->elf, obj->size), "path=%`'s",
&pkg->strings.p[obj->path]);
CHECK_NOTNULL((obj->strs = GetElfStringTable(obj->elf, obj->size)), "on %s",
&pkg->strings.p[obj->path]);
CHECK_NOTNULL(
(obj->syms = GetElfSymbolTable(obj->elf, obj->size, &obj->symcount)));
CHECK_NE(0, obj->symcount);
IndexSections(obj);
const char *path;
path = pkg->strings.p + obj->path;
if ((fd = open(path, O_RDONLY)) == -1) {
SysExit(path, "open");
}
if ((obj->size = lseek(fd, 0, SEEK_END)) == -1) {
SysExit(path, "lseek");
}
if ((obj->elf = mmap(0, obj->size, PROT_READ, MAP_SHARED, fd, 0)) ==
MAP_FAILED) {
SysExit(path, "mmap");
}
close(fd);
if (!IsElf64Binary(obj->elf, obj->size)) {
Print(2, path, ": not an elf64 binary\n", NULL);
exit(1);
}
if (!(obj->strs = GetElfStringTable(obj->elf, obj->size))) {
Print(2, path, ": missing elf string table\n", NULL);
exit(1);
}
if (!(obj->syms = GetElfSymbolTable(obj->elf, obj->size, &obj->symcount))) {
Print(2, path, ": missing elf symbol table\n", NULL);
exit(1);
}
IndexSections(pkg, obj);
LoadPriviligedRefsToUndefs(pkg, obj);
}
void CloseObject(struct Object *obj) {
CHECK_NE(-1, munmap(obj->elf, obj->size));
static void CloseObject(struct Object *obj) {
if (munmap(obj->elf, obj->size)) notpossible;
}
void LoadObjects(struct Package *pkg) {
static void LoadObjects(struct Package *pkg) {
size_t i;
struct Object *obj;
for (i = 0; i < pkg->objects.i; ++i) {
obj = pkg->objects.p + i;
OpenObject(pkg, obj, O_RDONLY, PROT_READ, MAP_SHARED);
OpenObject(pkg, obj, i);
LoadSymbols(pkg, i);
CloseObject(obj);
}
@ -327,7 +539,7 @@ void LoadObjects(struct Package *pkg) {
(void *)CompareSymbolName, pkg->strings.p);
}
struct Symbol *BisectSymbol(struct Package *pkg, const char *name) {
static struct Symbol *BisectSymbol(struct Package *pkg, const char *name) {
int c;
long m, l, r;
l = 0;
@ -346,9 +558,9 @@ struct Symbol *BisectSymbol(struct Package *pkg, const char *name) {
return NULL;
}
bool FindSymbol(const char *name, struct Package *pkg,
struct Packages *directdeps, struct Package **out_pkg,
struct Symbol **out_sym) {
static bool FindSymbol(const char *name, struct Package *pkg,
struct Packages *directdeps, struct Package **out_pkg,
struct Symbol **out_sym) {
size_t i, j;
struct Symbol *sym;
if ((sym = BisectSymbol(pkg, name))) {
@ -366,7 +578,7 @@ bool FindSymbol(const char *name, struct Package *pkg,
return false;
}
void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
static void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
size_t i, j;
struct Package *dep;
struct Symbol *undef;
@ -374,15 +586,13 @@ void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
undef = &pkg->undefs.p[i];
if (undef->bind_ == STB_WEAK) continue;
if (!FindSymbol(pkg->strings.p + undef->name, pkg, deps, NULL, NULL)) {
fprintf(stderr, "%s: %`'s (%s) %s %s\n", "error",
pkg->strings.p + undef->name,
pkg->strings.p + pkg->objects.p[undef->object].path,
"not defined by direct deps of", pkg->strings.p + pkg->path);
Print(2, pkg->strings.p + pkg->path, ": undefined symbol '",
pkg->strings.p + undef->name, "' (",
pkg->strings.p + pkg->objects.p[undef->object].path,
") not defined by direct dependencies:\n", NULL);
for (j = 0; j < deps->i; ++j) {
dep = deps->p[j];
fputc('\t', stderr);
fputs(dep->strings.p + dep->path, stderr);
fputc('\n', stderr);
Print(2, "\t", dep->strings.p + dep->path, "\n", NULL);
}
exit(1);
}
@ -391,43 +601,53 @@ void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
bzero(&pkg->undefs, sizeof(pkg->undefs));
}
forceinline bool IsRipRelativeModrm(uint8_t modrm) {
return (modrm & 0b11000111) == 0b00000101;
static void CheckYourPrivilege(struct Package *pkg, struct Packages *deps) {
int i, j, o, f;
const char *name;
struct Symbol *sym;
struct Package *dep;
for (f = i = 0; i < prtu.i; ++i) {
name = prtu.p[i].symbol_name;
if (FindSymbol(name, pkg, deps, &dep, &sym) &&
dep->sections.p[sym->section].kind == kText) {
Print(2, prtu.p[i].object_path,
": privileged code referenced unprivileged symbol '", name,
"' in section '",
dep->strings.p + dep->sections.p[sym->section].name, "'\n", NULL);
++f;
}
}
if (f) exit(1);
}
forceinline uint8_t ChangeRipToRbx(uint8_t modrm) {
return (modrm & 0b00111000) | 0b10000011;
static bool IsSymbolDirectlyReachable(struct Package *pkg,
struct Packages *deps,
const char *symbol) {
return FindSymbol(symbol, pkg, deps, 0, 0);
}
bool IsSymbolDirectlyReachable(struct Package *pkg, struct Packages *deps,
const char *symbol) {
return FindSymbol(symbol, pkg, deps, NULL, NULL);
}
void Package(int argc, char *argv[], struct Package *pkg,
struct Packages *deps) {
static void Package(int argc, char *argv[], struct Package *pkg,
struct Packages *deps) {
size_t i, j;
GetOpts(pkg, deps, argc, argv);
LoadObjects(pkg);
CheckStrictDeps(pkg, deps);
CheckYourPrivilege(pkg, deps);
WritePackage(pkg);
for (i = 0; i < deps->i; ++i) {
CHECK_NE(-1, munmap(deps->p[i]->addr, deps->p[i]->size));
if (munmap(deps->p[i]->addr, deps->p[i]->size)) notpossible;
}
for (i = 0; i < pkg->objects.i; ++i) {
free(pkg->objects.p[i].sections.p);
}
free(pkg->strings.p);
free(pkg->objects.p);
free(pkg->symbols.p);
free(deps->p);
}
int main(int argc, char *argv[]) {
struct Package pkg;
struct Packages deps;
if (argc == 2 && !strcmp(argv[1], "-n")) exit(0);
if (IsModeDbg()) ShowCrashReports();
if (argc == 2 && !strcmp(argv[1], "-n")) {
exit(0);
}
if (!IsOptimized()) {
ShowCrashReports();
}
bzero(&pkg, sizeof(pkg));
bzero(&deps, sizeof(deps));
Package(argc, argv, &pkg, &deps);

View file

@ -1052,7 +1052,9 @@ wontreturn void StraceMain(int argc, char *argv[]) {
exit(1);
}
if (IsModeDbg()) ShowCrashReports();
if (!IsOptimized()) {
ShowCrashReports();
}
if (argc < 2) {
kprintf("Usage: %s PROGRAM [ARGS...]%n", argv[0]);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/winsize.h"

View file

@ -25,6 +25,7 @@
(require 'ld-script)
(require 'make-mode)
(setq cosmo-dbg-mode "zero")
(setq c-doc-comment-style 'javadown)
(add-to-list 'auto-mode-alist '("\\.x$" . c-mode)) ;; -aux-info
@ -162,13 +163,13 @@
(cond ((eq arg 1) "tiny")
((eq arg 2) "opt")
((eq arg 3) "rel")
((eq arg 4) "dbg")
((eq arg 4) cosmo-dbg-mode)
((eq arg 5) "")
((eq arg 6) "llvm")
((eq arg 7) "aarch64")
((eq arg 8) "aarch64-tiny")
(default default)
((cosmo-intest) "dbg")
((cosmo-intest) cosmo-dbg-mode)
(t "fastbuild")))
(defun cosmo--make-suffix (arg)
@ -684,7 +685,7 @@
(let* ((this (or (buffer-file-name) dired-directory))
(root (locate-dominating-file this "Makefile")))
(when root
(let* ((mode (cosmo--make-mode arg "dbg"))
(let* ((mode (cosmo--make-mode arg cosmo-dbg-mode))
(name (file-relative-name this root))
(next (file-name-sans-extension name))
(exec (format "o/%s/%s.com.dbg" mode next))

View file

@ -249,6 +249,7 @@ o/$(MODE)/tool/net/redbean-demo.com: \
o/$(MODE)/tool/net/redbean-static.com.dbg: \
$(TOOL_NET_DEPS) \
$(TOOL_NET_REDBEAN_LUA_MODULES) \
o/$(MODE)/tool/net/redbean-static.o \
o/$(MODE)/tool/net/net.pkg \
$(CRT) \
@ -300,6 +301,7 @@ o/$(MODE)/tool/net/redbean-unsecure.com: \
o/$(MODE)/tool/net/redbean-original.com.dbg: \
$(TOOL_NET_DEPS) \
$(TOOL_NET_REDBEAN_LUA_MODULES) \
o/$(MODE)/tool/net/redbean-original.o \
o/$(MODE)/tool/net/net.pkg \
$(CRT) \