From bb4cbdff44904c61b18486afee325a5f549846f9 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Thu, 22 Dec 2022 16:06:25 +0100 Subject: [PATCH] src: fix m68k-atari build, prepare for std::atomic, port John's MemBuffer debug --- src/conf.h | 37 ++++++++++++++++++++++++++++++++++--- src/console.h | 2 ++ src/util/dt_impl.cpp | 6 +++++- src/util/membuffer.cpp | 28 ++++++++++++++++++++++++---- src/util/membuffer.h | 26 +++++++++++++++++++++----- src/util/xspan.cpp | 4 ++-- 6 files changed, 88 insertions(+), 15 deletions(-) diff --git a/src/conf.h b/src/conf.h index 5a9f3b4d..7e265406 100644 --- a/src/conf.h +++ b/src/conf.h @@ -117,6 +117,9 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char #define ACC_WANT_ACC_LIB_H 1 #define ACC_WANT_ACC_CXX_H 1 #include "miniacc.h" +#if (ACC_CC_MSC) +# include +#endif /* intergral types */ typedef acc_int8_t upx_int8_t; @@ -264,12 +267,14 @@ typedef upx_int64_t upx_off_t; #endif // avoid warnings about shadowing global functions +#undef _base #undef basename #undef index #undef outp -#define basename upx_basename -#define index upx_index -#define outp upx_outp +#define _base upx_renamed__base +#define basename upx_renamed_basename +#define index upx_renamed_index +#define outp upx_renamed_outp #undef PAGE_MASK #undef PAGE_SIZE @@ -321,6 +326,16 @@ inline void NO_fprintf(FILE *, const char *, ...) {} # define upx_memcpy_inline memcpy #endif +#if __has_builtin(__builtin_return_address) +# define upx_return_address() __builtin_return_address(0) +#elif defined(__GNUC__) +# define upx_return_address() __builtin_return_address(0) +#elif (ACC_CC_MSC) +# define upx_return_address() _ReturnAddress() +#else +# define upx_return_address() nullptr +#endif + #define UNUSED(var) ACC_UNUSED(var) #define COMPILE_TIME_ASSERT(e) ACC_COMPILE_TIME_ASSERT(e) @@ -328,6 +343,14 @@ inline void NO_fprintf(FILE *, const char *, ...) {} #define __packed_struct(s) struct alignas(1) s { #define __packed_struct_end() }; +#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__) +// hack for broken compiler +#define upx_alignas_1 __attribute__((__aligned__(1),__packed__)) +#define upx_alignas_16 __attribute__((__aligned__(2))) // object file maximum 2 ??? +#define upx_alignas__(a) upx_alignas_ ## a +#define alignas(x) upx_alignas__(x) +#endif + #define COMPILE_TIME_ASSERT_ALIGNOF_USING_SIZEOF__(a,b) { \ typedef a acc_tmp_a_t; typedef b acc_tmp_b_t; \ struct alignas(1) acc_tmp_t { acc_tmp_b_t x; acc_tmp_a_t y; acc_tmp_b_t z; }; \ @@ -730,6 +753,14 @@ struct upx_compress_result_t #include #include #include +#if __STDC_NO_ATOMICS__ || 1 +// UPX currently does not use multithreading +#define upx_std_atomic(Type) Type +//#define upx_std_atomic(Type) typename std::add_volatile::type +#else +#include +#define upx_std_atomic(Type) std::atomic +#endif #include "options.h" #include "except.h" diff --git a/src/console.h b/src/console.h index 6e684147..511b28de 100644 --- a/src/console.h +++ b/src/console.h @@ -62,6 +62,8 @@ #elif 1 && (ACC_OS_EMX && defined(__RSXNT__)) #define USE_SCREEN 1 #define USE_SCREEN_WIN32 1 +#elif 1 && (ACC_ARCH_M68K && ACC_OS_TOS) +#define NO_CONSOLE 1 #endif #if 0 || (NO_ANSI) diff --git a/src/util/dt_impl.cpp b/src/util/dt_impl.cpp index 09377dee..ce6d7a44 100644 --- a/src/util/dt_impl.cpp +++ b/src/util/dt_impl.cpp @@ -33,8 +33,12 @@ #if !defined(UPX_DOCTEST_CONFIG_MULTITHREADING) #define DOCTEST_CONFIG_NO_MULTITHREADING #endif -#if defined(__MSDOS__) && defined(__DJGPP__) +#if defined(__i386__) && defined(__MSDOS__) && defined(__DJGPP__) && defined(__GNUC__) #define DOCTEST_CONFIG_NO_POSIX_SIGNALS +#elif defined(__m68k__) && defined(__atarist__) && defined(__GNUC__) +#define DOCTEST_CONFIG_COLORS_NONE +#define DOCTEST_CONFIG_NO_POSIX_SIGNALS +#pragma GCC diagnostic ignored "-Wshadow" #endif #define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS #if !defined(DOCTEST_CONFIG_DISABLE) diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index a8d81ba1..7448dcfe 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -32,6 +32,14 @@ void *membuffer_get_void_ptr(MemBuffer &mb) { return mb.getVoidPtr(); } unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); } +MemBuffer::Stats MemBuffer::stats; + +#if DEBUG +#define debug_set(var, expr) (var) = (expr) +#else +#define debug_set(var, expr) /*empty*/ +#endif + /************************************************************************* // bool use_simple_mcheck() **************************************************************************/ @@ -60,13 +68,17 @@ __acc_static_forceinline constexpr bool use_simple_mcheck() { return true; } // **************************************************************************/ -MemBuffer::MemBuffer(upx_uint64_t size_in_bytes) { alloc(size_in_bytes); } +MemBuffer::MemBuffer(upx_uint64_t size_in_bytes) { + alloc(size_in_bytes); + debug_set(debug.last_return_address_alloc, upx_return_address()); +} MemBuffer::~MemBuffer() { this->dealloc(); } // similar to BoundedPtr, except checks only at creation // skip == offset, take == size_in_bytes void *MemBuffer::subref_impl(const char *errfmt, size_t skip, size_t take) { + debug_set(debug.last_return_address_subref, upx_return_address()); // check overrun and wrap-around if (skip + take > b_size_in_bytes || skip + take < skip) { char buf[100]; @@ -130,14 +142,17 @@ unsigned MemBuffer::getSizeForDecompression(unsigned uncompressed_size, unsigned void MemBuffer::allocForCompression(unsigned uncompressed_size, unsigned extra) { unsigned size = getSizeForCompression(uncompressed_size, extra); alloc(size); + debug_set(debug.last_return_address_alloc, upx_return_address()); } void MemBuffer::allocForDecompression(unsigned uncompressed_size, unsigned extra) { unsigned size = getSizeForDecompression(uncompressed_size, extra); alloc(size); + debug_set(debug.last_return_address_alloc, upx_return_address()); } void MemBuffer::fill(unsigned off, unsigned len, int value) { + debug_set(debug.last_return_address_fill, upx_return_address()); checkState(); assert((int) off >= 0); assert((int) len >= 0); @@ -156,8 +171,6 @@ void MemBuffer::fill(unsigned off, unsigned len, int value) { #define MAGIC1(p) ((PTR_BITS(p) ^ 0xfefdbeeb) | 1) #define MAGIC2(p) ((PTR_BITS(p) ^ 0xfefdbeeb ^ 0x80024011) | 1) -unsigned MemBuffer::global_alloc_counter = 0; - void MemBuffer::checkState() const { if (!b) throwInternalError("block not allocated"); @@ -177,8 +190,10 @@ void MemBuffer::alloc(upx_uint64_t size) { assert(b_size_in_bytes == 0); // assert(size > 0); + debug_set(debug.last_return_address_alloc, upx_return_address()); size_t bytes = mem_size(1, size, use_simple_mcheck() ? 32 : 0); unsigned char *p = (unsigned char *) malloc(bytes); + NO_printf("MemBuffer::alloc %llu: %p\n", size, p); if (!p) throwOutOfMemoryException(); b = p; @@ -189,17 +204,22 @@ void MemBuffer::alloc(upx_uint64_t size) { set_ne32(b - 8, b_size_in_bytes); set_ne32(b - 4, MAGIC1(b)); set_ne32(b + b_size_in_bytes, MAGIC2(b)); - set_ne32(b + b_size_in_bytes + 4, global_alloc_counter++); + set_ne32(b + b_size_in_bytes + 4, stats.global_alloc_counter); } #if !defined(__SANITIZE_ADDRESS__) && 0 fill(0, b_size_in_bytes, (rand() & 0xff) | 1); // debug (void) VALGRIND_MAKE_MEM_UNDEFINED(b, b_size_in_bytes); #endif + stats.global_alloc_counter += 1; + stats.global_total_bytes += b_size_in_bytes; + stats.global_total_active_bytes += b_size_in_bytes; } void MemBuffer::dealloc() { if (b != nullptr) { + debug_set(debug.last_return_address_dealloc, upx_return_address()); checkState(); + stats.global_total_active_bytes -= b_size_in_bytes; if (use_simple_mcheck()) { // clear magic constants set_ne32(b - 8, 0); diff --git a/src/util/membuffer.h b/src/util/membuffer.h index c289a50d..1c1ffe1d 100644 --- a/src/util/membuffer.h +++ b/src/util/membuffer.h @@ -71,7 +71,7 @@ public: } }; -class MemBuffer : public MemBufferBase { +class MemBuffer final : public MemBufferBase { public: MemBuffer() = default; explicit MemBuffer(upx_uint64_t size_in_bytes); @@ -94,21 +94,37 @@ public: // util void fill(unsigned off, unsigned len, int value); - void clear(unsigned off, unsigned len) { fill(off, len, 0); } - void clear() { fill(0, b_size_in_bytes, 0); } + __acc_forceinline void clear(unsigned off, unsigned len) { fill(off, len, 0); } + __acc_forceinline void clear() { fill(0, b_size_in_bytes, 0); } // If the entire range [skip, skip+take) is inside the buffer, // then return &b[skip]; else throwCantPack(sprintf(errfmt, skip, take)). // This is similar to BoundedPtr, except only checks once. // skip == offset, take == size_in_bytes - pointer subref(const char *errfmt, size_t skip, size_t take) { + __acc_forceinline pointer subref(const char *errfmt, size_t skip, size_t take) { return (pointer) subref_impl(errfmt, skip, take); } private: void *subref_impl(const char *errfmt, size_t skip, size_t take); - static unsigned global_alloc_counter; + // static debug stats + struct Stats { + upx_std_atomic(upx_uint32_t) global_alloc_counter; + upx_std_atomic(upx_uint64_t) global_total_bytes; + upx_std_atomic(upx_uint64_t) global_total_active_bytes; + }; + static Stats stats; +#if DEBUG + // debugging aid + struct Debug { + void *last_return_address_alloc = nullptr; + void *last_return_address_dealloc = nullptr; + void *last_return_address_fill = nullptr; + void *last_return_address_subref = nullptr; + }; + Debug debug; +#endif // disable copy, assignment and move assignment MemBuffer(const MemBuffer &) = delete; diff --git a/src/util/xspan.cpp b/src/util/xspan.cpp index 11755884..59af5d15 100644 --- a/src/util/xspan.cpp +++ b/src/util/xspan.cpp @@ -30,7 +30,7 @@ SPAN_NAMESPACE_BEGIN -unsigned long long span_check_stats_check_range = 0; +upx_std_atomic(upx_uint64_t) span_check_stats_check_range_counter(0); // HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience __acc_noinline void span_fail_nullptr() { @@ -61,7 +61,7 @@ void span_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes) ptrdiff_t off = (const char *) p - (const char *) base; if __acc_very_unlikely (off < 0 || off > size_in_bytes) span_fail_range_range(); - span_check_stats_check_range += 1; + span_check_stats_check_range_counter += 1; // fprintf(stderr, "span_check_range done\n"); }