diff --git a/src/stub/src/amd64-darwin.macho-main.c b/src/stub/src/amd64-darwin.macho-main.c index e0a7ef52..e9ba72c5 100644 --- a/src/stub/src/amd64-darwin.macho-main.c +++ b/src/stub/src/amd64-darwin.macho-main.c @@ -34,7 +34,7 @@ #include "include/darwin.h" #ifndef DEBUG /*{*/ -#define DEBUG 0 +#define DEBUG 1 #endif /*}*/ /************************************************************************* @@ -45,136 +45,44 @@ // it at an address different from it load address: there must be no // static data, and no string constants. -#if !DEBUG /*{*/ -#define DPRINTF(a) /* empty: no debug drivel */ -#define DEBUG_STRCON(name, value) /* empty */ -#else /*}{ DEBUG */ -extern int write(int, void const *, size_t); -#if 0 -#include "stdarg.h" -#else -#define va_arg __builtin_va_arg -#define va_end __builtin_va_end -#define va_list __builtin_va_list -#define va_start __builtin_va_start -#endif +#if !DEBUG //{ +#define DPRINTF(fmt, args...) /*empty*/ +#else //}{ +// DPRINTF is defined as an expression using "({ ... })" +// so that DPRINTF can be invoked inside an expression, +// and then followed by a comma to ignore the return value. +// The only complication is that percent and backslash +// must be doubled in the format string, because the format +// string is processd twice: once at compile-time by 'asm' +// to produce the assembled value, and once at runtime to use it. +#if defined(__powerpc__) //{ +#define DPRINTF(fmt, args...) ({ \ + char const *r_fmt; \ + asm("bl 0f; .string \"" fmt "\"; .balign 4; 0: mflr %0" \ +/*out*/ : "=r"(r_fmt) \ +/* in*/ : \ +/*und*/ : "lr"); \ + dprintf(r_fmt, args); \ +}) +#elif defined(__x86_64) //}{ +#define DPRINTF(fmt, args...) ({ \ + char const *r_fmt; \ + asm("call 0f; .asciz \"" fmt "\"; 0: pop %0" \ +/*out*/ : "=r"(r_fmt) ); \ + dprintf(r_fmt, args); \ +}) +#elif defined(__aarch64__) //}{ +#define DPRINTF(fmt, args...) ({ \ + char const *r_fmt; \ + asm("bl 0f; .string \"" fmt "\"; .balign 4; 0: mov %0,x30" \ +/*out*/ : "=r"(r_fmt) \ +/* in*/ : \ +/*und*/ : "x30"); \ + dprintf(r_fmt, args); \ +}) +#endif //} -#if defined(__i386__) || defined(__x86_64__) /*{*/ -#define PIC_STRING(value, var) \ - __asm__ __volatile__ ( \ - "call 0f; .asciz \"" value "\"; \ - 0: pop %0;" : "=r"(var) : \ - ) -#elif defined(__arm__) /*}{*/ -#define PIC_STRING(value, var) \ - __asm__ __volatile__ ( \ - "mov %0,pc; b 0f; \ - .asciz \"" value "\"; .balign 4; \ - 0: " : "=r"(var) \ - ) -#elif defined(__mips__) /*}{*/ -#define PIC_STRING(value, var) \ - __asm__ __volatile__ ( \ - ".set noreorder; bal 0f; move %0,$31; .set reorder; \ - .asciz \"" value "\"; .balign 4; \ - 0: " \ - : "=r"(var) : : "ra" \ - ) -#endif /*}*/ - - -#define DEBUG_STRCON(name, strcon) \ - static char const *name(void) { \ - register char const *rv; PIC_STRING(strcon, rv); \ - return rv; \ - } - - -#ifdef __arm__ /*{*/ -extern unsigned div10(unsigned); -#else /*}{*/ -static unsigned -div10(unsigned x) -{ - return x / 10u; -} -#endif /*}*/ - -static int -unsimal(unsigned x, char *ptr, int n) -{ - if (10<=x) { - unsigned const q = div10(x); - x -= 10 * q; - n = unsimal(q, ptr, n); - } - ptr[n] = '0' + x; - return 1+ n; -} - -static int -decimal(int x, char *ptr, int n) -{ - if (x < 0) { - x = -x; - ptr[n++] = '-'; - } - return unsimal(x, ptr, n); -} - -DEBUG_STRCON(STR_hex, "0123456789abcdef"); - -static int -heximal(unsigned long x, char *ptr, int n) -{ - if (16<=x) { - n = heximal(x>>4, ptr, n); - x &= 0xf; - } - ptr[n] = STR_hex()[x]; - return 1+ n; -} - - -#define DPRINTF(a) dprintf a - -static int -dprintf(char const *fmt, ...) -{ - char c; - int n= 0; - char *ptr; - char buf[20]; - va_list va; va_start(va, fmt); - ptr= &buf[0]; - while (0!=(c= *fmt++)) if ('%'!=c) goto literal; - else switch (c= *fmt++) { - default: { -literal: - n+= write(2, fmt-1, 1); - } break; - case 0: goto done; /* early */ - case 'u': { - n+= write(2, buf, unsimal(va_arg(va, unsigned), buf, 0)); - } break; - case 'd': { - n+= write(2, buf, decimal(va_arg(va, int), buf, 0)); - } break; - case 'p': { - buf[0] = '0'; - buf[1] = 'x'; - n+= write(2, buf, heximal((unsigned long)va_arg(va, void *), buf, 2)); - } break; - case 'x': { - buf[0] = '0'; - buf[1] = 'x'; - n+= write(2, buf, heximal(va_arg(va, int), buf, 2)); - } break; - } -done: - va_end(va); - return n; -} +static int dprintf(char const *fmt, ...); // forward #endif /*}*/ @@ -187,17 +95,15 @@ typedef struct { void *buf; } Extent; -DEBUG_STRCON(STR_xread, "xread %%p(%%x %%p) %%p %%x\\n") -DEBUG_STRCON(STR_xreadfail, "xreadfail %%p(%%x %%p) %%p %%x\\n") - static void xread(Extent *x, void *buf, size_t count) { unsigned char *p=x->buf, *q=buf; size_t j; - DPRINTF((STR_xread(), x, x->size, x->buf, buf, count)); + DPRINTF("xread %%p(%%x %%p) %%p %%x\\n", x, x->size, x->buf, buf, count); if (x->size < count) { - DPRINTF((STR_xreadfail(), x, x->size, x->buf, buf, count)); + DPRINTF("xreadfail %%p(%%x %%p) %%p %%x\\n", + x, x->size, x->buf, buf, count); exit(127); } for (j = count; 0!=j--; ++p, ++q) { @@ -217,12 +123,11 @@ xread(Extent *x, void *buf, size_t count) #define err_exit(a) goto error #else //}{ save debugging time #define ERR_LAB /*empty*/ -DEBUG_STRCON(STR_exit, "err_exit %%x\\n"); static void err_exit(int a) { - DPRINTF((STR_exit(), a)); + DPRINTF("err_exit %%x\\n", a); (void)a; // debugging convenience exit(127); } @@ -263,11 +168,7 @@ typedef void f_unfilter( ); typedef int f_expand( const nrv_byte *, nrv_uint, - nrv_byte *, nrv_uint *, unsigned ); - -DEBUG_STRCON(STR_unpackExtent, - "unpackExtent in=%%p(%%x %%p) out=%%p(%%x %%p) %%p %%p\\n"); -DEBUG_STRCON(STR_err5, "sz_cpr=%%x sz_unc=%%x xo->size=%%x\\n"); + nrv_byte *, size_t *, unsigned ); static void unpackExtent( @@ -277,8 +178,8 @@ unpackExtent( f_unfilter *f_unf ) { - DPRINTF((STR_unpackExtent(), - xi, xi->size, xi->buf, xo, xo->size, xo->buf, f_decompress, f_unf)); + DPRINTF("unpackExtent in=%%p(%%x %%p) out=%%p(%%x %%p) %%p %%p\\n", + xi, xi->size, xi->buf, xo, xo->size, xo->buf, f_decompress, f_unf); while (xo->size) { struct b_info h; // Note: if h.sz_unc == h.sz_cpr then the block was not @@ -299,7 +200,8 @@ ERR_LAB } if (h.sz_cpr > h.sz_unc || h.sz_unc > xo->size ) { - DPRINTF((STR_err5(), h.sz_cpr, h.sz_unc, xo->size)); + DPRINTF("sz_cpr=%%x sz_unc=%%x xo->size=%%x\\n", + h.sz_cpr, h.sz_unc, xo->size); err_exit(5); } // Now we have: @@ -308,7 +210,7 @@ ERR_LAB // assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize); if (h.sz_cpr < h.sz_unc) { // Decompress block - nrv_uint out_len = h.sz_unc; // EOF for lzma + size_t out_len = h.sz_unc; // EOF for lzma int const j = (*f_decompress)(xi->buf, h.sz_cpr, xo->buf, &out_len, h.b_method); if (j != 0 || out_len != (nrv_uint)h.sz_unc) @@ -471,11 +373,7 @@ extern void *mmap(void *, size_t, unsigned, unsigned, int, off_t_upx_stub); ssize_t pread(int, void *, size_t, off_t_upx_stub); extern void bswap(void *, unsigned); -DEBUG_STRCON(STR_mmap, - "mmap addr=%%p len=%%p prot=%%x flags=%%x fd=%%d off=%%p\\n"); -DEBUG_STRCON(STR_do_xmap, - "do_xmap fdi=%%x mhdr=%%p xi=%%p(%%x %%p) f_unf=%%p\\n") - +// FIXME: must reserve convex hull of pages; must reloc PIE static Mach_AMD64_thread_state const * do_xmap( Mach_header64 const *const mhdr, @@ -491,8 +389,8 @@ do_xmap( Mach_AMD64_thread_state const *entry = 0; unsigned j; - DPRINTF((STR_do_xmap(), - fdi, mhdr, xi, (xi? xi->size: 0), (xi? xi->buf: 0), f_unf)); + DPRINTF("do_xmap fdi=%%x mhdr=%%p xi=%%p(%%x %%p) f_unf=%%p\\n", + fdi, mhdr, xi, (xi? xi->size: 0), (xi? xi->buf: 0), f_unf); for ( j=0; j < mhdr->ncmds; ++j, (sc = (Mach_segment_command const *)(sc->cmdsize + (void const *)sc)) @@ -514,7 +412,8 @@ do_xmap( int const fdm = ((0==sc->filesize) ? MAP_ANON_FD : fdi); off_t_upx_stub const offset = sc->fileoff + fat_offset; - DPRINTF((STR_mmap(), addr, mlen3, prot, flags, fdm, offset)); + DPRINTF("mmap addr=%%p len=%%p prot=%%x flags=%%x fd=%%d off=%%p\\n", + addr, mlen3, prot, flags, fdm, offset); if (addr != mmap(addr, mlen3, prot, flags, fdm, offset)) { err_exit(8); } @@ -562,14 +461,10 @@ ERR_LAB /************************************************************************* -// upx_main - called by our entry code +// upx_main - called by our unfolded entry code // **************************************************************************/ -DEBUG_STRCON(STR_upx_main, - "upx_main szc=%%x f_dec=%%p f_unf=%%p " - " xo=%%p(%%x %%p) xi=%%p(%%x %%p) mhdrpp=%%p\\n") - Mach_AMD64_thread_state const * upx_main( struct l_info const *const li, @@ -590,9 +485,10 @@ upx_main( xo.size = ((struct b_info const *)(void const *)xi.buf)->sz_unc; xi0 = xi; - DPRINTF((STR_upx_main(), + DPRINTF("upx_main szc=%%x f_dec=%%p f_unf=%%p " + " xo=%%p(%%x %%p) xi=%%p(%%x %%p) mhdrpp=%%p mhdrp=%%p\\n", sz_compressed, f_decompress, f_unf, &xo, xo.size, xo.buf, - &xi, xi.size, xi.buf, mhdrpp)); + &xi, xi.size, xi.buf, mhdrpp, *mhdrpp); // Uncompress Macho headers unpackExtent(&xi, &xo, f_decompress, 0); // never filtered? @@ -643,4 +539,113 @@ ERR_LAB return entry; } +#if DEBUG //{ + +static int +unsimal(unsigned x, char *ptr, int n) +{ + unsigned m = 10; + while (10 <= (x / m)) m *= 10; + while (10 <= x) { + unsigned d = x / m; + x -= m * d; + m /= 10; + ptr[n++] = '0' + d; + } + ptr[n++] = '0' + x; + return n; +} + +static int +decimal(int x, char *ptr, int n) +{ + if (x < 0) { + x = -x; + ptr[n++] = '-'; + } + return unsimal(x, ptr, n); +} + +static int +heximal(unsigned long x, char *ptr, int n) +{ + unsigned j = -1+ 2*sizeof(unsigned long); + unsigned long m = 0xful << (4 * j); + for (; j; --j, m >>= 4) { // omit leading 0 digits + if (m & x) break; + } + for (; m; --j, m >>= 4) { + unsigned d = 0xf & (x >> (4 * j)); + ptr[n++] = ((10<=d) ? ('a' - 10) : '0') + d; + } + return n; +} + +#define va_arg __builtin_va_arg +#define va_end __builtin_va_end +#define va_list __builtin_va_list +#define va_start __builtin_va_start + +static int +dprintf(char const *fmt, ...) +{ + int n= 0; + char const *literal = 0; // NULL + char buf[24]; // ~0ull == 18446744073709551615 ==> 20 chars + va_list va; va_start(va, fmt); + for (;;) { + char c = *fmt++; + if (!c) { // end of fmt + if (literal) { + goto finish; + } + break; // goto done + } + if ('%'!=c) { + if (!literal) { + literal = fmt; // 1 beyond start of literal + } + continue; + } + // '%' == c + if (literal) { +finish: + n += write(2, -1+ literal, fmt - literal); + literal = 0; // NULL + if (!c) { // fmt already ended + break; // goto done + } + } + switch (c= *fmt++) { // deficiency: does not handle _long_ + default: { // un-implemented conversion + n+= write(2, -1+ fmt, 1); + } break; + case 0: { // fmt ends with "%\0" ==> ignore + goto done; + } break; + case 'u': { + n+= write(2, buf, unsimal(va_arg(va, unsigned), buf, 0)); + } break; + case 'd': { + n+= write(2, buf, decimal(va_arg(va, int), buf, 0)); + } break; + case 'p': { + buf[0] = '0'; + buf[1] = 'x'; + n+= write(2, buf, heximal((unsigned long)va_arg(va, void *), buf, 2)); + } break; + case 'x': { + buf[0] = '0'; + buf[1] = 'x'; + n+= write(2, buf, heximal(va_arg(va, int), buf, 2)); + } break; + } // 'switch' + } +done: + va_end(va); + return n; + } + +#endif //} + /* vim:set ts=4 sw=4 et: */