From 69d173ef01487d24ec0cb8bb673173e79f94f6a3 Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Wed, 18 Dec 2024 18:49:42 -0700 Subject: [PATCH 1/4] [libc] Enhance debugging output for amalloc and dmalloc --- libc/malloc/amalloc.c | 48 ++++++++++++++++++-------------------- libc/malloc/v7malloc.c | 52 +++++++++++++++++++----------------------- 2 files changed, 45 insertions(+), 55 deletions(-) diff --git a/libc/malloc/amalloc.c b/libc/malloc/amalloc.c index 201008f3a..c8579d4f2 100644 --- a/libc/malloc/amalloc.c +++ b/libc/malloc/amalloc.c @@ -17,7 +17,7 @@ #include #include #include -#define DEBUG 2 /* =1 heap checking asserts, =2 sysctl, =3 show heap */ +#define DEBUG 1 /* =1 use sysctl, =2 debug output, =3 show heap */ /* C storage allocator * circular first-fit strategy @@ -41,7 +41,7 @@ #define ALIGN int #define NALIGN 1 #define BUSY 1 -#define BLOCK 34 /* min+WORD amount to sbrk */ +#define BLOCK 34 /* min+WORD amount to sbrk (was 514) */ #define MINALLOC 14 /* minimum actual malloc size */ #define GRANULE 0 /* sbrk granularity */ @@ -71,21 +71,17 @@ static NPTR alloct; /*arena top*/ static NPTR allocx; /*for benefit of realloc*/ #if DEBUG -#define ASSERT(p) if(!(p))malloc_assert_fail(#p);else {} -static void malloc_assert_fail(char *s); -static int malloc_check_heap(void); -#else -#define ASSERT(p) -#endif - -#if DEBUG > 1 +#define ASSERT(p) if(!(p))malloc_assert_fail(#p,__LINE__);else {} #define debug(...) do { if (debug_level > 1) __dprintf(__VA_ARGS__); } while (0) #define debug2(...) do { if (debug_level > 2) __dprintf(__VA_ARGS__); } while (0) -int __dprintf(const char *fmt, ...); -static void malloc_show_heap(void); static int debug_level = DEBUG; +static void malloc_assert_fail(char *s, int); +static void malloc_show_heap(void); +static int malloc_check_heap(void); #else +#define ASSERT(p) #define debug(...) +#define debug2(...) #define malloc_show_heap() #endif @@ -96,7 +92,7 @@ int __amalloc_add_heap(char __far *start, size_t size) allocs = (FPTR)start; allocseg = FP_SEG(start); allocsize = size / sizeof(union store); - debug("Adding %04x %04x size %d DS %04x %04x\n", start, size, &size); + debug("Adding SEG %04x size %d DS %04x\n", FP_SEG(start), size, FP_SEG(&size)); allocs[0].ptr = setbusy(&allocs[1]); allocs[1].ptr = (NPTR)&allocs[allocsize-2]; @@ -113,11 +109,11 @@ __amalloc(size_t nbytes) NPTR p, q; unsigned int nw, temp; -#if DEBUG == 2 +#if DEBUG == 1 sysctl(CTL_GET, "malloc.debug", &debug_level); #endif - debug("(%d)malloc(%u) ", getpid(), nbytes); + debug("(%d)malloc(%5u) ", getpid(), nbytes); if (!allocs) return NULL; errno = 0; @@ -147,7 +143,7 @@ __amalloc(size_t nbytes) if (debug_level > 2) malloc_show_heap(); ASSERT(q>p); ASSERT(q 2) malloc_show_heap(); - debug("sbrk(%d) ", temp*WORD); + debug2("sbrk(%d) ", temp*WORD); #if 0 /* not required and slow, initial break always even */ q = (NPTR)sbrk(0); if((INT)q & (sizeof(union store) - 1)) @@ -208,7 +204,7 @@ __amalloc(size_t nbytes) if(q!=alloct+1) /* mark any gap as permanently allocated*/ next(alloct) = setbusy(next(alloct)); alloct = next(q) = q+temp-1; - debug("(TOTAL %u) ", + debug2("(TOTAL %u) ", sizeof(union store) + (clearbusy(alloct) - clearbusy(allocs[allocsize-1].ptr)) * sizeof(union store)); next(alloct) = setbusy(allocs); @@ -222,7 +218,7 @@ __amalloc(size_t nbytes) next(allocp) = next(p); } next(p) = setbusy(allocp); - debug("= %04x\n", (unsigned)p); + debug2("= %04x\n", (unsigned)p); malloc_show_heap(); return MK_FPTR(allocseg, p+1); } @@ -236,8 +232,8 @@ __afree(void *ptr) if (p == NULL) return; - debug("(%d) free(%d) = %04x\n", getpid(), - (unsigned)(next(p-1) - p) * sizeof(union store), p-1); + debug("(%d) free(%5u) ", getpid(), (unsigned)(next(p-1) - p) * sizeof(union store)); + debug2("= %04x\n", p-1); ASSERT(FP_SEG(ptr)==allocseg); ASSERT(p>clearbusy(allocs[allocsize-1].ptr)&&p<=alloct); ASSERT(malloc_check_heap()); @@ -307,9 +303,9 @@ __arealloc(void *ptr, size_t nbytes) #endif #if DEBUG -static void malloc_assert_fail(char *s) +static void malloc_assert_fail(char *s, int line) { - __dprintf("malloc assert fail: %s\n", s); + __dprintf("amalloc assert fail: %s (line %d)\n", s, line); abort(); } @@ -330,15 +326,14 @@ malloc_check_heap(void) ASSERT(p==alloct); return((x==1)|(p==allocp)); } -#endif -#if DEBUG > 1 static void malloc_show_heap(void) { NPTR p; int n = 1; unsigned int size, alloc = 0, free = 0; + static unsigned int maxalloc; debug2("--- heap size ---\n"); malloc_check_heap(); @@ -357,7 +352,8 @@ malloc_show_heap(void) debug2("\n"); } alloc += sizeof(union store); + if (alloc > maxalloc) maxalloc = alloc; debug2("%2d: %04x %4u (top) ", n, (unsigned)alloct, 2); - debug("alloc %u, free %u, total %u\n", alloc, free, alloc+free); + debug("alloc %5u, free %5u, arena %5u/%5u\n", alloc, free, maxalloc, alloc+free); } #endif diff --git a/libc/malloc/v7malloc.c b/libc/malloc/v7malloc.c index 4430c3d5c..cdf88775f 100644 --- a/libc/malloc/v7malloc.c +++ b/libc/malloc/v7malloc.c @@ -9,10 +9,11 @@ * Use near heap pointers to work with OpenWatcom large model * Combine free areas at heap start before allocating from free area at end of heap */ +#include #include #include -#include -#define DEBUG 2 /* =1 heap checking asserts, =2 sysctl, =3 show heap */ +#include +#define DEBUG 1 /* =1 use sysctl, =2 debug output, =3 show heap */ /* C storage allocator * circular first-fit strategy @@ -36,8 +37,7 @@ #define ALIGN int #define NALIGN 1 #define BUSY 1 -//#define BLOCK 514 /* min+WORD amount to sbrk */ -#define BLOCK 34 /* min+WORD amount to sbrk */ +#define BLOCK 34 /* min+WORD amount to sbrk (was 514) */ #define MINALLOC 14 /* minimum actual malloc size */ #define GRANULE 0 /* sbrk granularity */ @@ -60,23 +60,17 @@ static NPTR alloct; /*arena top*/ static NPTR allocx; /*for benefit of realloc*/ #if DEBUG -#include -#include -#define ASSERT(p) if(!(p))malloc_assert_fail(#p);else {} -static void malloc_assert_fail(char *s); -static int malloc_check_heap(void); -#else -#define ASSERT(p) -#endif - -#if DEBUG > 1 +#define ASSERT(p) if(!(p))malloc_assert_fail(#p,__LINE__);else {} #define debug(...) do { if (debug_level > 1) __dprintf(__VA_ARGS__); } while (0) #define debug2(...) do { if (debug_level > 2) __dprintf(__VA_ARGS__); } while (0) -int __dprintf(const char *fmt, ...); -static void malloc_show_heap(void); static int debug_level = DEBUG; +static void malloc_assert_fail(char *s, int); +static void malloc_show_heap(void); +static int malloc_check_heap(void); #else +#define ASSERT(p) #define debug(...) +#define debug2(...) #define malloc_show_heap() #endif @@ -86,7 +80,7 @@ __dmalloc(size_t nbytes) NPTR p, q; unsigned int nw, temp; -#if DEBUG == 2 +#if DEBUG == 1 sysctl(CTL_GET, "malloc.debug", &debug_level); #endif if (allocs[0].ptr == 0) { /*first time*/ @@ -100,7 +94,7 @@ __dmalloc(size_t nbytes) allocp = (NPTR)&allocs[0]; } - debug("(%d)malloc(%u) ", getpid(), nbytes); + debug("(%d)malloc(%5u) ", getpid(), nbytes); errno = 0; if (nbytes == 0) { debug(" (malloc 0) = NULL\n"); @@ -128,7 +122,7 @@ __dmalloc(size_t nbytes) if (debug_level > 2) malloc_show_heap(); ASSERT(q>p); ASSERT(q 2) malloc_show_heap(); - debug("sbrk(%d) ", temp*WORD); + debug2("sbrk(%d) ", temp*WORD); #if 0 /* not required and slow, initial break always even */ q = (NPTR)sbrk(0); if((INT)q & (sizeof(union store) - 1)) @@ -189,7 +183,7 @@ __dmalloc(size_t nbytes) if(q!=alloct+1) /* mark any gap as permanently allocated*/ next(alloct) = setbusy(next(alloct)); alloct = next(q) = q+temp-1; - debug("(TOTAL %u) ", + debug2("(TOTAL %u) ", sizeof(union store) + (clearbusy(alloct) - clearbusy(allocs[SIZE-1].ptr)) * sizeof(union store)); next(alloct) = setbusy(allocs); @@ -203,7 +197,7 @@ __dmalloc(size_t nbytes) next(allocp) = next(p); } next(p) = setbusy(allocp); - debug("= %04x\n", (unsigned)p); + debug2("= %04x\n", (unsigned)p); malloc_show_heap(); return((void *)(p+1)); } @@ -217,8 +211,8 @@ __dfree(void *ptr) if (p == NULL) return; - debug("(%d) free(%d) = %04x\n", getpid(), - (unsigned)(next(p-1) - p) * sizeof(union store), p-1); + debug("(%d) free(%5u) ", getpid(), (unsigned)(next(p-1) - p) * sizeof(union store)); + debug2("= %04x\n", p-1); ASSERT(p>clearbusy(allocs[SIZE-1].ptr)&&p<=alloct); ASSERT(malloc_check_heap()); allocp = --p; @@ -284,9 +278,9 @@ __drealloc(void *ptr, size_t nbytes) } #if DEBUG -static void malloc_assert_fail(char *s) +static void malloc_assert_fail(char *s, int line) { - __dprintf("malloc assert fail: %s\n", s); + __dprintf("dmalloc assert fail: %s (line %d)\n", s, line); abort(); } @@ -305,15 +299,14 @@ malloc_check_heap(void) ASSERT(p==alloct); return((x==1)|(p==allocp)); } -#endif -#if DEBUG > 1 static void malloc_show_heap(void) { NPTR p; int n = 1; unsigned int size, alloc = 0, free = 0; + static unsigned int maxalloc; debug2("--- heap size ---\n"); malloc_check_heap(); @@ -335,7 +328,8 @@ malloc_show_heap(void) debug2("\n"); } alloc += sizeof(union store); + if (alloc > maxalloc) maxalloc = alloc; debug2("%2d: %04x %4u (top) ", n, (unsigned)alloct, 2); - debug("alloc %u, free %u, total %u\n", alloc, free, alloc+free); + debug("alloc %5u, free %5u, arena %5u/%5u\n", alloc, free, maxalloc, alloc+free); } #endif From 9890f0e673f9d3c7d1bd74338725e90c60bf428e Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Wed, 18 Dec 2024 20:07:05 -0700 Subject: [PATCH 2/4] Allow redirection of __dprintf output from console --- libc/malloc/amalloc.c | 3 ++- libc/malloc/dprintf.c | 8 ++++++-- libc/malloc/v7malloc.c | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libc/malloc/amalloc.c b/libc/malloc/amalloc.c index c8579d4f2..2cd8001e9 100644 --- a/libc/malloc/amalloc.c +++ b/libc/malloc/amalloc.c @@ -70,11 +70,11 @@ static NPTR allocp; /*search ptr*/ static NPTR alloct; /*arena top*/ static NPTR allocx; /*for benefit of realloc*/ +static int debug_level = DEBUG; #if DEBUG #define ASSERT(p) if(!(p))malloc_assert_fail(#p,__LINE__);else {} #define debug(...) do { if (debug_level > 1) __dprintf(__VA_ARGS__); } while (0) #define debug2(...) do { if (debug_level > 2) __dprintf(__VA_ARGS__); } while (0) -static int debug_level = DEBUG; static void malloc_assert_fail(char *s, int); static void malloc_show_heap(void); static int malloc_check_heap(void); @@ -335,6 +335,7 @@ malloc_show_heap(void) unsigned int size, alloc = 0, free = 0; static unsigned int maxalloc; + if (!debug_level) return; debug2("--- heap size ---\n"); malloc_check_heap(); for(p = (NPTR)&allocs[0]; clearbusy(next(p)) > p; p=clearbusy(next(p))) { diff --git a/libc/malloc/dprintf.c b/libc/malloc/dprintf.c index fbd7e9ba4..eda959cff 100644 --- a/libc/malloc/dprintf.c +++ b/libc/malloc/dprintf.c @@ -44,8 +44,12 @@ int __dprintf(const char *fmt, ...) char b[80]; static int fd = -1; - if (fd < 0) - fd = open(_PATH_CONSOLE, O_WRONLY); + if (fd < 0) { + if (!isatty(STDERR_FILENO)) + fd = STDERR_FILENO; + else + fd = open(_PATH_CONSOLE, O_WRONLY); + } va_start(va, fmt); for (n = 0; *fmt; fmt++) { if (*fmt == '%') { diff --git a/libc/malloc/v7malloc.c b/libc/malloc/v7malloc.c index cdf88775f..04842ffff 100644 --- a/libc/malloc/v7malloc.c +++ b/libc/malloc/v7malloc.c @@ -59,11 +59,11 @@ static NPTR allocp; /*search ptr*/ static NPTR alloct; /*arena top*/ static NPTR allocx; /*for benefit of realloc*/ +static int debug_level = DEBUG; #if DEBUG #define ASSERT(p) if(!(p))malloc_assert_fail(#p,__LINE__);else {} #define debug(...) do { if (debug_level > 1) __dprintf(__VA_ARGS__); } while (0) #define debug2(...) do { if (debug_level > 2) __dprintf(__VA_ARGS__); } while (0) -static int debug_level = DEBUG; static void malloc_assert_fail(char *s, int); static void malloc_show_heap(void); static int malloc_check_heap(void); @@ -308,6 +308,7 @@ malloc_show_heap(void) unsigned int size, alloc = 0, free = 0; static unsigned int maxalloc; + if (!debug_level) return; debug2("--- heap size ---\n"); malloc_check_heap(); for(p = (NPTR)&allocs[0]; clearbusy(next(p)) > p; p=clearbusy(next(p))) { From 86dc6f84f2b05c7c12188a3a42e6ac896c26c783 Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Wed, 18 Dec 2024 21:00:39 -0700 Subject: [PATCH 3/4] Add fmemalloc debug options --- libc/malloc/Makefile | 1 - libc/malloc/amalloc.c | 2 +- libc/malloc/dprintf.c | 3 +++ libc/malloc/fmemalloc.c | 47 +++++++++++++++++++++++++++++++++++++---- libc/malloc/fmemfree.c | 7 ------ libc/malloc/v7malloc.c | 2 +- 6 files changed, 48 insertions(+), 14 deletions(-) delete mode 100644 libc/malloc/fmemfree.c diff --git a/libc/malloc/Makefile b/libc/malloc/Makefile index 5e417add6..23a5fdc6a 100644 --- a/libc/malloc/Makefile +++ b/libc/malloc/Makefile @@ -37,7 +37,6 @@ OBJS = \ brk.o \ sbrk.o \ fmemalloc.o \ - fmemfree.o \ dprintf.o \ # default and debug mallocs available for ia16 and OWC diff --git a/libc/malloc/amalloc.c b/libc/malloc/amalloc.c index 2cd8001e9..47bab2875 100644 --- a/libc/malloc/amalloc.c +++ b/libc/malloc/amalloc.c @@ -9,7 +9,7 @@ * Enhancements: * Minimum BLOCK allocate from kernel sbrk, > BLOCK allocates requested size * Much improved size and heap overflow handling with errno returns - * Full heap integrity checking and reporting with DEBUG options + * Full heap integrity checking and reporting with debug options * Use near heap pointers to work with OpenWatcom large model * Combine free areas at heap start before allocating from free area at end of heap */ diff --git a/libc/malloc/dprintf.c b/libc/malloc/dprintf.c index eda959cff..c83fd1050 100644 --- a/libc/malloc/dprintf.c +++ b/libc/malloc/dprintf.c @@ -59,7 +59,10 @@ int __dprintf(const char *fmt, ...) width = width * 10 + *fmt - '0'; fmt++; } + again: switch (*fmt) { + case 'l': + fmt++; goto again; case 's': p = va_arg(va, char *); goto outstr; diff --git a/libc/malloc/fmemalloc.c b/libc/malloc/fmemalloc.c index 840d47787..27bb223e4 100644 --- a/libc/malloc/fmemalloc.c +++ b/libc/malloc/fmemalloc.c @@ -1,14 +1,53 @@ #include +#include +#include +#include +/* fmemalloc/fmemfree - allocate/free from main memory */ -#define _MK_FP(seg,off) ((void __far *)((((unsigned long)(seg)) << 16) | (off))) +#define DEBUG 1 /* =1 use sysctl, =2 debug output */ + +#if DEBUG +#define debug(...) do { if (debug_level > 1) __dprintf(__VA_ARGS__); } while (0) +static int debug_level = DEBUG; +static unsigned long total; +static unsigned long maxsize; +#else +#define debug(...) +#endif + +#define FP_SEG(fp) ((unsigned)((unsigned long)(void __far *)(fp) >> 16)) +#define FP_OFF(fp) ((unsigned)(unsigned long)(void __far *)(fp)) +#define MK_FP(seg,off) ((void __far *)((((unsigned long)(seg)) << 16) | \ + ((unsigned int)(off)))) -/* alloc from main memory */ void __far *fmemalloc(unsigned long size) { unsigned short seg; unsigned int paras = (unsigned int)((size + 15) >> 4); - if (_fmemalloc(paras, &seg)) +#if DEBUG == 1 + sysctl(CTL_GET, "malloc.debug", &debug_level); +#endif + debug("(%d)FMEMALLOC(%5lu) ", getpid(), size); + if (_fmemalloc(paras, &seg)) { + debug("= FAIL\n"); return 0; - return _MK_FP(seg, 0); + } +#if DEBUG + total += size; + if (size > maxsize) maxsize = size; + debug("total %lu, maxsize %lu\n", (unsigned)total, (unsigned)maxsize); +#endif + return MK_FP(seg, 0); +} + +int fmemfree(void __far *ptr) +{ + debug("(%d) fmemfree()\n", getpid()); // FIXME get size of allocation + if (FP_OFF(ptr)) { + debug(" FAIL (bad pointer)\n"); // FIXME convert to ASSERT + errno = EINVAL; + return -1; + } + return _fmemfree(FP_SEG(ptr)); } diff --git a/libc/malloc/fmemfree.c b/libc/malloc/fmemfree.c deleted file mode 100644 index 05ad3c90e..000000000 --- a/libc/malloc/fmemfree.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -/* free from main memory */ -int fmemfree(void __far *ptr) -{ - return _fmemfree((unsigned short)((unsigned long)ptr >> 16)); -} diff --git a/libc/malloc/v7malloc.c b/libc/malloc/v7malloc.c index 04842ffff..dfdfa6979 100644 --- a/libc/malloc/v7malloc.c +++ b/libc/malloc/v7malloc.c @@ -5,7 +5,7 @@ * Enhancements: * Minimum BLOCK allocate from kernel sbrk, > BLOCK allocates requested size * Much improved size and heap overflow handling with errno returns - * Full heap integrity checking and reporting with DEBUG options + * Full heap integrity checking and reporting with debug options * Use near heap pointers to work with OpenWatcom large model * Combine free areas at heap start before allocating from free area at end of heap */ From 71bafc52d22fd828b4230e3ec38a95d83b1b8368 Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Wed, 18 Dec 2024 21:26:34 -0700 Subject: [PATCH 4/4] Add long conversion to __dprintf --- libc/malloc/dprintf.c | 29 ++++++++++++++++++++++------- libc/malloc/fmemalloc.c | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/libc/malloc/dprintf.c b/libc/malloc/dprintf.c index c83fd1050..1a2482fe4 100644 --- a/libc/malloc/dprintf.c +++ b/libc/malloc/dprintf.c @@ -4,16 +4,21 @@ #include #include -static char *uitostr(unsigned int val, int radix, int width) +static char *fmtultostr(unsigned long val, int radix, int width) { - static char buf[6]; + static char buf[34]; char *p = buf + sizeof(buf) - 1; unsigned int c; *p = '\0'; do { +#ifdef _M_I86 + c = radix; + val = __divmod(val, &c); +#else c = val % radix; val = val / radix; +#endif if (c > 9) *--p = 'a' - 10 + c; else @@ -28,19 +33,22 @@ static char *uitostr(unsigned int val, int radix, int width) /* * Very tiny printf to console. * Supports: - * %{0-9} width + * %{0-9} field width + * %l{u,d,x,p} * %u unsigned decimal * %d decimal (positive numbers only) - * %p zero-fill hexadecimal width 4 + * %p pointer (zero-filled hexadecimal) * %x hexadecimal * %s string */ int __dprintf(const char *fmt, ...) { unsigned int n; + unsigned long val; int radix, width; char *p; va_list va; + int lval; char b[80]; static int fd = -1; @@ -55,6 +63,7 @@ int __dprintf(const char *fmt, ...) if (*fmt == '%') { ++fmt; width = 0; + lval = 0; while (*fmt >= '0' && *fmt <= '9') { width = width * 10 + *fmt - '0'; fmt++; @@ -62,12 +71,17 @@ int __dprintf(const char *fmt, ...) again: switch (*fmt) { case 'l': - fmt++; goto again; + lval = 1; + fmt++; + goto again; case 's': p = va_arg(va, char *); goto outstr; case 'p': - width = 4; + if (sizeof(char *) == sizeof(unsigned long)) + lval = 1; + width = lval? 8: 4; + /* fall through */ case 'x': radix = 16; goto convert; @@ -75,7 +89,8 @@ int __dprintf(const char *fmt, ...) case 'u': radix = 10; convert: - p = uitostr(va_arg(va, unsigned int), radix, width); + val = lval? va_arg(va, unsigned long): va_arg(va, unsigned int); + p = fmtultostr(val, radix, width); outstr: while (*p && n < sizeof(b)) b[n++] = *p++; diff --git a/libc/malloc/fmemalloc.c b/libc/malloc/fmemalloc.c index 27bb223e4..78506be1a 100644 --- a/libc/malloc/fmemalloc.c +++ b/libc/malloc/fmemalloc.c @@ -36,7 +36,7 @@ void __far *fmemalloc(unsigned long size) #if DEBUG total += size; if (size > maxsize) maxsize = size; - debug("total %lu, maxsize %lu\n", (unsigned)total, (unsigned)maxsize); + debug("total %lu, maxsize %lu\n", total, maxsize); #endif return MK_FP(seg, 0); }