aboutsummaryrefslogtreecommitdiff
path: root/debug/programs
diff options
context:
space:
mode:
Diffstat (limited to 'debug/programs')
-rw-r--r--debug/programs/checksum.c38
-rw-r--r--debug/programs/debug.c51
-rwxr-xr-xdebug/programs/entry.S132
-rw-r--r--debug/programs/init.c24
-rw-r--r--debug/programs/mprv.S46
-rw-r--r--debug/programs/regs.S57
-rw-r--r--debug/programs/start.S12
-rw-r--r--debug/programs/step.S24
-rw-r--r--debug/programs/tiny-malloc.c600
9 files changed, 984 insertions, 0 deletions
diff --git a/debug/programs/checksum.c b/debug/programs/checksum.c
new file mode 100644
index 0000000..e076f8a
--- /dev/null
+++ b/debug/programs/checksum.c
@@ -0,0 +1,38 @@
+#include <stdint.h>
+
+// CRC code from http://www.hackersdelight.org/hdcodetxt/crc.c.txt
+
+// Reverses (reflects) bits in a 32-bit word.
+unsigned reverse(unsigned x) {
+ x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555);
+ x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333);
+ x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F);
+ x = (x << 24) | ((x & 0xFF00) << 8) |
+ ((x >> 8) & 0xFF00) | (x >> 24);
+ return x;
+}
+
+// ----------------------------- crc32a --------------------------------
+
+/* This is the basic CRC algorithm with no optimizations. It follows the
+logic circuit as closely as possible. */
+
+unsigned int crc32a(uint8_t *message, unsigned int size) {
+ int i, j;
+ unsigned int byte, crc;
+
+ i = 0;
+ crc = 0xFFFFFFFF;
+ while (i < size) {
+ byte = message[i]; // Get next byte.
+ byte = reverse(byte); // 32-bit reversal.
+ for (j = 0; j <= 7; j++) { // Do eight times.
+ if ((int)(crc ^ byte) < 0)
+ crc = (crc << 1) ^ 0x04C11DB7;
+ else crc = crc << 1;
+ byte = byte << 1; // Ready next msg bit.
+ }
+ i = i + 1;
+ }
+ return reverse(~crc);
+}
diff --git a/debug/programs/debug.c b/debug/programs/debug.c
new file mode 100644
index 0000000..20b1cdc
--- /dev/null
+++ b/debug/programs/debug.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+unsigned int crc32a(uint8_t *message, unsigned int size);
+
+void rot13(char *buf)
+{
+ while (*buf) {
+ if ((*buf >= 'a' && *buf <= 'm') ||
+ (*buf >= 'A' && *buf <= 'M')) {
+ *buf += 13;
+ } else if ((*buf >= 'n' && *buf <= 'z') ||
+ (*buf >= 'N' && *buf <= 'Z')) {
+ *buf -= 13;
+ }
+ buf++;
+ }
+}
+
+size_t strlen(const char *buf)
+{
+ int len = 0;
+ while (buf[len])
+ len++;
+ return len;
+}
+
+extern void *__malloc_freelist;
+
+int main()
+{
+ __malloc_freelist = 0;
+
+ volatile int i = 0;
+ int j = 0;
+ char *fox = "The quick brown fox jumps of the lazy dog.";
+ unsigned int checksum = 0;
+
+start:
+ while (i)
+ j++;
+
+ rot13(fox);
+ checksum ^= crc32a(fox, strlen(fox));
+ rot13(fox);
+ checksum ^= crc32a(fox, strlen(fox));
+
+ return checksum;
+}
diff --git a/debug/programs/entry.S b/debug/programs/entry.S
new file mode 100755
index 0000000..80904cd
--- /dev/null
+++ b/debug/programs/entry.S
@@ -0,0 +1,132 @@
+#ifndef ENTRY_S
+#define ENTRY_S
+
+#include "encoding.h"
+
+#define STACK_SIZE 512
+
+#ifdef __riscv64
+# define LREG ld
+# define SREG sd
+# define REGBYTES 8
+#else
+# define LREG lw
+# define SREG sw
+# define REGBYTES 4
+#endif
+
+ .section .text.entry
+ .globl _start
+_start:
+ j handle_reset
+
+nmi_vector:
+ j nmi_vector
+
+trap_vector:
+ j trap_entry
+
+handle_reset:
+ la t0, trap_entry
+ csrw mtvec, t0
+ csrwi mstatus, 0
+ csrwi mideleg, 0
+ csrwi medeleg, 0
+ csrwi mie, 0
+
+ # initialize global pointer
+ la gp, _gp
+
+ # initialize stack pointer
+ la sp, stack_top
+
+ # perform the rest of initialization in C
+ j _init
+
+
+trap_entry:
+ addi sp, sp, -32*REGBYTES
+
+ SREG x1, 1*REGBYTES(sp)
+ SREG x2, 2*REGBYTES(sp)
+ SREG x3, 3*REGBYTES(sp)
+ SREG x4, 4*REGBYTES(sp)
+ SREG x5, 5*REGBYTES(sp)
+ SREG x6, 6*REGBYTES(sp)
+ SREG x7, 7*REGBYTES(sp)
+ SREG x8, 8*REGBYTES(sp)
+ SREG x9, 9*REGBYTES(sp)
+ SREG x10, 10*REGBYTES(sp)
+ SREG x11, 11*REGBYTES(sp)
+ SREG x12, 12*REGBYTES(sp)
+ SREG x13, 13*REGBYTES(sp)
+ SREG x14, 14*REGBYTES(sp)
+ SREG x15, 15*REGBYTES(sp)
+ SREG x16, 16*REGBYTES(sp)
+ SREG x17, 17*REGBYTES(sp)
+ SREG x18, 18*REGBYTES(sp)
+ SREG x19, 19*REGBYTES(sp)
+ SREG x20, 20*REGBYTES(sp)
+ SREG x21, 21*REGBYTES(sp)
+ SREG x22, 22*REGBYTES(sp)
+ SREG x23, 23*REGBYTES(sp)
+ SREG x24, 24*REGBYTES(sp)
+ SREG x25, 25*REGBYTES(sp)
+ SREG x26, 26*REGBYTES(sp)
+ SREG x27, 27*REGBYTES(sp)
+ SREG x28, 28*REGBYTES(sp)
+ SREG x29, 29*REGBYTES(sp)
+ SREG x30, 30*REGBYTES(sp)
+ SREG x31, 31*REGBYTES(sp)
+
+ csrr a0, mcause
+ csrr a1, mepc
+ mv a2, sp
+ jal handle_trap
+ csrw mepc, a0
+
+ # Remain in M-mode after mret
+ li t0, MSTATUS_MPP
+ csrs mstatus, t0
+
+ LREG x1, 1*REGBYTES(sp)
+ LREG x2, 2*REGBYTES(sp)
+ LREG x3, 3*REGBYTES(sp)
+ LREG x4, 4*REGBYTES(sp)
+ LREG x5, 5*REGBYTES(sp)
+ LREG x6, 6*REGBYTES(sp)
+ LREG x7, 7*REGBYTES(sp)
+ LREG x8, 8*REGBYTES(sp)
+ LREG x9, 9*REGBYTES(sp)
+ LREG x10, 10*REGBYTES(sp)
+ LREG x11, 11*REGBYTES(sp)
+ LREG x12, 12*REGBYTES(sp)
+ LREG x13, 13*REGBYTES(sp)
+ LREG x14, 14*REGBYTES(sp)
+ LREG x15, 15*REGBYTES(sp)
+ LREG x16, 16*REGBYTES(sp)
+ LREG x17, 17*REGBYTES(sp)
+ LREG x18, 18*REGBYTES(sp)
+ LREG x19, 19*REGBYTES(sp)
+ LREG x20, 20*REGBYTES(sp)
+ LREG x21, 21*REGBYTES(sp)
+ LREG x22, 22*REGBYTES(sp)
+ LREG x23, 23*REGBYTES(sp)
+ LREG x24, 24*REGBYTES(sp)
+ LREG x25, 25*REGBYTES(sp)
+ LREG x26, 26*REGBYTES(sp)
+ LREG x27, 27*REGBYTES(sp)
+ LREG x28, 28*REGBYTES(sp)
+ LREG x29, 29*REGBYTES(sp)
+ LREG x30, 30*REGBYTES(sp)
+ LREG x31, 31*REGBYTES(sp)
+
+ addi sp, sp, 32*REGBYTES
+ mret
+
+ // Fill the stack with data so we can see if it was overrun.
+ .align 4
+stack_bottom:
+ .fill STACK_SIZE/4, 4, 0x22446688
+stack_top:
+#endif
diff --git a/debug/programs/init.c b/debug/programs/init.c
new file mode 100644
index 0000000..a2b41b0
--- /dev/null
+++ b/debug/programs/init.c
@@ -0,0 +1,24 @@
+int main(void);
+
+void handle_trap(unsigned int mcause, unsigned int mepc, unsigned int sp)
+{
+ while (1)
+ ;
+}
+
+void _exit(int status)
+{
+ // Make sure gcc doesn't inline _exit, so we can actually set a breakpoint
+ // on it.
+ volatile int i = 42;
+ while (i)
+ ;
+ // _exit isn't supposed to return.
+ while (1)
+ ;
+}
+
+void _init()
+{
+ _exit(main());
+}
diff --git a/debug/programs/mprv.S b/debug/programs/mprv.S
new file mode 100644
index 0000000..115ccb5
--- /dev/null
+++ b/debug/programs/mprv.S
@@ -0,0 +1,46 @@
+#include "../../env/encoding.h"
+#define PGSHIFT 12
+
+ .global main
+
+ .section .text
+main:
+ # Set up a page table entry that maps 0x0... to 0x8...
+ la t0, page_table
+ srli t0, t0, PGSHIFT
+ csrw CSR_SPTBR, t0
+
+ # update mstatus
+ csrr t1, CSR_MSTATUS
+#ifdef __riscv32
+ li t0, (MSTATUS_MPRV | (VM_SV32 << 24))
+#else
+ li t0, (MSTATUS_MPRV | (VM_SV39 << 24))
+#endif
+ #li t0, ((VM_SV39 << 24))
+ or t1, t0, t1
+ csrw CSR_MSTATUS, t1
+
+ la t0, (loop - 0x80000000)
+ csrw CSR_MEPC, t0
+
+ # Exit supervisor mode, entering user mode at loop.
+ mret
+
+loop:
+ la t0, data
+ lw t1, 0(t0)
+ j loop
+
+ .section .data
+data:
+ .word 0xbead
+
+ .balign 0x1000
+page_table:
+#ifdef __riscv32
+ .word ((0x80000000 >> 2) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_G | PTE_U)
+#else
+ .word ((0x80000000 >> 2) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_G | PTE_U)
+ .word 0
+#endif
diff --git a/debug/programs/regs.S b/debug/programs/regs.S
new file mode 100644
index 0000000..2cacd4f
--- /dev/null
+++ b/debug/programs/regs.S
@@ -0,0 +1,57 @@
+#ifdef __riscv64
+# define LREG ld
+# define SREG sd
+# define REGBYTES 8
+#else
+# define LREG lw
+# define SREG sw
+# define REGBYTES 4
+#endif
+
+#include "../../env/encoding.h"
+
+ .global main
+main:
+ nop
+ j main
+
+write_regs:
+ SREG x2, 0(x1)
+ SREG x3, 8(x1)
+ SREG x4, 16(x1)
+ SREG x5, 24(x1)
+ SREG x6, 32(x1)
+ SREG x7, 40(x1)
+ SREG x8, 48(x1)
+ SREG x9, 56(x1)
+ SREG x10, 64(x1)
+ SREG x11, 72(x1)
+ SREG x12, 80(x1)
+ SREG x13, 88(x1)
+ SREG x14, 96(x1)
+ SREG x15, 104(x1)
+ SREG x16, 112(x1)
+ SREG x17, 120(x1)
+ SREG x18, 128(x1)
+ SREG x19, 136(x1)
+ SREG x20, 144(x1)
+ SREG x21, 152(x1)
+ SREG x22, 160(x1)
+ SREG x23, 168(x1)
+ SREG x24, 176(x1)
+ SREG x25, 184(x1)
+ SREG x26, 192(x1)
+ SREG x27, 200(x1)
+ SREG x28, 208(x1)
+ SREG x29, 216(x1)
+ SREG x30, 224(x1)
+ SREG x31, 232(x1)
+
+ csrr x1, CSR_MSCRATCH
+
+all_done:
+ j all_done
+
+ .balign 16
+data:
+ .fill 64, 8, 0
diff --git a/debug/programs/start.S b/debug/programs/start.S
new file mode 100644
index 0000000..76c37bb
--- /dev/null
+++ b/debug/programs/start.S
@@ -0,0 +1,12 @@
+ .global _start
+
+_start:
+ la sp, stack_end
+ jal main
+done:
+ j done
+
+ .data
+stack:
+ .fill 4096, 1, 0
+stack_end:
diff --git a/debug/programs/step.S b/debug/programs/step.S
new file mode 100644
index 0000000..6601548
--- /dev/null
+++ b/debug/programs/step.S
@@ -0,0 +1,24 @@
+// Test stepping over a variety of instructions.
+
+ .global main
+
+main:
+ la t0, trap_entry // 0, 4
+ csrw mtvec, t0 // 0x8
+
+ li t0, 5 // 0xc
+ beq zero, zero, one // 0x10
+ nop // 0x14
+one:
+ beq zero, t0, one // 0x18
+ jal two // 0x1c
+
+three:
+ .word 0 // 0x20
+ nop // 0x24
+
+two:
+ ret // 0x28
+
+trap_entry:
+ j trap_entry // 0x2c
diff --git a/debug/programs/tiny-malloc.c b/debug/programs/tiny-malloc.c
new file mode 100644
index 0000000..699660c
--- /dev/null
+++ b/debug/programs/tiny-malloc.c
@@ -0,0 +1,600 @@
+// https://github.com/32bitmicro/newlib-nano-1.0/blob/master/newlib/libc/machine/xstormy16/tiny-malloc.c
+
+/* A replacement malloc with:
+ - Much reduced code size;
+ - Smaller RAM footprint;
+ - The ability to handle downward-growing heaps;
+ but
+ - Slower;
+ - Probably higher memory fragmentation;
+ - Doesn't support threads (but, if it did support threads,
+ it wouldn't need a global lock, only a compare-and-swap instruction);
+ - Assumes the maximum alignment required is the alignment of a pointer;
+ - Assumes that memory is already there and doesn't need to be allocated.
+
+* Synopsis of public routines
+
+ malloc(size_t n);
+ Return a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available.
+ free(void* p);
+ Release the chunk of memory pointed to by p, or no effect if p is null.
+ realloc(void* p, size_t n);
+ Return a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available. The returned pointer may or may not be
+ the same as p. If p is null, equivalent to malloc. Unless the
+ #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+ memalign(size_t alignment, size_t n);
+ Return a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument, which must be a power of
+ two. Will fail if 'alignment' is too large.
+ calloc(size_t unit, size_t quantity);
+ Returns a pointer to quantity * unit bytes, with all locations
+ set to zero.
+ cfree(void* p);
+ Equivalent to free(p).
+ malloc_trim(size_t pad);
+ Release all but pad bytes of freed top-most memory back
+ to the system. Return 1 if successful, else 0.
+ malloc_usable_size(void* p);
+ Report the number usable allocated bytes associated with allocated
+ chunk p. This may or may not report more bytes than were requested,
+ due to alignment and minimum size constraints.
+ malloc_stats();
+ Prints brief summary statistics on stderr.
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics.
+ mallopt(int parameter_number, int parameter_value)
+ Changes one of the tunable parameters described below. Returns
+ 1 if successful in changing the parameter, else 0. Actually, returns 0
+ always, as no parameter can be changed.
+*/
+
+#ifdef __xstormy16__
+#define MALLOC_DIRECTION -1
+#endif
+
+#ifndef MALLOC_DIRECTION
+#define MALLOC_DIRECTION 1
+#endif
+
+#include <stddef.h>
+
+void* malloc(size_t);
+void free(void*);
+void* realloc(void*, size_t);
+void* memalign(size_t, size_t);
+void* valloc(size_t);
+void* pvalloc(size_t);
+void* calloc(size_t, size_t);
+void cfree(void*);
+int malloc_trim(size_t);
+size_t malloc_usable_size(void*);
+void malloc_stats(void);
+int mallopt(int, int);
+struct mallinfo mallinfo(void);
+
+typedef struct freelist_entry {
+ size_t size;
+ struct freelist_entry *next;
+} *fle;
+
+extern void * __malloc_end;
+extern fle __malloc_freelist;
+
+/* Return the number of bytes that need to be added to X to make it
+ aligned to an ALIGN boundary. ALIGN must be a power of 2. */
+#define M_ALIGN(x, align) (-(size_t)(x) & ((align) - 1))
+
+/* Return the number of bytes that need to be subtracted from X to make it
+ aligned to an ALIGN boundary. ALIGN must be a power of 2. */
+#define M_ALIGN_SUB(x, align) ((size_t)(x) & ((align) - 1))
+
+extern char *__malloc_start;
+
+/* This is the minimum gap allowed between __malloc_end and the top of
+ the stack. This is only checked for when __malloc_end is
+ decreased; if instead the stack grows into the heap, silent data
+ corruption will result. */
+#define MALLOC_MINIMUM_GAP 32
+
+#ifdef __xstormy16__
+register void * stack_pointer asm ("r15");
+#define MALLOC_LIMIT stack_pointer
+#else
+#define MALLOC_LIMIT __builtin_frame_address (0)
+#endif
+
+#if MALLOC_DIRECTION < 0
+#define CAN_ALLOC_P(required) \
+ (((size_t) __malloc_end - (size_t)MALLOC_LIMIT \
+ - MALLOC_MINIMUM_GAP) >= (required))
+#else
+#define CAN_ALLOC_P(required) \
+ (((size_t)MALLOC_LIMIT - (size_t) __malloc_end \
+ - MALLOC_MINIMUM_GAP) >= (required))
+#endif
+
+/* real_size is the size we actually have to allocate, allowing for
+ overhead and alignment. */
+#define REAL_SIZE(sz) \
+ ((sz) < sizeof (struct freelist_entry) - sizeof (size_t) \
+ ? sizeof (struct freelist_entry) \
+ : sz + sizeof (size_t) + M_ALIGN(sz, sizeof (size_t)))
+
+#ifdef DEFINE_MALLOC
+
+void * __malloc_end = &__malloc_start;
+fle __malloc_freelist;
+
+void *
+malloc (size_t sz)
+{
+ fle *nextfree;
+ fle block;
+
+ /* real_size is the size we actually have to allocate, allowing for
+ overhead and alignment. */
+ size_t real_size = REAL_SIZE (sz);
+
+ /* Look for the first block on the freelist that is large enough. */
+ for (nextfree = &__malloc_freelist;
+ *nextfree;
+ nextfree = &(*nextfree)->next)
+ {
+ block = *nextfree;
+
+ if (block->size >= real_size)
+ {
+ /* If the block found is just the right size, remove it from
+ the free list. Otherwise, split it. */
+ if (block->size < real_size + sizeof (struct freelist_entry))
+ {
+ *nextfree = block->next;
+ return (void *)&block->next;
+ }
+ else
+ {
+ size_t newsize = block->size - real_size;
+ fle newnext = block->next;
+ *nextfree = (fle)((size_t)block + real_size);
+ (*nextfree)->size = newsize;
+ (*nextfree)->next = newnext;
+ goto done;
+ }
+ }
+
+ /* If this is the last block on the freelist, and it was too small,
+ enlarge it. */
+ if (! block->next
+ && __malloc_end == (void *)((size_t)block + block->size))
+ {
+ size_t moresize = real_size - block->size;
+ if (! CAN_ALLOC_P (moresize))
+ return NULL;
+
+ *nextfree = NULL;
+ if (MALLOC_DIRECTION < 0)
+ {
+ block = __malloc_end = (void *)((size_t)block - moresize);
+ }
+ else
+ {
+ __malloc_end = (void *)((size_t)block + real_size);
+ }
+
+ goto done;
+ }
+ }
+
+ /* No free space at the end of the free list. Allocate new space
+ and use that. */
+
+ if (! CAN_ALLOC_P (real_size))
+ return NULL;
+
+ if (MALLOC_DIRECTION > 0)
+ {
+ block = __malloc_end;
+ __malloc_end = (void *)((size_t)__malloc_end + real_size);
+ }
+ else
+ {
+ block = __malloc_end = (void *)((size_t)__malloc_end - real_size);
+ }
+ done:
+ block->size = real_size;
+ return (void *)&block->next;
+}
+
+#endif
+
+#ifdef DEFINE_FREE
+
+void
+free (void *block_p)
+{
+ fle *nextfree;
+ fle block = (fle)((size_t) block_p - offsetof (struct freelist_entry, next));
+
+ if (block_p == NULL)
+ return;
+
+ /* Look on the freelist to see if there's a free block just before
+ or just after this block. */
+ for (nextfree = &__malloc_freelist;
+ *nextfree;
+ nextfree = &(*nextfree)->next)
+ {
+ fle thisblock = *nextfree;
+ if ((size_t)thisblock + thisblock->size == (size_t) block)
+ {
+ thisblock->size += block->size;
+ if (MALLOC_DIRECTION > 0
+ && thisblock->next
+ && (size_t) block + block->size == (size_t) thisblock->next)
+ {
+ thisblock->size += thisblock->next->size;
+ thisblock->next = thisblock->next->next;
+ }
+ return;
+ }
+ else if ((size_t) thisblock == (size_t) block + block->size)
+ {
+ if (MALLOC_DIRECTION < 0
+ && thisblock->next
+ && (size_t) block == ((size_t) thisblock->next
+ + thisblock->next->size))
+ {
+ *nextfree = thisblock->next;
+ thisblock->next->size += block->size + thisblock->size;
+ }
+ else
+ {
+ block->size += thisblock->size;
+ block->next = thisblock->next;
+ *nextfree = block;
+ }
+ return;
+ }
+ else if ((MALLOC_DIRECTION > 0
+ && (size_t) thisblock > (size_t) block)
+ || (MALLOC_DIRECTION < 0
+ && (size_t) thisblock < (size_t) block))
+ break;
+ }
+
+ block->next = *nextfree;
+ *nextfree = block;
+ return;
+}
+#endif
+
+#ifdef DEFINE_REALLOC
+void *
+realloc (void *block_p, size_t sz)
+{
+ fle block = (fle)((size_t) block_p - offsetof (struct freelist_entry, next));
+ size_t real_size = REAL_SIZE (sz);
+ size_t old_real_size;
+
+ if (block_p == NULL)
+ return malloc (sz);
+
+ old_real_size = block->size;
+
+ /* Perhaps we need to allocate more space. */
+ if (old_real_size < real_size)
+ {
+ void *result;
+ size_t old_size = old_real_size - sizeof (size_t);
+
+ /* Need to allocate, copy, and free. */
+ result = malloc (sz);
+ if (result == NULL)
+ return NULL;
+ memcpy (result, block_p, old_size < sz ? old_size : sz);
+ free (block_p);
+ return result;
+ }
+ /* Perhaps we can free some space. */
+ if (old_real_size - real_size >= sizeof (struct freelist_entry))
+ {
+ fle newblock = (fle)((size_t)block + real_size);
+ block->size = real_size;
+ newblock->size = old_real_size - real_size;
+ free (&newblock->next);
+ }
+ return block_p;
+}
+#endif
+
+#ifdef DEFINE_CALLOC
+void *
+calloc (size_t n, size_t elem_size)
+{
+ void *result;
+ size_t sz = n * elem_size;
+ result = malloc (sz);
+ if (result != NULL)
+ memset (result, 0, sz);
+ return result;
+}
+#endif
+
+#ifdef DEFINE_CFREE
+void
+cfree (void *p)
+{
+ free (p);
+}
+#endif
+
+#ifdef DEFINE_MEMALIGN
+void *
+memalign (size_t align, size_t sz)
+{
+ fle *nextfree;
+ fle block;
+
+ /* real_size is the size we actually have to allocate, allowing for
+ overhead and alignment. */
+ size_t real_size = REAL_SIZE (sz);
+
+ /* Some sanity checking on 'align'. */
+ if ((align & (align - 1)) != 0
+ || align <= 0)
+ return NULL;
+
+ /* Look for the first block on the freelist that is large enough. */
+ /* One tricky part is this: We want the result to be a valid pointer
+ to free. That means that there has to be room for a size_t
+ before the block. If there's additional space before the block,
+ it should go on the freelist, or it'll be lost---we could add it
+ to the size of the block before it in memory, but finding the
+ previous block is expensive. */
+ for (nextfree = &__malloc_freelist;
+ ;
+ nextfree = &(*nextfree)->next)
+ {
+ size_t before_size;
+ size_t old_size;
+
+ /* If we've run out of free blocks, allocate more space. */
+ if (! *nextfree)
+ {
+ old_size = real_size;
+ if (MALLOC_DIRECTION < 0)
+ {
+ old_size += M_ALIGN_SUB (((size_t)__malloc_end
+ - old_size + sizeof (size_t)),
+ align);
+ if (! CAN_ALLOC_P (old_size))
+ return NULL;
+ block = __malloc_end = (void *)((size_t)__malloc_end - old_size);
+ }
+ else
+ {
+ block = __malloc_end;
+ old_size += M_ALIGN ((size_t)__malloc_end + sizeof (size_t),
+ align);
+ if (! CAN_ALLOC_P (old_size))
+ return NULL;
+ __malloc_end = (void *)((size_t)__malloc_end + old_size);
+ }
+ *nextfree = block;
+ block->size = old_size;
+ block->next = NULL;
+ }
+ else
+ {
+ block = *nextfree;
+ old_size = block->size;
+ }
+
+
+ before_size = M_ALIGN (&block->next, align);
+ if (before_size != 0)
+ before_size = sizeof (*block) + M_ALIGN (&(block+1)->next, align);
+
+ /* If this is the last block on the freelist, and it is too small,
+ enlarge it. */
+ if (! block->next
+ && old_size < real_size + before_size
+ && __malloc_end == (void *)((size_t)block + block->size))
+ {
+ if (MALLOC_DIRECTION < 0)
+ {
+ size_t moresize = real_size - block->size;
+ moresize += M_ALIGN_SUB ((size_t)&block->next - moresize, align);
+ if (! CAN_ALLOC_P (moresize))
+ return NULL;
+ block = __malloc_end = (void *)((size_t)block - moresize);
+ block->next = NULL;
+ block->size = old_size = old_size + moresize;
+ before_size = 0;
+ }
+ else
+ {
+ if (! CAN_ALLOC_P (before_size + real_size - block->size))
+ return NULL;
+ __malloc_end = (void *)((size_t)block + before_size + real_size);
+ block->size = old_size = before_size + real_size;
+ }
+
+ /* Two out of the four cases below will now be possible; which
+ two depends on MALLOC_DIRECTION. */
+ }
+
+ if (old_size >= real_size + before_size)
+ {
+ /* This block will do. If there needs to be space before it,
+ split the block. */
+ if (before_size != 0)
+ {
+ fle old_block = block;
+
+ old_block->size = before_size;
+ block = (fle)((size_t)block + before_size);
+
+ /* If there's no space after the block, we're now nearly
+ done; just make a note of the size required.
+ Otherwise, we need to create a new free space block. */
+ if (old_size - before_size
+ <= real_size + sizeof (struct freelist_entry))
+ {
+ block->size = old_size - before_size;
+ return (void *)&block->next;
+ }
+ else
+ {
+ fle new_block;
+ new_block = (fle)((size_t)block + real_size);
+ new_block->size = old_size - before_size - real_size;
+ if (MALLOC_DIRECTION > 0)
+ {
+ new_block->next = old_block->next;
+ old_block->next = new_block;
+ }
+ else
+ {
+ new_block->next = old_block;
+ *nextfree = new_block;
+ }
+ goto done;
+ }
+ }
+ else
+ {
+ /* If the block found is just the right size, remove it from
+ the free list. Otherwise, split it. */
+ if (old_size <= real_size + sizeof (struct freelist_entry))
+ {
+ *nextfree = block->next;
+ return (void *)&block->next;
+ }
+ else
+ {
+ size_t newsize = old_size - real_size;
+ fle newnext = block->next;
+ *nextfree = (fle)((size_t)block + real_size);
+ (*nextfree)->size = newsize;
+ (*nextfree)->next = newnext;
+ goto done;
+ }
+ }
+ }
+ }
+
+ done:
+ block->size = real_size;
+ return (void *)&block->next;
+}
+#endif
+
+#ifdef DEFINE_VALLOC
+void *
+valloc (size_t sz)
+{
+ return memalign (128, sz);
+}
+#endif
+#ifdef DEFINE_PVALLOC
+void *
+pvalloc (size_t sz)
+{
+ return memalign (128, sz + M_ALIGN (sz, 128));
+}
+#endif
+
+#ifdef DEFINE_MALLINFO
+#include "malloc.h"
+
+struct mallinfo
+mallinfo (void)
+{
+ struct mallinfo r;
+ fle fr;
+ size_t free_size;
+ size_t total_size;
+ size_t free_blocks;
+
+ memset (&r, 0, sizeof (r));
+
+ free_size = 0;
+ free_blocks = 0;
+ for (fr = __malloc_freelist; fr; fr = fr->next)
+ {
+ free_size += fr->size;
+ free_blocks++;
+ if (! fr->next)
+ {
+ int atend;
+ if (MALLOC_DIRECTION > 0)
+ atend = (void *)((size_t)fr + fr->size) == __malloc_end;
+ else
+ atend = (void *)fr == __malloc_end;
+ if (atend)
+ r.keepcost = fr->size;
+ }
+ }
+
+ if (MALLOC_DIRECTION > 0)
+ total_size = (char *)__malloc_end - (char *)&__malloc_start;
+ else
+ total_size = (char *)&__malloc_start - (char *)__malloc_end;
+
+#ifdef DEBUG
+ /* Fixme: should walk through all the in-use blocks and see if
+ they're valid. */
+#endif
+
+ r.arena = total_size;
+ r.fordblks = free_size;
+ r.uordblks = total_size - free_size;
+ r.ordblks = free_blocks;
+ return r;
+}
+#endif
+
+#ifdef DEFINE_MALLOC_STATS
+#include "malloc.h"
+#include <stdio.h>
+
+void
+malloc_stats(void)
+{
+ struct mallinfo i;
+ FILE *fp;
+
+ fp = stderr;
+ i = mallinfo();
+ fprintf (fp, "malloc has reserved %u bytes between %p and %p\n",
+ i.arena, &__malloc_start, __malloc_end);
+ fprintf (fp, "there are %u bytes free in %u chunks\n",
+ i.fordblks, i.ordblks);
+ fprintf (fp, "of which %u bytes are at the end of the reserved space\n",
+ i.keepcost);
+ fprintf (fp, "and %u bytes are in use.\n", i.uordblks);
+}
+#endif
+
+#ifdef DEFINE_MALLOC_USABLE_SIZE
+size_t
+malloc_usable_size (void *block_p)
+{
+ fle block = (fle)((size_t) block_p - offsetof (struct freelist_entry, next));
+ return block->size - sizeof (size_t);
+}
+#endif
+
+#ifdef DEFINE_MALLOPT
+int
+mallopt (int n, int v)
+{
+ (void)n; (void)v;
+ return 0;
+}
+#endif