This Trac instance is not used for development anymore!

We migrated our development workflow to git and Gitea.
To test the future redirection, replace trac by ariadne in the page URL.

Changeset 9871 for ps


Ignore:
Timestamp:
07/18/11 11:21:56 (13 years ago)
Author:
Jan Wassenberg
Message:

post-alpha sync with work.
debug stack trace fixes, remove more asm, change CONTINUE/OK scheme to OK/ALL_COMPLETE, fix tests

Location:
ps/trunk/source
Files:
32 edited

Legend:

Unmodified
Added
Removed
  • ps/trunk/source/lib/allocators/unique_range.cpp

    r9362 r9871  
    22#include "lib/allocators/unique_range.h"
    33
     4#include "lib/bits.h"   // is_pow2, round_up
    45#include "lib/sysdep/cpu.h" // cpu_AtomicAdd
    56#include "lib/sysdep/rtl.h" // rtl_FreeAligned
    67
    78
    8 static void UniqueRangeDeleterNone(void* UNUSED(pointer), size_t UNUSED(size))
     9// (hardwired index avoids RegisterUniqueRangeDeleter overhead for
     10// this commonly used allocator.)
     11static const IdxDeleter idxDeleterAligned = 1;
     12
     13
     14static void FreeNone(void* UNUSED(pointer), size_t UNUSED(size))
    915{
    10     // (introducing this do-nothing function avoids having to check whether deleter != 0)
     16    // (providing a deleter function for idxDeleterNone avoids
     17    // having to check whether deleters[idxDeleter] == 0)
    1118}
    1219
    13 static void UniqueRangeDeleterAligned(void* pointer, size_t UNUSED(size))
     20static void FreeAligned(void* pointer, size_t UNUSED(size))
    1421{
    1522    return rtl_FreeAligned(pointer);
     
    1724
    1825
    19 static UniqueRangeDeleter deleters[idxDeleterBits+1] = { UniqueRangeDeleterNone, UniqueRangeDeleterAligned };
     26static UniqueRangeDeleter deleters[allocationAlignment] = { FreeNone, FreeAligned };
    2027
    2128static IdxDeleter numDeleters = 2;
    2229
    2330
    24 IdxDeleter AddUniqueRangeDeleter(UniqueRangeDeleter deleter)
     31void RegisterUniqueRangeDeleter(UniqueRangeDeleter deleter, volatile IdxDeleter* idxDeleterOut)
    2532{
    2633    ENSURE(deleter);
    27     IdxDeleter idxDeleter = cpu_AtomicAdd(&numDeleters, 1);
     34
     35    if(!cpu_CAS(idxDeleterOut, idxDeleterNone, -1)) // not the first call for this deleter
     36    {
     37        // wait until an index has been assigned
     38        while(*idxDeleterOut <= 0)
     39            cpu_Pause();
     40        return;
     41    }
     42
     43    const IdxDeleter idxDeleter = cpu_AtomicAdd(&numDeleters, 1);
    2844    ENSURE(idxDeleter < (IdxDeleter)ARRAY_SIZE(deleters));
    2945    deleters[idxDeleter] = deleter;
    30     return idxDeleter;
     46    COMPILER_FENCE;
     47    *idxDeleterOut = idxDeleter;    // linearization point
    3148}
    3249
     
    3956        deleters[idxDeleter](pointer, size);
    4057}
     58
     59
     60UniqueRange AllocateAligned(size_t size, size_t alignment)
     61{
     62    ENSURE(is_pow2(alignment));
     63    alignment = std::max(alignment, allocationAlignment);
     64
     65    const size_t alignedSize = round_up(size, alignment);
     66    const UniqueRange::pointer p = rtl_AllocateAligned(alignedSize, alignment);
     67
     68    static volatile IdxDeleter idxDeleterAligned;
     69    if(idxDeleterAligned == 0)
     70        RegisterUniqueRangeDeleter(FreeAligned, &idxDeleterAligned);
     71
     72    return RVALUE(UniqueRange(p, size, idxDeleterAligned));
     73}
  • ps/trunk/source/lib/allocators/unique_range.h

    r9362 r9871  
    33
    44#include "lib/lib_api.h"
     5#include "lib/alignment.h"  // allocationAlignment
    56
    67// we usually don't hold multiple references to allocations, so unique_ptr
     
    1516// however, this inflates the pointer size to 3 words. if only a few allocator types
    1617// are needed, we can replace the function pointer with an index stashed into the
    17 // lower bits of the pointer (safe because allocations are always aligned to the
    18 // word size).
     18// lower bits of the pointer (safe because all allocations' addresses are multiples
     19// of allocationAlignment).
    1920typedef intptr_t IdxDeleter;
    2021
    2122// no-op deleter (use when returning part of an existing allocation)
    22 // must be zero because reset() sets address (which includes idxDeleter) to zero.
    2323static const IdxDeleter idxDeleterNone = 0;
    24 
    25 static const IdxDeleter idxDeleterAligned = 1;
    26 
    27 // (temporary value to prevent concurrent calls to AddUniqueRangeDeleter)
    28 static const IdxDeleter idxDeleterBusy = -IdxDeleter(1);
    29 
    30 // governs the maximum number of IdxDeleter and each pointer's alignment requirements
    31 static const IdxDeleter idxDeleterBits = 0x7;
    3224
    3325typedef void (*UniqueRangeDeleter)(void* pointer, size_t size);
    3426
    3527/**
    36  * @return the next available IdxDeleter and associate it with the deleter.
    37  * halts the program if the idxDeleterBits limit has been reached.
     28 * register a deleter, returning its index within the table.
    3829 *
    39  * thread-safe, but no attempt is made to detect whether the deleter has already been
    40  * registered (would require a mutex). each allocator must ensure they only call this once.
     30 * @param deleter function pointer. must be uniquely associated with
     31 *   the idxDeleter storage location.
     32 * @param idxDeleter location where to store the next available index.
     33 *   if it is already non-zero, skip the call to this function to
     34 *   avoid overhead.
     35 *
     36 * thread-safe. idxDeleter is used for mutual exclusion between
     37 * multiple callers for the same deleter. concurrent registration of
     38 * different deleters is also safe due to atomic increments.
     39 *
     40 * halts the program if more than allocationAlignment deleters are
     41 * to be registered.
    4142 **/
    42 LIB_API IdxDeleter AddUniqueRangeDeleter(UniqueRangeDeleter deleter);
     43LIB_API void RegisterUniqueRangeDeleter(UniqueRangeDeleter deleter, volatile IdxDeleter* idxDeleter);
    4344
    4445LIB_API void CallUniqueRangeDeleter(void* pointer, size_t size, IdxDeleter idxDeleter) throw();
     
    5758    UniqueRange()
    5859    {
    59         Set(0, 0, idxDeleterNone);
     60        Clear();
    6061    }
    6162
     
    6768    UniqueRange(RVALUE_REF(UniqueRange) rvalue)
    6869    {
    69         UniqueRange& lvalue = LVALUE(rvalue);
    70         address_ = lvalue.address_;
    71         size_ = lvalue.size_;
    72         lvalue.address_ = 0;
     70        Pilfer(LVALUE(rvalue));
    7371    }
    7472
     
    7977        {
    8078            Delete();
    81             address_ = lvalue.address_;
    82             size_ = lvalue.size_;
    83             lvalue.address_ = 0;
     79            Pilfer(lvalue);
    8480        }
    8581        return *this;
     
    9389    pointer get() const
    9490    {
    95         return pointer(address_ & ~idxDeleterBits);
     91        return pointer(address_ & ~(allocationAlignment-1));
    9692    }
    9793
    9894    IdxDeleter get_deleter() const
    9995    {
    100         return IdxDeleter(address_ & idxDeleterBits);
     96        return IdxDeleter(address_ % allocationAlignment);
    10197    }
    10298
     
    110106    {
    111107        pointer ret = get();
    112         address_ = 0;
     108        Clear();
    113109        return ret;
    114110    }
     
    117113    {
    118114        Delete();
    119         address_ = 0;
     115        Clear();
    120116    }
    121117
     
    140136    void Set(pointer p, size_t size, IdxDeleter deleter)
    141137    {
    142         ASSERT((uintptr_t(p) & idxDeleterBits) == 0);
    143         ASSERT(deleter <= idxDeleterBits);
     138        ASSERT((uintptr_t(p) % allocationAlignment) == 0);
     139        ASSERT(size_t(deleter) < allocationAlignment);
    144140
    145141        address_ = uintptr_t(p) | deleter;
     
    149145        ASSERT(get_deleter() == deleter);
    150146        ASSERT(this->size() == size);
     147    }
     148
     149    void Clear()
     150    {
     151        Set(0, 0, idxDeleterNone);
     152    }
     153
     154    void Pilfer(UniqueRange& victim)
     155    {
     156        const size_t size = victim.size();
     157        const IdxDeleter idxDeleter = victim.get_deleter();
     158        pointer p = victim.release();
     159        Set(p, size, idxDeleter);
     160        victim.Clear();
    151161    }
    152162
     
    180190}
    181191
     192LIB_API UniqueRange AllocateAligned(size_t size, size_t alignment);
     193
    182194#endif  // #ifndef INCLUDED_ALLOCATORS_UNIQUE_RANGE
  • ps/trunk/source/lib/debug.cpp

    r9545 r9871  
    533533ErrorReaction debug_OnError(Status err, atomic_bool* suppress, const wchar_t* file, int line, const char* func)
    534534{
     535    CACHE_ALIGNED u8 context[DEBUG_CONTEXT_SIZE];
     536    (void)debug_CaptureContext(context);
     537
    535538    if(ShouldSkipError(err))
    536539        return ER_CONTINUE;
    537540
    538     void* context = 0;
    539541    const wchar_t* lastFuncToSkip = L"debug_OnError";
    540542    wchar_t buf[400];
     
    547549ErrorReaction debug_OnAssertionFailure(const wchar_t* expr, atomic_bool* suppress, const wchar_t* file, int line, const char* func)
    548550{
    549     void* context = 0;
     551    CACHE_ALIGNED u8 context[DEBUG_CONTEXT_SIZE];
     552    (void)debug_CaptureContext(context);
     553
    550554    const std::wstring lastFuncToSkip = L"debug_OnAssertionFailure";
    551555    wchar_t buf[400];
  • ps/trunk/source/lib/debug.h

    r9410 r9871  
    4040#include "lib/types.h"  // intptr_t
    4141#include "lib/status.h"
     42#include "lib/alignment.h"
    4243#include "lib/code_annotation.h"
    4344#include "lib/code_generation.h"
     
    120121 * rationale: this value is fairly distinctive and helps when
    121122 * debugging the symbol engine.
    122  * initial value is 0 rather that another constant; this avoids
    123  * allocating .rdata space.
     123 * use 0 as the initial value to avoid allocating .rdata space.
    124124 **/
    125125const atomic_bool DEBUG_SUPPRESS = 0xAB;
     
    175175    ERI_NOT_IMPLEMENTED
    176176};
     177
    177178
    178179/**
     
    193194LIB_API ErrorReaction debug_DisplayError(const wchar_t* description, size_t flags, void* context, const wchar_t* lastFuncToSkip, const wchar_t* file, int line, const char* func, atomic_bool* suppress);
    194195
    195 /**
    196  * convenience version, in case the advanced parameters aren't needed.
    197  * macro instead of providing overload/default values for C compatibility.
    198  **/
    199 #define DEBUG_DISPLAY_ERROR(text) debug_DisplayError(text, 0, 0, L"debug_DisplayError", WIDEN(__FILE__),__LINE__,__func__, 0)
     196// simplified version for just displaying an error message
     197#define DEBUG_DISPLAY_ERROR(description)\
     198    do\
     199    {\
     200        CACHE_ALIGNED u8 context[DEBUG_CONTEXT_SIZE];\
     201        (void)debug_CaptureContext(context);\
     202        (void)debug_DisplayError(description, 0, context, L"debug_DisplayError", WIDEN(__FILE__), __LINE__, __func__, 0);\
     203    }\
     204    while(0)
    200205
    201206
     
    418423
    419424/**
    420  * Maximum number of characters (including trailing \\0) written to
     425 * Maximum number of characters (including null terminator) written to
    421426 * user's buffers by debug_ResolveSymbol.
    422427 **/
    423 const size_t DBG_SYMBOL_LEN = 1000;
    424 const size_t DBG_FILE_LEN = 100;
     428static const size_t DEBUG_SYMBOL_CHARS = 1000;
     429static const size_t DEBUG_FILE_CHARS = 100;
    425430
    426431/**
    427432 * read and return symbol information for the given address.
    428433 *
    429  * NOTE: the PDB implementation is rather slow (~500us).
     434 * NOTE: the PDB implementation is rather slow (~500 us).
    430435 *
    431436 * @param ptr_of_interest address of symbol (e.g. function, variable)
    432  * @param sym_name optional out; size >= DBG_SYMBOL_LEN chars;
    433  * receives symbol name returned via debug info.
    434  * @param file optional out; size >= DBG_FILE_LEN chars; receives
    435  * base name only (no path; see rationale in wdbg_sym) of
    436  * source file containing the symbol.
     437 * @param sym_name optional out; holds at least DEBUG_SYMBOL_CHARS;
     438 *   receives symbol name returned via debug info.
     439 * @param file optional out; holds at least DEBUG_FILE_CHARS;
     440 *   receives base name only (no path; see rationale in wdbg_sym) of
     441 *   source file containing the symbol.
    437442 * @param line optional out; receives source file line number of symbol.
    438443 *
     
    444449LIB_API Status debug_ResolveSymbol(void* ptr_of_interest, wchar_t* sym_name, wchar_t* file, int* line);
    445450
     451static const size_t DEBUG_CONTEXT_SIZE = 2048;  // Win32 CONTEXT is currently 1232 bytes
     452
     453/**
     454 * @param context must point to an instance of the platform-specific type
     455 *   (e.g. CONTEXT) or CACHE_ALIGNED storage of DEBUG_CONTEXT_SIZE bytes.
     456 **/
     457LIB_API Status debug_CaptureContext(void* context);
     458
     459
    446460/**
    447461 * write a complete stack trace (including values of local variables) into
     
    451465 * @param maxChars Max chars of buffer (should be several thousand).
    452466 * @param context Platform-specific representation of execution state
    453  *        (e.g. Win32 CONTEXT). if not NULL, tracing starts there; this is useful
    454  *        for exceptions. Otherwise, tracing starts from the current call stack.
     467 *        (e.g. Win32 CONTEXT). either specify an SEH exception's
     468 *        context record or use debug_CaptureContext to retrieve the current state.
     469 *        Rationale: intermediates such as debug_DisplayError change the
     470 *        context, so it should be captured as soon as possible.
    455471 * @param lastFuncToSkip Is used for omitting error-reporting functions like
    456472 *        debug_OnAssertionFailure from the stack trace. It is either 0 (skip nothing) or
  • ps/trunk/source/lib/debug_stl.cpp

    r9447 r9871  
    3838static const StatusDefinition debugStlStatusDefinitions[] = {
    3939    { ERR::STL_CNT_UNKNOWN, L"Unknown STL container type_name" },
     40    { ERR::STL_CNT_UNSUPPORTED, L"Unsupported STL container" },
    4041    { ERR::STL_CNT_INVALID, L"Container type is known but contents are invalid" }
    4142};
     
    5051    {\
    5152        src += ARRAY_SIZE(what)-1-1; /* see preincrement rationale*/\
    52         wcscpy_s(dst, ARRAY_SIZE(what), (with));\
     53        wcscpy_s(dst, ARRAY_SIZE(with), (with));\
    5354        dst += ARRAY_SIZE(with)-1;\
    5455    }
     
    140141        REPLACE(L"std::_List_nod", L"list")
    141142        REPLACE(L"std::_Tree_nod", L"map")
    142         REPLACE(L"std::basic_string<char,", L"string<")
    143         REPLACE(L"std::basic_string<unsigned short,", L"wstring<")
    144         STRIP(L"std::char_traits<char>,")
    145         STRIP(L"std::char_traits<unsigned short>,")
     143        REPLACE(L"std::basic_string<char, ", L"string<")
     144        REPLACE(L"std::basic_string<__wchar_t, ", L"wstring<")
     145        REPLACE(L"std::basic_string<unsigned short, ", L"wstring<")
     146        STRIP(L"std::char_traits<char>, ")
     147        STRIP(L"std::char_traits<unsigned short>, ")
     148        STRIP(L"std::char_traits<__wchar_t>, ")
    146149        STRIP(L"std::_Tmap_traits")
    147150        STRIP(L"std::_Tset_traits")
     
    555558    UNUSED2(el_iterator);
    556559    UNUSED2(it_mem);
    557     return ERR::STL_CNT_UNKNOWN;    // NOWARN
     560    return ERR::STL_CNT_UNSUPPORTED;    // NOWARN
    558561#else
    559562
  • ps/trunk/source/lib/debug_stl.h

    r9410 r9871  
    3232{
    3333    const Status STL_CNT_UNKNOWN = -100500;
     34    const Status STL_CNT_UNSUPPORTED = -100501;
    3435    // likely causes: not yet initialized or memory corruption.
    35     const Status STL_CNT_INVALID = -100501;
     36    const Status STL_CNT_INVALID = -100502;
    3637}
    3738
     
    4647 * @param name Buffer holding input symbol name; modified in-place.
    4748 *        There is no length limit; must be large enough to hold typical STL
    48  *        strings. DBG_SYMBOL_LEN chars is a good measure.
     49 *        strings. DEBUG_SYMBOL_CHARS chars is a good measure.
    4950 * @return name for convenience.
    5051 **/
  • ps/trunk/source/lib/external_libraries/dbghelp.h

    r8484 r9871  
    122122#endif
    123123
     124#pragma pack(push, 8)   // seems to be required
     125
    124126#define _NO_CVCONST_H   // request SymTagEnum be defined
    125127#include <dbghelp.h>    // must come after win.h and the above definitions
     128
     129#pragma pack(pop)
    126130
    127131#if ICC_VERSION
  • ps/trunk/source/lib/file/archive/archive_zip.cpp

    r9550 r9871  
    382382            lfh_bytes_remaining -= size;
    383383
    384             return INFO::CONTINUE;
     384            return INFO::OK;
    385385        }
    386386
  • ps/trunk/source/lib/file/archive/stream.cpp

    r9462 r9871  
    117117{
    118118    if(m_outProduced == m_outputBufferManager.Size())   // output buffer full; must not call Process
    119         return INFO::OK;
     119        return INFO::ALL_COMPLETE;
    120120
    121121    size_t inConsumed, outProduced;
     
    126126    m_inConsumed += inConsumed;
    127127    m_outProduced += outProduced;
    128     return INFO::CONTINUE;
     128    return INFO::OK;
    129129}
    130130
  • ps/trunk/source/lib/file/io/io.cpp

    r9447 r9871  
    3232
    3333namespace io {
    34 
    35 UniqueRange Allocate(size_t size, size_t alignment)
    36 {
    37     ENSURE(is_pow2(alignment));
    38     if(alignment <= (size_t)idxDeleterBits)
    39         alignment = idxDeleterBits+1;
    40 
    41     const size_t alignedSize = round_up(size, alignment);
    42     const UniqueRange::pointer p = rtl_AllocateAligned(alignedSize, alignment);
    43     return RVALUE(UniqueRange(p, size, idxDeleterAligned));
    44 }
    45 
    4634
    4735// this is just a thin wrapper on top of lowio and POSIX aio.
  • ps/trunk/source/lib/file/io/io.h

    r9580 r9871  
    3232#include "lib/alignment.h"
    3333#include "lib/bits.h"
     34#include "lib/timer.h"
    3435#include "lib/file/file.h"
    3536#include "lib/sysdep/filesystem.h"  // wtruncate
     
    5253// use this instead of the file cache for write buffers that are
    5354// never reused (avoids displacing other items).
    54 LIB_API UniqueRange Allocate(size_t size, size_t alignment = maxSectorSize);
     55static inline UniqueRange Allocate(size_t size, size_t alignment = maxSectorSize)
     56{
     57    return RVALUE(AllocateAligned(size, alignment));
     58}
    5559
    5660
     
    147151    /**
    148152     * called after a block I/O has completed.
    149      *
    150      * @return INFO::CONTINUE to proceed; any other value will
    151      * be immediately returned by Run.
     153     * @return Status (see RETURN_STATUS_FROM_CALLBACK).
    152154     *
    153155     * allows progress notification and processing data while waiting for
     
    156158    Status operator()(const u8* UNUSED(block), size_t UNUSED(blockSize)) const
    157159    {
    158         return INFO::CONTINUE;
     160        return INFO::OK;
    159161    }
    160162};
     
    165167    /**
    166168     * called before a block I/O is issued.
    167      *
    168      * @return INFO::CONTINUE to proceed; any other value will
    169      * be immediately returned by Run.
     169     * @return Status (see RETURN_STATUS_FROM_CALLBACK).
    170170     *
    171171     * allows generating the data to write while waiting for
     
    174174    Status operator()(aiocb& UNUSED(cb)) const
    175175    {
    176         return INFO::CONTINUE;
     176        return INFO::OK;
    177177    }
    178178};
     
    246246                cb.aio_nbytes = round_up(size_t(op.size - blocksIssued * p.blockSize), size_t(p.alignment));
    247247
    248             RETURN_IF_NOT_CONTINUE(issueHook(cb));
     248            RETURN_STATUS_FROM_CALLBACK(issueHook(cb));
    249249
    250250            RETURN_STATUS_IF_ERR(Issue(cb, p.queueDepth));
     
    254254        RETURN_STATUS_IF_ERR(WaitUntilComplete(cb, p.queueDepth));
    255255
    256         RETURN_IF_NOT_CONTINUE(completedHook((u8*)cb.aio_buf, cb.aio_nbytes));
     256        RETURN_STATUS_FROM_CALLBACK(completedHook((u8*)cb.aio_buf, cb.aio_nbytes));
    257257    }
    258258
     
    276276// Store
    277277
    278 // efficient writing requires preallocation, and the resulting file is
     278// efficient writing requires preallocation; the resulting file is
    279279// padded to the sector size and needs to be truncated afterwards.
    280280// this function takes care of both.
     
    317317// Load
    318318
    319 // convenience function provided for symmetry with Store
     319// convenience function provided for symmetry with Store.
    320320template<class CompletedHook, class IssueHook>
    321321static inline Status Load(const OsPath& pathname, void* buf, size_t size, const Parameters& p = Parameters(), const CompletedHook& completedHook = CompletedHook(), const IssueHook& issueHook = IssueHook())
  • ps/trunk/source/lib/posix/posix.cpp

    r9015 r9871  
    2323#include "precompiled.h"
    2424#include "lib/posix/posix.h"
    25 
    26 #if ARCH_IA32
    27 # include "lib/sysdep/arch/ia32/ia32_asm.h"
    28 #endif
    29 
    30 
    31 #if !HAVE_C99_MATH
    32 
    33 size_t fpclassifyd(double d)
    34 {
    35 #if ARCH_IA32
    36     return ia32_asm_fpclassifyd(d);
    37 #else
    38     // really sucky stub implementation; doesn't attempt to cover all cases.
    39 
    40     if(d != d)
    41         return FP_NAN;
    42     else
    43         return FP_NORMAL;
    44 #endif
    45 }
    46 
    47 size_t fpclassifyf(float f)
    48 {
    49 #if ARCH_IA32
    50     return ia32_asm_fpclassifyf(f);
    51 #else
    52     const double d = (double)f;
    53     return fpclassifyd(d);
    54 #endif
    55 }
    56 
    57 #endif  // #if !HAVE_C99_MATH
    5825
    5926
  • ps/trunk/source/lib/posix/posix.h

    r9572 r9871  
    116116#endif
    117117
    118 // fpclassify etc (too few/diverse to make separate HAVE_ for each)
    119 #if HAVE_C99 || ICC_VERSION || GCC_VERSION
    120 # define HAVE_C99_MATH 1
    121 #else
    122 # define HAVE_C99_MATH 0
    123 #endif
    124 
    125 #if !HAVE_C99_MATH
    126 extern size_t fpclassifyf(float f);
    127 extern size_t fpclassifyd(double d);
    128 #define fpclassify(x) ( (sizeof(x) == sizeof(float))? fpclassifyf(x) : fpclassifyd(x) )
    129 
    130 // these definitions "happen" to match IA32_FP_* and allow using
    131 // ia32_fp_classify without having to translate the return value.
    132 // we don't #define to IA32_FP_* to avoid dependency.
    133 #  define FP_NAN       0x0100
    134 #  define FP_NORMAL    0x0400
    135 #  define FP_INFINITE  (FP_NAN | FP_NORMAL)
    136 #  define FP_ZERO      0x4000
    137 #  define FP_SUBNORMAL (FP_NORMAL | FP_ZERO)
    138 
    139 # define isnan(d) (fpclassify(d) == FP_NAN)
    140 # define isfinite(d) ((fpclassify(d) & FP_NAN) == 0)
    141 # define isinf(d) (fpclassify(d) == (FP_NAN|FP_NORMAL))
    142 # define isnormal(d) (fpclassify(d) == FP_NORMAL)
    143 //# define signbit
    144 #else   // HAVE_C99_MATH
    145118// Some systems have C99 support but in C++ they provide only std::isfinite
    146119// and not isfinite. C99 specifies that isfinite is a macro, so we can use
    147120// #ifndef and define it if it's not there already.
    148121// We've included <cmath> above to make sure it defines that macro.
    149 # ifndef isfinite
    150 #  define fpclassify std::fpclassify
     122#ifndef isfinite
     123# if MSC_VERSION
     124#  define isfinite _finite
     125#  define isnan _isnan
     126# else
    151127#  define isfinite std::isfinite
    152128#  define isnan std::isnan
    153 #  define isinf std::isinf
    154 #  define isnormal std::isnormal
    155129# endif
    156 #endif  // HAVE_C99_MATH
     130#endif
    157131
    158132#endif  // #ifndef INCLUDED_POSIX
  • ps/trunk/source/lib/posix/tests/test_posix.h

    r7513 r9871  
    2828{
    2929public:
    30     template<typename T>
    31     void do_fpclassify()
    32     {
    33         T zero = 0.f;
    34         T one = 1.f;
    35         T inf = std::numeric_limits<T>::infinity();
    36         T ninf = -std::numeric_limits<T>::infinity();
    37         T qnan = std::numeric_limits<T>::quiet_NaN();
    38         T snan = std::numeric_limits<T>::signaling_NaN();
    39         T min = std::numeric_limits<T>::min();
    40         T sub = std::numeric_limits<T>::denorm_min();
    41         T sub2 = std::numeric_limits<T>::min() / 2;
    42 
    43         TS_ASSERT_EQUALS((int)fpclassify(zero), (int)FP_ZERO);
    44         TS_ASSERT_EQUALS((int)fpclassify(one), (int)FP_NORMAL);
    45         TS_ASSERT_EQUALS((int)fpclassify(inf), (int)FP_INFINITE);
    46         TS_ASSERT_EQUALS((int)fpclassify(ninf), (int)FP_INFINITE);
    47         TS_ASSERT_EQUALS((int)fpclassify(qnan), (int)FP_NAN);
    48         TS_ASSERT_EQUALS((int)fpclassify(snan), (int)FP_NAN);
    49         TS_ASSERT_EQUALS((int)fpclassify(min), (int)FP_NORMAL);
    50 #ifndef OS_WIN // http://trac.wildfiregames.com/ticket/478
    51         TS_ASSERT_EQUALS((int)fpclassify(sub), (int)FP_SUBNORMAL);
    52         TS_ASSERT_EQUALS((int)fpclassify(sub2), (int)FP_SUBNORMAL);
    53 #endif
    54 
    55         TS_ASSERT(!isnan(zero));
    56         TS_ASSERT(!isnan(one));
    57         TS_ASSERT(!isnan(inf));
    58         TS_ASSERT(!isnan(ninf));
    59         TS_ASSERT(isnan(qnan));
    60         TS_ASSERT(isnan(snan));
    61         TS_ASSERT(!isnan(min));
    62         TS_ASSERT(!isnan(sub));
    63         TS_ASSERT(!isnan(sub2));
    64 
    65         TS_ASSERT(isfinite(zero));
    66         TS_ASSERT(isfinite(one));
    67         TS_ASSERT(!isfinite(inf));
    68         TS_ASSERT(!isfinite(ninf));
    69         TS_ASSERT(!isfinite(qnan));
    70         TS_ASSERT(!isfinite(snan));
    71         TS_ASSERT(isfinite(min));
    72         TS_ASSERT(isfinite(sub));
    73         TS_ASSERT(isfinite(sub2));
    74 
    75         TS_ASSERT(!isinf(zero));
    76         TS_ASSERT(!isinf(one));
    77         TS_ASSERT(isinf(inf));
    78         TS_ASSERT(isinf(ninf));
    79         TS_ASSERT(!isinf(qnan));
    80         TS_ASSERT(!isinf(snan));
    81         TS_ASSERT(!isinf(min));
    82         TS_ASSERT(!isinf(sub));
    83         TS_ASSERT(!isinf(sub2));
    84 
    85         TS_ASSERT(!isnormal(zero));
    86         TS_ASSERT(isnormal(one));
    87         TS_ASSERT(!isnormal(inf));
    88         TS_ASSERT(!isnormal(ninf));
    89         TS_ASSERT(!isnormal(qnan));
    90         TS_ASSERT(!isnormal(snan));
    91         TS_ASSERT(isnormal(min));
    92 #ifndef OS_WIN // http://trac.wildfiregames.com/ticket/478
    93         TS_ASSERT(!isnormal(sub));
    94         TS_ASSERT(!isnormal(sub2));
    95 #endif
    96     }
    97 
    98     void test_fpclassifyf()
    99     {
    100         do_fpclassify<float>();
    101     }
    102 
    103     void test_fpclassifyd()
    104     {
    105         do_fpclassify<double>();
    106     }
    107 
    10830    void test_wcsdup()
    10931    {
  • ps/trunk/source/lib/res/sound/snd_mgr.cpp

    r9477 r9871  
    10101010 * @param al_buf buffer name.
    10111011 * @return Status, most commonly:
    1012  * INFO::CONTINUE = buffer has been returned; more are expected to be available.
    1013  * INFO::OK = buffer has been returned but is the last one (EOF).
     1012 * INFO::OK = buffer has been returned; more are expected to be available.
     1013 * INFO::ALL_COMPLETE = buffer has been returned but is the last one (EOF).
    10141014 */
    10151015static Status snd_data_buf_get(Handle hsd, ALuint& al_buf)
     
    10301030    al_buf = al_buf_alloc(data, (ALsizei)size, sd->al_fmt, sd->al_freq);
    10311031
    1032     return (size < maxBufferSize)? INFO::OK : INFO::CONTINUE;
     1032    return (size < maxBufferSize)? INFO::ALL_COMPLETE : INFO::OK;
    10331033}
    10341034
     
    16521652            Status ret = snd_data_buf_get(vs->hsd, al_buf);
    16531653            RETURN_STATUS_IF_ERR(ret);
    1654             if(ret == INFO::OK) // no further buffers will be forthcoming
     1654            if(ret == INFO::ALL_COMPLETE)   // no further buffers will be forthcoming
    16551655                vs->flags |= VS_EOF;
    16561656
  • ps/trunk/source/lib/status.cpp

    r9545 r9871  
    121121{ ERR::FAIL,            L"Function failed (no details available)" },
    122122
    123 { INFO::CONTINUE,       L"Continue (not an error)" },
    124123{ INFO::SKIPPED,        L"Skipped (not an error)" },
    125124{ INFO::CANNOT_HANDLE,  L"Cannot handle (not an error)" },
  • ps/trunk/source/lib/status.h

    r9545 r9871  
    311311    while(0)
    312312
     313// if expression (typically the invocation of a callback) evaluates to:
     314// - INFO::OK, do nothing;
     315// - INFO::ALL_COMPLETE, return INFO::OK;
     316// - anything else, return that.
     317#define RETURN_STATUS_FROM_CALLBACK(expression)\
     318    do\
     319    {\
     320        const Status status_ = (expression);\
     321        if(status_ == INFO::ALL_COMPLETE)\
     322            return INFO::OK;\
     323        else if(status_ != INFO::OK)\
     324            return status_;\
     325    }\
     326    while(0)
     327
    313328// return 0 if expression is negative. use in functions that return pointers.
    314329#define RETURN_0_IF_ERR(expression)\
     
    318333        if(status_ < 0)\
    319334            return 0;\
    320     }\
    321     while(0)
    322 
    323 // return expression if it evaluates to something other than
    324 // INFO::CONTINUE. use when invoking callbacks.
    325 #define RETURN_IF_NOT_CONTINUE(expression)\
    326     do\
    327     {\
    328         const Status status_ = (expression);\
    329         if(status_ != INFO::CONTINUE)\
    330             return status_;\
    331335    }\
    332336    while(0)
     
    363367    // note: these values are > 100 to allow multiplexing them with
    364368    // coroutine return values, which return completion percentage.
    365 
    366     // the function (usually a callback) would like to be called again.
    367     const Status CONTINUE      = +100000;
    368369
    369370    // notify caller that nothing was done.
  • ps/trunk/source/lib/sysdep/arch/ia32/ia32.cpp

    r9410 r9871  
    3030#include "lib/sysdep/arch/ia32/ia32.h"
    3131#include "lib/sysdep/arch/ia32/ia32_asm.h"
    32 
    33 
    34 static const size_t maxInstructionLength = 15;  // IA-32 limitation
    35 
    36 static bool IsCall(void* ret_addr, void*& target)
    37 {
    38     target = 0; // (not always possible to determine)
    39 
    40     // points to end of the CALL instruction (which is of unknown length)
    41     const u8* c = (const u8*)ret_addr;
    42     // this would allow for avoiding exceptions when accessing ret_addr
    43     // close to the beginning of the code segment. it's not currently set
    44     // because this is really unlikely and not worth the trouble.
    45     const size_t len = maxInstructionLength;
    46 
    47     // (most frequent cases first to reduce stack walk overhead:)
    48 
    49     // CALL rel32 (E8 cd)
    50     if(len >= 5 && c[-5] == 0xE8)
    51     {
    52         i32 offset;
    53         memcpy(&offset, c-sizeof(offset), sizeof(offset));
    54         target = (void*)(intptr_t(ret_addr) + intptr_t(offset));
    55         return true;
    56     }
    57 
    58     // CALL r32                    => FF D0-D7                 
    59     if(len >= 2 && c[-2] == 0xFF && (c[-1] & 0xF8) == 0xD0)
    60         return true;
    61 
    62     // CALL [r32 + disp8]          => FF 50-57(!54) disp8
    63     if(len >= 3 && c[-3] == 0xFF && (c[-2] & 0xF8) == 0x50 && c[-2] != 0x54)
    64         return true;
    65 
    66     // CALL [disp32]               => FF 15 disp32
    67     if(len >= 6 && c[-6] == 0xFF && c[-5] == 0x15)
    68     {
    69         void** addr_of_target;
    70         memcpy(&addr_of_target, c-sizeof(addr_of_target), sizeof(addr_of_target));
    71         target = *addr_of_target;
    72         // there are no meaningful checks we can perform: we're called from
    73         // the stack trace code, so ring0 addresses may be legit.
    74         // even if the pointer is 0, it's better to pass its value on
    75         // (may help in tracking down memory corruption)
    76         return true;
    77     }
    78 
    79     // CALL [r32 + r32*s]          => FF 14 SIB
    80     if(len >= 3 && c[-3] == 0xFF && c[-2] == 0x14)
    81         return true;
    82     // CALL [r32]                  => FF 00-3F(!14/15)
    83     if(len >= 2 && c[-2] == 0xFF && c[-1] < 0x40 && c[-1] != 0x14 && c[-1] != 0x15)
    84         return true;
    85     // CALL [r32 + r32*s + disp8]  => FF 54 SIB disp8
    86     if(len >= 4 && c[-4] == 0xFF && c[-3] == 0x54)
    87         return true;
    88     // CALL [r32 + r32*s + disp32] => FF 94 SIB disp32
    89     if(len >= 7 && c[-7] == 0xFF && c[-6] == 0x94)
    90         return true;
    91     // CALL [r32 + disp32]         => FF 90-97(!94) disp32
    92     if(len >= 6 && c[-6] == 0xFF && (c[-5] & 0xF8) == 0x90 && c[-5] != 0x94)
    93         return true;
    94 
    95     return false;
    96 }
    97 
    98 Status ia32_GetCallTarget(void* ret_addr, void*& target)
    99 {
    100     if(IsCall(ret_addr, target))
    101     {
    102         // follow the incremental linker's jump tables
    103         const u8* c = (const u8*)target;
    104         if(c && c[0] == 0xE9)
    105         {
    106             i32 offset;
    107             memcpy(&offset, c+1, sizeof(offset));
    108             target = (void*)(intptr_t(c)+5 + intptr_t(offset));
    109         }
    110 
    111         return INFO::OK;
    112     }
    113 
    114     const u8* const instructionWindow = (const u8*)ret_addr - maxInstructionLength;
    115     if(memchr(instructionWindow, 0xCC, maxInstructionLength))
    116         return ERR::AGAIN;  // NOWARN (debugger has inserted a breakpoint)
    117 
    118     // this shouldn't normally be reached but might happen if the
    119     // call stack is corrupted. note that we mustn't warn, because
    120     // this routine is already called from the stack dump chain.
    121     debug_break();
    122     return ERR::CPU_UNKNOWN_OPCODE; // NOWARN (see above)
    123 }
    124 
    125 
    126 void cpu_ConfigureFloatingPoint()
    127 {
    128     // no longer set 24 bit (float) precision by default: for
    129     // very long game uptimes (> 1 day; e.g. dedicated server),
    130     // we need full precision when calculating the time.
    131     // if there's a spot where we want to speed up divides|sqrts,
    132     // we can temporarily change precision there.
    133     //ia32_asm_control87(IA32_PC_24, IA32_MCW_PC);
    134 
    135     // to help catch bugs, enable as many floating-point exceptions as
    136     // possible. unfortunately SpiderMonkey triggers all of them.
    137     // note: passing a flag *disables* that exception.
    138     ia32_asm_control87(IA32_EM_ZERODIVIDE|IA32_EM_INVALID|IA32_EM_DENORMAL|IA32_EM_OVERFLOW|IA32_EM_UNDERFLOW|IA32_EM_INEXACT, IA32_MCW_EM);
    139 
    140     // no longer round toward zero (truncate). changing this setting
    141     // resulted in much faster float->int casts, because the compiler
    142     // could be told (via /QIfist) to use FISTP while still truncating
    143     // the result as required by ANSI C. however, FPU calculation
    144     // results were changed significantly, so it had to be disabled.
    145     //ia32_asm_control87(IA32_RC_CHOP, IA32_MCW_RC);
    146 }
    147 
    14832
    14933#if MSC_VERSION
  • ps/trunk/source/lib/sysdep/arch/ia32/ia32_asm.asm

    r8985 r9871  
    2020; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    2121
    22 ; optimized assembly code for IA-32. not provided as
    23 ; inline assembly because that's compiler-specific.
     22; assembly code for IA-32 (avoid inline assembly due to differing
     23; compiler support and/or syntax).
    2424
    2525%include "ia32.inc"
    26 
    27 ; note: pure asm functions prevent inlining but also avoid redundant
    28 ; store/loads generated by VC inline asm (ugh).
    29 
    3026
    3127;-------------------------------------------------------------------------------
     
    5551    pop     ebx
    5652    ret
    57 
    58 
    59 ;-------------------------------------------------------------------------------
    60 ; FPU
    61 ;-------------------------------------------------------------------------------
    62 
    63 ; extern "C" u32 __cdecl ia32_asm_control87(u32 new_cw, u32 mask);
    64 global sym(ia32_asm_control87)
    65 sym(ia32_asm_control87):
    66     push    eax
    67     fnstcw  [esp]
    68     pop     eax                         ; old_cw
    69     mov     ecx, [esp+4]                ; new_val
    70     mov     edx, [esp+8]                ; mask
    71     and     ecx, edx                    ; new_val & mask
    72     not     edx                         ; ~mask
    73     and     eax, edx                    ; old_cw & ~mask
    74     or      eax, ecx                    ; (old_cw & ~mask) | (new_val & mask)
    75     push    eax                         ; = new_cw
    76     fldcw   [esp]
    77     pop     eax
    78     xor     eax, eax                    ; return value
    79     ret
    80 
    81 
    82 ; possible IA-32 FPU control word flags after FXAM: NAN|NORMAL|ZERO
    83 FP_CLASSIFY_MASK    equ 0x4500
    84 
    85 ; extern "C" size_t __cdecl ia32_asm_fpclassifyd(double d);
    86 global sym(ia32_asm_fpclassifyd)
    87 sym(ia32_asm_fpclassifyd):
    88     fld     qword [esp+4]
    89     fxam
    90     fnstsw  ax
    91     fstp    st0
    92     and     eax, FP_CLASSIFY_MASK
    93     ret
    94 
    95 ; extern "C" size_t __cdecl ia32_asm_fpclassifyf(float f);
    96 global sym(ia32_asm_fpclassifyf)
    97 sym(ia32_asm_fpclassifyf):
    98     fld     dword [esp+4]
    99     fxam
    100     fnstsw  ax
    101     fstp    st0
    102     and     eax, FP_CLASSIFY_MASK
    103     ret
    104 
    105 
    106 ;-------------------------------------------------------------------------------
    107 ; misc
    108 ;-------------------------------------------------------------------------------
    109 
    110 ; write the current execution state (e.g. all register values) into
    111 ; (Win32::CONTEXT*)pcontext (defined as void* to avoid dependency).
    112 ; optimized for size; this must be straight asm because ; extern "C"
    113 ; is compiler-specific and compiler-generated prolog code inserted before
    114 ; inline asm trashes EBP and ESP (unacceptable).
    115 ; extern "C" void ia32_asm_GetCurrentContext(void* pcontext);
    116 global sym(ia32_asm_GetCurrentContext)
    117 sym(ia32_asm_GetCurrentContext):
    118     pushad
    119     pushfd
    120     mov     edi, [esp+4+32+4]   ; pcontext
    121 
    122     ; ContextFlags
    123     mov     eax, 0x10007        ; segs, int, control
    124     stosd
    125 
    126     ; DRx and FloatSave
    127     ; rationale: we can't access the debug registers from Ring3, and
    128     ; the FPU save area is irrelevant, so zero them.
    129     xor     eax, eax
    130     push    byte 6+8+20
    131     pop     ecx
    132 rep stosd
    133 
    134     ; CONTEXT_SEGMENTS
    135     mov     ax, gs
    136     stosd
    137     mov     ax, fs
    138     stosd
    139     mov     ax, es
    140     stosd
    141     mov     ax, ds
    142     stosd
    143 
    144     ; CONTEXT_INTEGER
    145     mov     eax, [esp+4+32-32]  ; edi
    146     stosd
    147     xchg    eax, esi
    148     stosd
    149     xchg    eax, ebx
    150     stosd
    151     xchg    eax, edx
    152     stosd
    153     mov     eax, [esp+4+32-8]   ; ecx
    154     stosd
    155     mov     eax, [esp+4+32-4]   ; eax
    156     stosd
    157 
    158     ; CONTEXT_CONTROL
    159     xchg    eax, ebp            ; ebp restored by POPAD
    160     stosd
    161     mov     eax, [esp+4+32]     ; return address
    162     sub     eax, 5              ; skip CALL instruction -> call site.
    163     stosd
    164     xor     eax, eax
    165     mov     ax, cs
    166     stosd
    167     pop     eax                 ; eflags
    168     stosd
    169     lea     eax, [esp+32+4+4]   ; esp
    170     stosd
    171     xor     eax, eax
    172     mov     ax, ss
    173     stosd
    174 
    175     ; ExtendedRegisters
    176     xor     ecx, ecx
    177     mov     cl, 512/4
    178 rep stosd
    179 
    180     popad
    181     ret
  • ps/trunk/source/lib/sysdep/arch/ia32/ia32_asm.h

    r9361 r9871  
    3131EXTERN_C void CALL_CONV ia32_asm_cpuid(x86_x64_CpuidRegs* regs);
    3232
    33 /// control87
    34 // FPU control word
    35 // .. Precision Control:
    36 const u32 IA32_MCW_PC = 0x0300;
    37 const u32 IA32_PC_24  = 0x0000;
    38 // .. Rounding Control:
    39 const u32 IA32_MCW_RC  = 0x0C00;
    40 const u32 IA32_RC_NEAR = 0x0000;
    41 const u32 IA32_RC_DOWN = 0x0400;
    42 const u32 IA32_RC_UP   = 0x0800;
    43 const u32 IA32_RC_CHOP = 0x0C00;
    44 // .. Exception Mask:
    45 const u32 IA32_MCW_EM        = 0x3F;
    46 const u32 IA32_EM_INVALID    = 0x01;
    47 const u32 IA32_EM_DENORMAL   = 0x02;
    48 const u32 IA32_EM_ZERODIVIDE = 0x04;
    49 const u32 IA32_EM_OVERFLOW   = 0x08;
    50 const u32 IA32_EM_UNDERFLOW  = 0x10;
    51 const u32 IA32_EM_INEXACT    = 0x20;
    52 /**
    53  * for all 1-bits in mask, update the corresponding FPU control word bits
    54  * with the bit values in new_val.
    55  * @return 0 to indicate success.
    56  **/
    57 EXTERN_C u32 CALL_CONV ia32_asm_control87(u32 new_val, u32 mask);
    58 
    59 /// POSIX fpclassify
    60 #define IA32_FP_NAN       0x0100
    61 #define IA32_FP_NORMAL    0x0400
    62 #define IA32_FP_INFINITE  (IA32_FP_NAN | IA32_FP_NORMAL)
    63 #define IA32_FP_ZERO      0x4000
    64 #define IA32_FP_SUBNORMAL (IA32_FP_NORMAL | IA32_FP_ZERO)
    65 EXTERN_C size_t CALL_CONV ia32_asm_fpclassifyd(double d);
    66 EXTERN_C size_t CALL_CONV ia32_asm_fpclassifyf(float f);
    67 
    68 /**
    69  * write the current execution state (e.g. all register values) into
    70  * (Win32::CONTEXT*)pcontext (defined as void* to avoid dependency).
    71  **/
    72 EXTERN_C void CALL_CONV ia32_asm_GetCurrentContext(void* pcontext);
    73 
    7433#endif  // #ifndef INCLUDED_IA32_ASM
  • ps/trunk/source/lib/sysdep/arch/x86_x64/topology.cpp

    r9870 r9871  
    2929
    3030#include <set>
    31 #include <bitset>
    3231
    3332#include "lib/bits.h"
     
    272271                    // generate fake but legitimate APIC IDs
    273272                    for(size_t processor = 0; processor < cpuTopology.numProcessors; processor++)
    274                         cpuTopology.apicIds[processor] = cpuTopology.sortedApicIds[processor] = processor;
     273                        cpuTopology.apicIds[processor] = cpuTopology.sortedApicIds[processor] = (ApicId)processor;
    275274                    return INFO::OK;
    276275                }
  • ps/trunk/source/lib/sysdep/arch/x86_x64/x86_x64.cpp

    r9846 r9871  
    4545#endif
    4646
    47 #define CPUID_INTRINSIC 0
     47#define HAVE_CPUIDEX 0
    4848#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 150030729    // __cpuidex available on VC10+ and VC9 SP1 (allows setting ecx beforehand)
    49 # undef CPUID_INTRINSIC
    50 # define CPUID_INTRINSIC 1
     49# undef HAVE_CPUIDEX
     50# define HAVE_CPUIDEX 1
    5151#else
    5252# if ARCH_AMD64
     
    7373static void cpuid(x86_x64_CpuidRegs* regs)
    7474{
    75 #if CPUID_INTRINSIC
     75#if HAVE_CPUIDEX
    7676    cassert(sizeof(regs->eax) == sizeof(int));
    7777    cassert(sizeof(*regs) == 4*sizeof(int));
  • ps/trunk/source/lib/sysdep/cpu.h

    r9410 r9871  
    103103}
    104104
    105 
    106 //-----------------------------------------------------------------------------
    107 // misc
    108 
    109 /**
    110  * set the FPU control word to "desirable" values (see implementation)
    111  **/
    112 LIB_API void cpu_ConfigureFloatingPoint();
    113 
    114 // NB: cpu_i64FromDouble et al. were faster than _ftol2, but are obsolete
    115 // since VC8 and GCC (with -ffast-math) generate SSE instructions.
    116 
    117105#endif  // #ifndef INCLUDED_CPU
  • ps/trunk/source/lib/sysdep/os/win/tests/test_wdbg_sym.h

    r9475 r9871  
    3434#include <stack>
    3535
     36#include "lib/bits.h"
    3637#include "lib/sysdep/os/win/win.h"  // HWND
    3738#include "lib/sysdep/sysdep.h"
     
    4647{
    4748    callers[numCallers++] = (void*)frame->AddrPC.Offset;
    48     return INFO::CONTINUE;
     49    return INFO::OK;
    4950}
    5051
     
    5758__declspec(noinline) static void Func1()
    5859{
    59     wdbg_sym_WalkStack(OnFrame, 0, 0, L"wdbg_sym_WalkStack");
     60    CONTEXT context;
     61    (void)debug_CaptureContext(&context);
     62    wdbg_sym_WalkStack(OnFrame, 0, context);
    6063}
    6164
     
    98101        wchar_t many_wchars[1024]; memset(many_wchars, 'a', sizeof(many_wchars));
    99102
    100         debug_printf(L"\n(dumping stack frames may result in access violations %.0d %.0c %.0c %.0g %.0g %.0d %.0d..)\n", ints[0], chars[0], many_wchars[0], large_array_of_large_structs[0].d1, small_array_of_large_structs[0].d1, large_array_of_small_structs[0].i1, small_array_of_small_structs[0].i1);
     103        debug_printf(L"\n(dumping stack frames may result in access violations...)\n");
     104        debug_printf(L"  locals: %.0d %.0c %.0c %.0g %.0g %.0d %.0d\n", ints[0], chars[0], many_wchars[0], large_array_of_large_structs[0].d1, small_array_of_large_structs[0].d1, large_array_of_small_structs[0].i1, small_array_of_small_structs[0].i1);
    101105
    102106        // note: we don't want any kind of dialog to be raised, because
     
    104108        // amount of text (not just "(failed)" error messages) was produced.
    105109        ErrorMessageMem emm = {0};
    106         const wchar_t* text = debug_BuildErrorMessage(L"dummy", 0,0,0, 0,L"debug_BuildErrorMessage", &emm);
     110        CACHE_ALIGNED u8 context[DEBUG_CONTEXT_SIZE];
     111        (void)debug_CaptureContext(context);
     112        const wchar_t* text = debug_BuildErrorMessage(L"dummy", 0,0,0, context, L"m_test_array", &emm);
    107113        TS_ASSERT(wcslen(text) > 500);
     114#if 0
    108115        {
    109116            std::wofstream s(L"d:\\out.txt");
    110117            s << text;
    111118        }
     119#endif
    112120        debug_FreeErrorMessage(&emm);
    113121
     
    288296    void test_stack_walk()
    289297    {
     298        Status ret;
     299
    290300        Func3();
    291301        TS_ASSERT(numCallers >= 3);
     302        size_t foundFunctionBits = 0;
    292303        void* funcAddresses[3] = { (void*)&Func1, (void*)&Func2, (void*)&Func3 };
    293         for(size_t i = 0; i < 3; i++)
    294         {
    295             wchar_t func1[DBG_SYMBOL_LEN], func2[DBG_SYMBOL_LEN];
    296             Status ret;
    297             ret = debug_ResolveSymbol(callers[i], func1, 0, 0);
     304        for(size_t idxCaller = 0; idxCaller < numCallers; idxCaller++)
     305        {
     306            wchar_t callerName[DEBUG_SYMBOL_CHARS];
     307            ret = debug_ResolveSymbol(callers[idxCaller], callerName, 0, 0);
    298308            TS_ASSERT_OK(ret);
    299             ret = debug_ResolveSymbol(funcAddresses[i], func2, 0, 0);
    300             TS_ASSERT_OK(ret);
    301             TS_ASSERT_WSTR_CONTAINS(func2, func1);
    302         }
     309
     310            wchar_t funcName[DEBUG_SYMBOL_CHARS];
     311            for(size_t idxFunc = 0; idxFunc < ARRAY_SIZE(funcAddresses); idxFunc++)
     312            {
     313                ret = debug_ResolveSymbol(funcAddresses[idxFunc], funcName, 0, 0);
     314                TS_ASSERT_OK(ret);
     315                if(wcsstr(funcName, callerName))
     316                    foundFunctionBits |= BIT(idxFunc);
     317            }
     318        }
     319        TS_ASSERT(foundFunctionBits == bit_mask<size_t>(ARRAY_SIZE(funcAddresses)));
    303320    }
    304321};
  • ps/trunk/source/lib/sysdep/os/win/wdbg_heap.cpp

    r9475 r9871  
    339339    {
    340340        if(!m_isRecordingKnownCallers)
    341             return INFO::SKIPPED;   // do not affect the stack walk
     341            return INFO::SKIPPED;
    342342
    343343        // last 'known' function has been reached
    344344        if(pc == (uintptr_t)&CallerFilter::CallHeapFunctions)
    345             return INFO::OK;    // stop stack walk
     345            return INFO::ALL_COMPLETE;
    346346
    347347        // pc is a 'known' function on the allocation hook's back-trace
    348348        // (e.g. _malloc_dbg and other helper functions)
    349349        m_knownCallers.Add(pc);
    350         return INFO::CONTINUE;
     350        return INFO::OK;
    351351    }
    352352
     
    676676    {
    677677        m_numCallers = 0;
    678         (void)wdbg_sym_WalkStack(OnFrame_Trampoline, (uintptr_t)this);
     678        CONTEXT context;
     679        (void)debug_CaptureContext(&context);
     680        (void)wdbg_sym_WalkStack(OnFrame_Trampoline, (uintptr_t)this, context);
    679681        std::fill(m_callers+m_numCallers, m_callers+maxCallers, 0);
    680682    }
     
    697699        // skip invalid frames
    698700        if(pc == 0)
    699             return INFO::CONTINUE;
     701            return INFO::OK;
    700702
    701703        Status ret = m_filter.NotifyOfCaller(pc);
     
    707709        // stop the stack walk if frame storage is full
    708710        if(m_numCallers >= maxCallers)
    709             return INFO::OK;
     711            return INFO::ALL_COMPLETE;
    710712
    711713        if(!m_filter.IsKnownCaller(pc))
    712714            m_callers[m_numCallers++] = pc;
    713         return INFO::CONTINUE;
     715        return INFO::OK;
    714716    }
    715717
     
    851853    for(size_t i = 0; i < numCallers; i++)
    852854    {
    853         wchar_t name[DBG_SYMBOL_LEN] = {'\0'}; wchar_t file[DBG_FILE_LEN] = {'\0'}; int line = -1;
     855        wchar_t name[DEBUG_SYMBOL_CHARS] = {'\0'}; wchar_t file[DEBUG_FILE_CHARS] = {'\0'}; int line = -1;
    854856        Status err = debug_ResolveSymbol((void*)callers[i], name, file, &line);
    855857        wdbg_printf(L"    ");
     
    945947
    946948    // load symbol information now (fails if it happens during shutdown)
    947     wchar_t name[DBG_SYMBOL_LEN]; wchar_t file[DBG_FILE_LEN]; int line;
     949    wchar_t name[DEBUG_SYMBOL_CHARS]; wchar_t file[DEBUG_FILE_CHARS]; int line;
    948950    (void)debug_ResolveSymbol(wdbg_heap_Init, name, file, &line);
    949951
  • ps/trunk/source/lib/sysdep/os/win/wdbg_sym.cpp

    r9519 r9871  
    2828#include "lib/sysdep/os/win/wdbg_sym.h"
    2929
    30 #include <stdlib.h>
    31 #include <stdio.h>
     30#include <cstdlib>
     31#include <cstdio>
    3232#include <set>
    3333
    34 #include "lib/byte_order.h"
     34#include "lib/byte_order.h" // movzx_le64
    3535#include "lib/module_init.h"
    3636#include "lib/sysdep/cpu.h"
    3737#include "lib/debug_stl.h"
    3838#include "lib/app_hooks.h"
    39 #if ARCH_IA32
    40 # include "lib/sysdep/arch/ia32/ia32.h"
    41 # include "lib/sysdep/arch/ia32/ia32_asm.h"
    42 #endif
    4339#include "lib/external_libraries/dbghelp.h"
    4440#include "lib/sysdep/os/win/wdbg.h"
    4541#include "lib/sysdep/os/win/wutil.h"
    46 
    47 
    48 #if ARCH_IA32 && !CONFIG_OMIT_FP
    49 # define IA32_STACK_WALK_ENABLED 1
    50 #else
    51 # define IA32_STACK_WALK_ENABLED 0
    52 #endif
     42#include "lib/sysdep/os/win/winit.h"
     43
     44WINIT_REGISTER_CRITICAL_INIT(wdbg_sym_Init);
     45
     46static WUTIL_FUNC(pRtlCaptureContext, VOID, (PCONTEXT));
     47
     48static Status wdbg_sym_Init()
     49{
     50    WUTIL_IMPORT_KERNEL32(RtlCaptureContext, pRtlCaptureContext);
     51    return INFO::OK;
     52}
    5353
    5454
     
    5757//----------------------------------------------------------------------------
    5858
    59 // passed to all dbghelp symbol query functions. we're not interested in
    60 // resolving symbols in other processes; the purpose here is only to
    61 // generate a stack trace. if that changes, we need to init a local copy
    62 // of these in dump_sym_cb and pass them to all subsequent dump_*.
     59// global for convenience (we only support a single process)
    6360static HANDLE hProcess;
    64 static uintptr_t mod_base;
    65 
    66 #if !IA32_STACK_WALK_ENABLED
     61
    6762// for StackWalk64; taken from PE header by InitDbghelp.
    6863static WORD machine;
    69 #endif
    7064
    7165static Status InitDbghelp()
     
    8175    // - do not set directly - that would zero any existing flags.
    8276    DWORD opts = pSymGetOptions();
     77    //opts |= SYMOPT_DEBUG; // lots of debug spew in output window
    8378    opts |= SYMOPT_DEFERRED_LOADS;  // the "fastest, most efficient way"
    84     //opts |= SYMOPT_DEBUG; // lots of debug spew in output window
     79    opts |= SYMOPT_LOAD_LINES;
    8580    opts |= SYMOPT_UNDNAME;
    8681    pSymSetOptions(opts);
     
    9691    WARN_IF_FALSE(ok);
    9792
    98     mod_base = (uintptr_t)pSymGetModuleBase64(hProcess, (u64)&InitDbghelp);
    99 
    100 #if !IA32_STACK_WALK_ENABLED
    101     IMAGE_NT_HEADERS* const header = pImageNtHeader((void*)(uintptr_t)mod_base);
     93    HMODULE hModule = GetModuleHandle(0);
     94    IMAGE_NT_HEADERS* const header = pImageNtHeader(hModule);
    10295    machine = header->FileHeader.Machine;
    103 #endif
    10496
    10597    return INFO::OK;
     
    110102// (on-demand initialization allows handling exceptions raised before
    111103// winit.cpp init functions are called)
     104//
     105// NB: this may take SECONDS if OS symbols are installed and
     106// symserv wants to access the internet.
    112107static void sym_init()
    113108{
    114109    static ModuleInitState initState;
    115110    ModuleInit(&initState, InitDbghelp);
     111}
     112
     113
     114static STACKFRAME64 PopulateStackFrame(CONTEXT& context)
     115{
     116    STACKFRAME64 sf;
     117    memset(&sf, 0, sizeof(sf));
     118    sf.AddrPC.Mode      = AddrModeFlat;
     119    sf.AddrFrame.Mode   = AddrModeFlat;
     120    sf.AddrStack.Mode   = AddrModeFlat;
     121#if ARCH_AMD64
     122    sf.AddrPC.Offset    = context.Rip;
     123    sf.AddrFrame.Offset = context.Rbp;
     124    sf.AddrStack.Offset = context.Rsp;
     125#else
     126    sf.AddrPC.Offset    = context.Eip;
     127    sf.AddrFrame.Offset = context.Ebp;
     128    sf.AddrStack.Offset = context.Esp;
     129#endif
     130    return sf;
     131}
     132
     133
     134static IMAGEHLP_STACK_FRAME PopulateImageStackFrame(const STACKFRAME64& sf)
     135{
     136    IMAGEHLP_STACK_FRAME isf;
     137    memset(&isf, 0, sizeof(isf));
     138    // apparently only PC, FP and SP are necessary, but
     139    // we copy everything to be safe.
     140    isf.InstructionOffset  = sf.AddrPC.Offset;
     141    isf.ReturnOffset       = sf.AddrReturn.Offset;
     142    isf.FrameOffset        = sf.AddrFrame.Offset;
     143    isf.StackOffset        = sf.AddrStack.Offset;
     144    isf.BackingStoreOffset = sf.AddrBStore.Offset;
     145    isf.FuncTableEntry     = (ULONG64)sf.FuncTableEntry;
     146    // (note: array of different types, can't copy directly)
     147    for(int i = 0; i < 4; i++)
     148        isf.Params[i] = sf.Params[i];
     149    // isf.Reserved - already zeroed
     150    isf.Virtual = sf.Virtual;
     151    // isf.Reserved2 - already zeroed
     152    return isf;
    116153}
    117154
     
    132169struct TI_FINDCHILDREN_PARAMS2
    133170{
    134     TI_FINDCHILDREN_PARAMS2(DWORD num_children)
     171    TI_FINDCHILDREN_PARAMS2(DWORD numChildren)
    135172    {
    136173        p.Start = 0;
    137         p.Count = std::min(num_children, MAX_CHILDREN);
    138     }
    139 
    140     static const DWORD MAX_CHILDREN = 300;
     174        p.Count = std::min(numChildren, maxChildren);
     175    }
     176
     177    static const DWORD maxChildren = 300;
    141178    TI_FINDCHILDREN_PARAMS p;
    142     DWORD additional_children[MAX_CHILDREN-1];
     179    DWORD childrenStorage[maxChildren-1];
    143180};
    144181
     
    153190
    154191    const DWORD64 addr = (DWORD64)ptr_of_interest;
    155     int successes = 0;
     192    size_t successes = 0;
    156193
    157194    WinScopedPreserveLastError s;   // SymFromAddrW, SymGetLineFromAddrW64
     
    166203        if(pSymFromAddrW(hProcess, addr, 0, sym))
    167204        {
    168             wcscpy_s(sym_name, DBG_SYMBOL_LEN, sym->Name);
     205            wcscpy_s(sym_name, DEBUG_SYMBOL_CHARS, sym->Name);
    169206            successes++;
    170207        }
     
    188225                // call site (full path is too long to display nicely).
    189226                const wchar_t* basename = path_name_only(line_info.FileName);
    190                 wcscpy_s(file, DBG_FILE_LEN, basename);
     227                wcscpy_s(file, DEBUG_FILE_CHARS, basename);
    191228                successes++;
    192229            }
     
    208245}
    209246
    210 // read and return symbol information for the given address. all of the
    211 // output parameters are optional; we pass back as much information as is
    212 // available and desired. return 0 iff any information was successfully
    213 // retrieved and stored.
    214 // sym_name and file must hold at least the number of chars above;
    215247// file is the base name only, not path (see rationale in wdbg_sym).
    216248// the PDB implementation is rather slow (~500µs).
     
    226258//----------------------------------------------------------------------------
    227259
    228 /*
    229 Subroutine linkage example code:
    230 
    231     push    param2
    232     push    param1
    233     call    func
    234 ret_addr:
    235     [..]
    236 
    237 func:
    238     push    ebp
    239     mov     ebp, esp
    240     sub     esp, local_size
    241     [..]
    242 
    243 Stack contents (down = decreasing address)
    244     [param2]
    245     [param1]
    246     ret_addr
    247     prev_ebp         (<- current ebp points at this value)
    248     [local_variables]
    249 */
    250 
    251 
    252 /*
    253     call    func1
    254 ret1:
    255 
    256 func1:
    257     push    ebp
    258     mov     ebp, esp
    259     call    func2
    260 ret2:
    261 
    262 func2:
    263     push    ebp
    264     mov     ebp, esp
    265     STARTHERE
    266 
    267     */
    268 
    269 #if IA32_STACK_WALK_ENABLED
    270 
    271 static Status ia32_walk_stack(_tagSTACKFRAME64* sf)
    272 {
    273     // read previous values from _tagSTACKFRAME64
    274     void* prev_fp  = (void*)(uintptr_t)sf->AddrFrame .Offset;
    275     void* prev_ip  = (void*)(uintptr_t)sf->AddrPC    .Offset;
    276     void* prev_ret = (void*)(uintptr_t)sf->AddrReturn.Offset;
    277     if(!debug_IsStackPointer(prev_fp))
    278         WARN_RETURN(ERR::_11);
    279     if(prev_ip && !debug_IsCodePointer(prev_ip))
    280         WARN_RETURN(ERR::_12);
    281     if(prev_ret && !debug_IsCodePointer(prev_ret))
    282         WARN_RETURN(ERR::_13);
    283 
    284     // read stack frame
    285     void* fp       = ((void**)prev_fp)[0];
    286     void* ret_addr = ((void**)prev_fp)[1];
    287     if(!fp)
    288         return INFO::ALL_COMPLETE;
    289     if(!debug_IsStackPointer(fp))
    290         WARN_RETURN(ERR::_14);
    291     if(!debug_IsCodePointer(ret_addr))
    292         return ERR::FAIL;   // NOWARN (invalid address)
    293 
    294     void* target;
    295     Status err = ia32_GetCallTarget(ret_addr, target);
    296     RETURN_STATUS_IF_ERR(err);
    297     if(target)  // were able to determine it from the call instruction
    298     {
    299         if(!debug_IsCodePointer(target))
    300             return ERR::FAIL;   // NOWARN (invalid address)
    301     }
    302 
    303     sf->AddrFrame .Offset = DWORD64(fp);
    304     sf->AddrStack .Offset = DWORD64(prev_fp)+8; // +8 reverts effects of call + push ebp
    305     sf->AddrPC    .Offset = DWORD64(target);
    306     sf->AddrReturn.Offset = DWORD64(ret_addr);
    307 
     260Status debug_CaptureContext(void* pcontext)
     261{
     262    // there are 4 ways to do so, in order of preference:
     263    // - RtlCaptureContext (only available on WinXP or above)
     264    // - assembly language subroutine (complicates the build system)
     265    // - intentionally raise an SEH exception and capture its context
     266    //   (causes annoying "first chance exception" messages and
     267    //   can't co-exist with WinScopedLock's destructor)
     268    // - GetThreadContext while suspended (a bit tricky + slow).
     269    //   note: it used to be common practice to query the current thread
     270    //   context, but WinXP SP2 and above require it be suspended.
     271
     272    if(!pRtlCaptureContext)
     273        return ERR::NOT_SUPPORTED;  // NOWARN
     274
     275    CONTEXT* context = (CONTEXT*)pcontext;
     276    cassert(sizeof(CONTEXT) <= DEBUG_CONTEXT_SIZE);
     277    memset(context, 0, sizeof(CONTEXT));
     278    context->ContextFlags = CONTEXT_FULL;
     279    pRtlCaptureContext(context);
    308280    return INFO::OK;
    309281}
    310282
     283
     284static Status CallStackWalk(STACKFRAME64& sf, CONTEXT& context)
     285{
     286    WinScopedLock lock(WDBG_SYM_CS);
     287
     288    SetLastError(0);    // StackWalk64 doesn't always SetLastError
     289    const HANDLE hThread = GetCurrentThread();
     290    if(!pStackWalk64(machine, hProcess, hThread, &sf, &context, 0, pSymFunctionTableAccess64, pSymGetModuleBase64, 0))
     291        return ERR::FAIL; // NOWARN (no stack frames left)
     292
     293    // (the frame pointer can be zero despite StackWalk64 returning TRUE.)
     294    if(sf.AddrFrame.Offset == 0)
     295        return ERR::FAIL;   // NOWARN (no stack frames left)
     296
     297    // huge WTF in x64 debug builds (dbghelp 6.12.0002.633):
     298    // AddrFrame.Offset doesn't match the correct RBP value.
     299    // StackWalk64 updates the context [http://bit.ly/lo1aqZ] and
     300    // its Rbp is correct, so we'll use that.
     301#if ARCH_AMD64
     302    sf.AddrFrame.Offset = context.Rbp;
    311303#endif
    312304
    313 
    314 // note: RtlCaptureStackBackTrace (http://msinilo.pl/blog/?p=40)
    315 // is likely to be much faster than StackWalk64 (especially relevant
    316 // for debug_GetCaller), but wasn't known during development and
    317 // remains undocumented.
    318 
    319 Status wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, const CONTEXT* pcontext, const wchar_t* lastFuncToSkip)
    320 {
    321     // to function properly, StackWalk64 requires a CONTEXT on
    322     // non-x86 systems (documented) or when in release mode (observed).
    323     // exception handlers can call wdbg_sym_WalkStack with their context record;
    324     // otherwise (e.g. dump_stack from ENSURE), we need to query it.
    325     CONTEXT context;
    326     // .. caller knows the context (most likely from an exception);
    327     //    since StackWalk64 may modify it, copy to a local variable.
    328     if(pcontext)
    329         context = *pcontext;
    330     // .. need to determine context ourselves.
    331     else
    332     {
    333         // there are 4 ways to do so, in order of preference:
    334         // - asm (easy to use but currently only implemented on IA32)
    335         // - RtlCaptureContext (only available on WinXP or above)
    336         // - intentionally raise an SEH exception and capture its context
    337         //   (causes annoying "first chance exception" messages and
    338         //   can't co-exist with WinScopedLock's destructor)
    339         // - GetThreadContext while suspended (a bit tricky + slow).
    340         //   note: it used to be common practice to query the current thread
    341         //   context, but WinXP SP2 and above require it be suspended.
    342         //
    343         // this MUST be done inline and not in an external function because
    344         // compiler-generated prolog code trashes some registers.
    345 
    346 #if ARCH_IA32
    347         ia32_asm_GetCurrentContext(&context);
    348 #else
    349         // we need to capture the context ASAP, lest more registers be
    350         // clobbered. since sym_init is no longer called from winit, the
    351         // best we can do is import the function pointer directly.
    352         static WUTIL_FUNC(pRtlCaptureContext, VOID, (PCONTEXT));
    353         if(!pRtlCaptureContext)
    354         {
    355             WUTIL_IMPORT_KERNEL32(RtlCaptureContext, pRtlCaptureContext);
    356             if(!pRtlCaptureContext)
    357                 return ERR::NOT_SUPPORTED;  // NOWARN
    358         }
    359         memset(&context, 0, sizeof(context));
    360         context.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER;
    361         pRtlCaptureContext(&context);
    362 #endif
    363     }
    364     pcontext = &context;
    365 
    366     _tagSTACKFRAME64 sf;
    367     memset(&sf, 0, sizeof(sf));
    368     sf.AddrPC.Mode      = AddrModeFlat;
    369     sf.AddrFrame.Mode   = AddrModeFlat;
    370     sf.AddrStack.Mode   = AddrModeFlat;
    371 #if ARCH_AMD64
    372     sf.AddrPC.Offset    = pcontext->Rip;
    373     sf.AddrFrame.Offset = pcontext->Rbp;
    374     sf.AddrStack.Offset = pcontext->Rsp;
    375 #else
    376     sf.AddrPC.Offset    = pcontext->Eip;
    377     sf.AddrFrame.Offset = pcontext->Ebp;
    378     sf.AddrStack.Offset = pcontext->Esp;
    379 #endif
    380 
    381 #if !IA32_STACK_WALK_ENABLED
     305    return INFO::OK;
     306}
     307
     308
     309// NB: CaptureStackBackTrace may be faster (http://msinilo.pl/blog/?p=40),
     310// but wasn't known during development.
     311Status wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, CONTEXT& context, const wchar_t* lastFuncToSkip)
     312{
    382313    sym_init();
    383 #endif
    384 
    385     // for each stack frame found:
    386     Status ret  = ERR::SYM_NO_STACK_FRAMES_FOUND;
    387     for(;;)
    388     {
    389         // rationale:
    390         // - provide a separate ia32 implementation so that simple
    391         //   stack walks (e.g. to determine callers of malloc) do not
    392         //   require firing up dbghelp. that takes tens of seconds when
    393         //   OS symbols are installed (because symserv is wanting to access
    394         //   the internet), which is entirely unacceptable.
    395         // - VC7.1 sometimes generates stack frames despite /Oy ;
    396         //   ia32_walk_stack may appear to work, but it isn't reliable in
    397         //   this case and therefore must not be used!
    398         // - don't switch between ia32_stack_walk and StackWalk64 when one
    399         //   of them fails: this needlessly complicates things. the ia32
    400         //   code is authoritative provided its prerequisite (FP not omitted)
    401         //   is met, otherwise totally unusable.
    402         Status err;
    403 #if IA32_STACK_WALK_ENABLED
    404         err = ia32_walk_stack(&sf);
    405 #else
    406         {
    407             WinScopedLock lock(WDBG_SYM_CS);
    408 
    409             // note: unfortunately StackWalk64 doesn't always SetLastError,
    410             // so we have to reset it and check for 0. *sigh*
    411             SetLastError(0);
    412             const HANDLE hThread = GetCurrentThread();
    413             const BOOL ok = pStackWalk64(machine, hProcess, hThread, &sf, (PVOID)pcontext, 0, pSymFunctionTableAccess64, pSymGetModuleBase64, 0);
    414             err = ok? INFO::OK : ERR::FAIL; // NOWARN (no stack frames are left)
    415         }
    416 #endif
    417 
    418         // no more frames found - abort. note: also test FP because
    419         // StackWalk64 sometimes erroneously reports success.
    420         void* const fp = (void*)(uintptr_t)sf.AddrFrame.Offset;
    421         if(err != INFO::OK || !fp)
     314
     315    STACKFRAME64 sf = PopulateStackFrame(context);
     316   
     317    wchar_t func[DEBUG_SYMBOL_CHARS];
     318
     319    Status ret = ERR::SYM_NO_STACK_FRAMES_FOUND;
     320    for(;;) // each stack frame:
     321    {
     322        if(CallStackWalk(sf, context) != INFO::OK)
    422323            return ret;
    423324
     
    425326        {
    426327            void* const pc = (void*)(uintptr_t)sf.AddrPC.Offset;
    427             wchar_t func[DBG_SYMBOL_LEN];
    428             err = debug_ResolveSymbol(pc, func, 0, 0);
    429             if(err == INFO::OK)
     328            if(debug_ResolveSymbol(pc, func, 0, 0) == INFO::OK)
    430329            {
    431                 if(wcsstr(func, lastFuncToSkip))
     330                if(wcsstr(func, lastFuncToSkip))    // this was the last one to skip
    432331                    lastFuncToSkip = 0;
    433332                continue;
     
    436335
    437336        ret = cb(&sf, cbData);
    438         // callback is allowing us to continue
    439         if(ret == INFO::CONTINUE)
    440             ret = INFO::OK;
    441         // callback reports it's done; stop calling it and return that value.
    442         // (can be either success or failure)
    443         else
    444         {
    445             ENSURE(ret <= 0);   // shouldn't return > 0
    446             return ret;
    447         }
    448     }
    449 }
    450 
    451 
    452 //
    453 // get address of Nth function above us on the call stack (uses wdbg_sym_WalkStack)
    454 //
    455 
    456 // called by wdbg_sym_WalkStack for each stack frame
    457 static Status nth_caller_cb(const _tagSTACKFRAME64* sf, uintptr_t cbData)
    458 {
    459     void** pfunc = (void**)cbData;
    460 
    461     // return its address
    462     *pfunc = (void*)(uintptr_t)sf->AddrPC.Offset;
    463     return INFO::OK;
    464 }
     337        RETURN_STATUS_FROM_CALLBACK(ret);
     338    }
     339}
     340
    465341
    466342void* debug_GetCaller(void* pcontext, const wchar_t* lastFuncToSkip)
    467343{
     344    struct StoreAddress
     345    {
     346        static Status Func(const STACKFRAME64* sf, uintptr_t cbData)
     347        {
     348            const uintptr_t funcAddress = sf->AddrPC.Offset;
     349
     350            // store funcAddress in our `output parameter'
     351            memcpy((void*)cbData, &funcAddress, sizeof(funcAddress));
     352
     353            return INFO::OK;
     354        }
     355    };
    468356    void* func;
    469     Status ret = wdbg_sym_WalkStack(nth_caller_cb, (uintptr_t)&func, (const CONTEXT*)pcontext, lastFuncToSkip);
     357    wdbg_assert(pcontext != 0);
     358    Status ret = wdbg_sym_WalkStack(&StoreAddress::Func, (uintptr_t)&func, *(CONTEXT*)pcontext, lastFuncToSkip);
    470359    return (ret == INFO::OK)? func : 0;
    471360}
    472361
    473362
    474 
    475363//-----------------------------------------------------------------------------
    476364// helper routines for symbol value dump
     
    478366
    479367// infinite recursion has never happened, but we check for it anyway.
    480 static const size_t MAX_INDIRECTION = 255;
    481 static const size_t MAX_LEVEL = 255;
     368static const size_t maxIndirection = 255;
     369static const size_t maxLevel = 255;
    482370
    483371struct DumpState
     
    485373    size_t level;
    486374    size_t indirection;
    487 
    488     DumpState()
    489     {
    490         level = 0;
    491         indirection = 0;
     375    uintptr_t moduleBase;
     376    LPSTACKFRAME64 stackFrame;
     377
     378    DumpState(uintptr_t moduleBase, LPSTACKFRAME64 stackFrame)
     379        : level(0), indirection(0), moduleBase(moduleBase), stackFrame(stackFrame)
     380    {
    492381    }
    493382};
     383
    494384
    495385//----------------------------------------------------------------------------
     
    653543
    654544// forward decl; called by dump_sequence and some of dump_sym_*.
    655 static Status dump_sym(DWORD id, const u8* p, DumpState state);
     545static Status dump_sym(DWORD id, const u8* p, DumpState& state);
    656546
    657547// from cvconst.h
    658548//
    659549// rationale: we don't provide a get_register routine, since only the
    660 // value of FP is known to dump_frame_cb (via _tagSTACKFRAME64).
     550// value of FP is known to dump_frame_cb (via STACKFRAME64).
    661551// displaying variables stored in registers is out of the question;
    662552// all we can do is display FP-relative variables.
     
    664554{
    665555    CV_REG_EBP = 22,
    666     CV_AMD64_RSP = 335
     556    CV_AMD64_RBP = 334
    667557};
    668558
     
    700590
    701591
    702 // split out of dump_sequence.
     592// moved out of dump_sequence.
    703593static Status dump_string(const u8* p, size_t el_size)
    704594{
     
    734624
    735625
    736 // split out of dump_sequence.
     626// moved out of dump_sequence.
    737627static void seq_determine_formatting(size_t el_size, size_t el_count, bool* fits_on_one_line, size_t* num_elements_to_show)
    738628{
     
    760650
    761651
    762 static Status dump_sequence(DebugStlIterator el_iterator, void* internal, size_t el_count, DWORD el_type_id, size_t el_size, DumpState state)
     652static Status dump_sequence(DebugStlIterator el_iterator, void* internal, size_t el_count, DWORD el_type_id, size_t el_size, DumpState& state)
    763653{
    764654    const u8* el_p = 0; // avoid "uninitialized" warning
     
    832722
    833723
    834 static Status dump_array(const u8* p, size_t el_count, DWORD el_type_id, size_t el_size, DumpState state)
     724static Status dump_array(const u8* p, size_t el_count, DWORD el_type_id, size_t el_size, DumpState& state)
    835725{
    836726    const u8* iterator_internal_pos = p;
     
    839729}
    840730
    841 
    842 static const _tagSTACKFRAME64* current_stackframe64;
    843731
    844732static Status CanHandleDataKind(DWORD dataKind)
     
    880768    if((flags & SYMFLAG_REGREL) == 0)
    881769        return false;
    882     if(reg == CV_REG_EBP || reg == CV_AMD64_RSP)
     770    if(reg == CV_REG_EBP || reg == CV_AMD64_RBP)
    883771        return true;
    884772    return false;
     
    903791}
    904792
    905 static Status DetermineSymbolAddress(DWORD id, const SYMBOL_INFOW* sym, const u8** pp)
    906 {
    907     const _tagSTACKFRAME64* sf = current_stackframe64;
    908 
     793static Status DetermineSymbolAddress(DWORD id, const SYMBOL_INFOW* sym, const DumpState& state, const u8** pp)
     794{
    909795    DWORD dataKind;
    910     if(!pSymGetTypeInfo(hProcess, mod_base, id, TI_GET_DATAKIND, &dataKind))
     796    if(!pSymGetTypeInfo(hProcess, state.moduleBase, id, TI_GET_DATAKIND, &dataKind))
    911797        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    912798    Status ret = CanHandleDataKind(dataKind);
     
    921807    uintptr_t addr = (uintptr_t)sym->Address;
    922808    if(IsRelativeToFramePointer(sym->Flags, sym->Register))
    923     {
    924 #if ARCH_AMD64
    925         addr += (uintptr_t)sf->AddrStack.Offset;
    926 #else
    927         addr += (uintptr_t)sf->AddrFrame.Offset;
    928 # if defined(NDEBUG)
    929         // NB: the addresses of register-relative symbols are apparently
    930         // incorrect [VC8, 32-bit Wow64]. the problem occurs regardless of
    931         // IA32_STACK_WALK_ENABLED and with both ia32_asm_GetCurrentContext
    932         // and RtlCaptureContext. the EBP, ESP and EIP values returned by
    933         // ia32_asm_GetCurrentContext match those reported by the IDE, so
    934         // the problem appears to lie in the offset values stored in the PDB.
    935         if(sym->Flags & SYMFLAG_PARAMETER)
    936             addr += sizeof(void*);
    937         else
    938             addr += sizeof(void*) * 2;
    939 # endif
    940 #endif
    941     }
     809        addr += (uintptr_t)state.stackFrame->AddrFrame.Offset;
    942810    else if(IsUnretrievable(sym->Flags))
    943811        return ERR::SYM_UNRETRIEVABLE;  // NOWARN
     
    945813    *pp = (const u8*)(uintptr_t)addr;
    946814
    947     debug_printf(L"SYM| %ls at %p  flags=%X dk=%d sym->addr=%I64X fp=%I64x\n", sym->Name, *pp, sym->Flags, dataKind, sym->Address, sf->AddrFrame.Offset);
     815    debug_printf(L"SYM| %ls at %p  flags=%X dk=%d sym->addr=%I64X fp=%I64x\n", sym->Name, *pp, sym->Flags, dataKind, sym->Address, state.stackFrame->AddrFrame.Offset);
    948816    return INFO::OK;
    949817}
     
    959827// called by dump_sym; lock is held.
    960828
    961 static Status dump_sym_array(DWORD type_id, const u8* p, DumpState state)
     829static Status dump_sym_array(DWORD type_id, const u8* p, DumpState& state)
    962830{
    963     ULONG64 size_ = 0;
    964     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
    965         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    966     const size_t size = (size_t)size_;
     831    ULONG64 size64 = 0;
     832    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_LENGTH, &size64))
     833        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     834    const size_t size = (size_t)size64;
    967835
    968836    // get element count and size
    969837    DWORD el_type_id = 0;
    970     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_TYPEID, &el_type_id))
     838    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_TYPEID, &el_type_id))
    971839        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    972840    // .. workaround: TI_GET_COUNT returns total struct size for
    973841    //    arrays-of-struct. therefore, calculate as size / el_size.
    974842    ULONG64 el_size_;
    975     if(!pSymGetTypeInfo(hProcess, mod_base, el_type_id, TI_GET_LENGTH, &el_size_))
     843    if(!pSymGetTypeInfo(hProcess, state.moduleBase, el_type_id, TI_GET_LENGTH, &el_size_))
    976844        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    977845    const size_t el_size = (size_t)el_size_;
     
    1000868
    1001869
    1002 static Status dump_sym_base_type(DWORD type_id, const u8* p, DumpState state)
     870static Status dump_sym_base_type(DWORD type_id, const u8* p, DumpState& state)
    1003871{
    1004872    DWORD base_type;
    1005     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_BASETYPE, &base_type))
    1006         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1007     ULONG64 size_ = 0;
    1008     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
    1009         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1010     const size_t size = (size_t)size_;
     873    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_BASETYPE, &base_type))
     874        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     875    ULONG64 size64 = 0;
     876    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_LENGTH, &size64))
     877        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     878    const size_t size = (size_t)size64;
    1011879
    1012880    // single out() call. note: we pass a single u64 for all sizes,
     
    1024892            break;
    1025893        if(i == size-1)
    1026             goto display_as_hex;
     894        {
     895            out(L"(uninitialized)");
     896            return INFO::OK;
     897        }
    1027898    }
    1028899
     
    1063934    case btUInt:
    1064935    case btULong:
    1065 display_as_hex:
    1066936        if(size == 1)
    1067937        {
     
    11341004//-----------------------------------------------------------------------------
    11351005
    1136 static Status dump_sym_base_class(DWORD type_id, const u8* p, DumpState state)
     1006static Status dump_sym_base_class(DWORD type_id, const u8* p, DumpState& state)
    11371007{
    11381008    DWORD base_class_type_id;
    1139     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_TYPEID, &base_class_type_id))
     1009    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_TYPEID, &base_class_type_id))
    11401010        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    11411011
     
    11441014    // and just not worth it.
    11451015    DWORD vptr_ofs;
    1146     if(pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_VIRTUALBASEPOINTEROFFSET, &vptr_ofs))
     1016    if(pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_VIRTUALBASEPOINTEROFFSET, &vptr_ofs))
    11471017        return ERR::SYM_UNSUPPORTED;    // NOWARN
    11481018
     
    11531023//-----------------------------------------------------------------------------
    11541024
    1155 static Status dump_sym_data(DWORD id, const u8* p, DumpState state)
     1025static Status dump_sym_data(DWORD id, const u8* p, DumpState& state)
    11561026{
    11571027    SYMBOL_INFO_PACKAGEW2 sp;
    11581028    SYMBOL_INFOW* sym = &sp.si;
    1159     if(!pSymFromIndexW(hProcess, mod_base, id, sym))
     1029    if(!pSymFromIndexW(hProcess, state.moduleBase, id, sym))
    11601030        RETURN_STATUS_IF_ERR(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    11611031
     
    11641034    __try
    11651035    {
    1166         RETURN_STATUS_IF_ERR(DetermineSymbolAddress(id, sym, &p));
     1036        RETURN_STATUS_IF_ERR(DetermineSymbolAddress(id, sym, state, &p));
    11671037        // display value recursively
    11681038        return dump_sym(sym->TypeIndex, p, state);
     
    11771047//-----------------------------------------------------------------------------
    11781048
    1179 static Status dump_sym_enum(DWORD type_id, const u8* p, DumpState UNUSED(state))
    1180 {
    1181     ULONG64 size_ = 0;
    1182     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
    1183         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1184     const size_t size = (size_t)size_;
     1049static Status dump_sym_enum(DWORD type_id, const u8* p, DumpState& state)
     1050{
     1051    ULONG64 size64 = 0;
     1052    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_LENGTH, &size64))
     1053        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     1054    const size_t size = (size_t)size64;
    11851055
    11861056    const i64 enum_value = movsx_le64(p, size);
    11871057
    11881058    // get array of child symbols (enumerants).
    1189     DWORD num_children;
    1190     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_CHILDRENCOUNT, &num_children))
    1191         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1192     TI_FINDCHILDREN_PARAMS2 fcp(num_children);
    1193     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_FINDCHILDREN, &fcp))
    1194         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1195     num_children = fcp.p.Count; // was truncated to MAX_CHILDREN
     1059    DWORD numChildren;
     1060    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_CHILDRENCOUNT, &numChildren))
     1061        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     1062    TI_FINDCHILDREN_PARAMS2 fcp(numChildren);
     1063    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_FINDCHILDREN, &fcp))
     1064        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     1065    numChildren = fcp.p.Count;  // was truncated to maxChildren
    11961066    const DWORD* children = fcp.p.ChildId;
    11971067
    11981068    // for each child (enumerant):
    1199     for(size_t i = 0; i < num_children; i++)
     1069    for(size_t i = 0; i < numChildren; i++)
    12001070    {
    12011071        DWORD child_data_id = children[i];
     
    12071077        // already pulled in by e.g. OpenGL anyway.
    12081078        VARIANT v;
    1209         if(!pSymGetTypeInfo(hProcess, mod_base, child_data_id, TI_GET_VALUE, &v))
     1079        if(!pSymGetTypeInfo(hProcess, state.moduleBase, child_data_id, TI_GET_VALUE, &v))
    12101080            WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    12111081        if(VariantChangeType(&v, &v, 0, VT_I8) != S_OK)
     
    12161086        {
    12171087            const wchar_t* name;
    1218             if(!pSymGetTypeInfo(hProcess, mod_base, child_data_id, TI_GET_SYMNAME, &name))
     1088            if(!pSymGetTypeInfo(hProcess, state.moduleBase, child_data_id, TI_GET_SYMNAME, &name))
    12191089                WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    12201090            out(L"%ls", name);
     
    12351105//-----------------------------------------------------------------------------
    12361106
    1237 static Status dump_sym_function(DWORD UNUSED(type_id), const u8* UNUSED(p), DumpState UNUSED(state))
     1107static Status dump_sym_function(DWORD UNUSED(type_id), const u8* UNUSED(p), DumpState& UNUSED(state))
    12381108{
    12391109    return INFO::SYM_SUPPRESS_OUTPUT;
     
    12431113//-----------------------------------------------------------------------------
    12441114
    1245 static Status dump_sym_function_type(DWORD UNUSED(type_id), const u8* p, DumpState state)
     1115static Status dump_sym_function_type(DWORD UNUSED(type_id), const u8* p, DumpState& state)
    12461116{
    12471117    // this symbol gives class parent, return type, and parameter count.
     
    12491119    // isn't exposed via TI_GET_SYMNAME, so we resolve it ourselves.
    12501120
    1251     wchar_t name[DBG_SYMBOL_LEN];
     1121    wchar_t name[DEBUG_SYMBOL_CHARS];
    12521122    Status err = ResolveSymbol_lk((void*)p, name, 0, 0);
    12531123
     
    13111181
    13121182
    1313 static Status dump_sym_pointer(DWORD type_id, const u8* p, DumpState state)
    1314 {
    1315     ULONG64 size_ = 0;
    1316     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
    1317         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1318     const size_t size = (size_t)size_;
     1183static Status dump_sym_pointer(DWORD type_id, const u8* p, DumpState& state)
     1184{
     1185    ULONG64 size64 = 0;
     1186    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_LENGTH, &size64))
     1187        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     1188    const size_t size = (size_t)size64;
    13191189
    13201190    // read+output pointer's value.
     
    13401210    // the responsible dump_sym* will erase "->", leaving only address.
    13411211    out(L" -> ");
    1342     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_TYPEID, &type_id))
     1212    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_TYPEID, &type_id))
    13431213        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    13441214
    13451215    // prevent infinite recursion just to be safe (shouldn't happen)
    1346     if(state.indirection >= MAX_INDIRECTION)
     1216    if(state.indirection >= maxIndirection)
    13471217        WARN_RETURN(ERR::SYM_NESTING_LIMIT);
    13481218    state.indirection++;
     
    13541224
    13551225
    1356 static Status dump_sym_typedef(DWORD type_id, const u8* p, DumpState state)
    1357 {
    1358     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_TYPEID, &type_id))
     1226static Status dump_sym_typedef(DWORD type_id, const u8* p, DumpState& state)
     1227{
     1228    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_TYPEID, &type_id))
    13591229        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    13601230    return dump_sym(type_id, p, state);
     
    13681238// useful for UDTs that contain typedefs describing their contents,
    13691239// e.g. value_type in STL containers.
    1370 static Status udt_get_child_type(const wchar_t* child_name, ULONG num_children, const DWORD* children, DWORD* el_type_id, size_t* el_size)
     1240static Status udt_get_child_type(const wchar_t* child_name, ULONG numChildren, const DWORD* children, const DumpState& state, DWORD* el_type_id, size_t* el_size)
    13711241{
    13721242    const DWORD lastError = GetLastError();
     
    13751245    *el_size = 0;
    13761246
    1377     for(ULONG i = 0; i < num_children; i++)
     1247    for(ULONG i = 0; i < numChildren; i++)
    13781248    {
    13791249        const DWORD child_id = children[i];
     
    13811251        SYMBOL_INFO_PACKAGEW2 sp;
    13821252        SYMBOL_INFOW* sym = &sp.si;
    1383         if(!pSymFromIndexW(hProcess, mod_base, child_id, sym))
     1253        if(!pSymFromIndexW(hProcess, state.moduleBase, child_id, sym))
    13841254        {
    13851255            // this happens for several UDTs; cause is unknown.
     
    14021272
    14031273
    1404 static Status udt_dump_std(const wchar_t* type_name, const u8* p, size_t size, DumpState state, ULONG num_children, const DWORD* children)
     1274static Status udt_dump_std(const wchar_t* type_name, const u8* p, size_t size, DumpState& state, ULONG numChildren, const DWORD* children)
    14051275{
    14061276    Status err;
     
    14111281
    14121282    // check for C++ objects that should be displayed via udt_dump_normal.
    1413     // STL containers are special-cased and the rest (apart from those here)
     1283    // C++03 containers are special-cased and the rest (apart from those here)
    14141284    // are ignored, because for the most part they are spew.
    1415     if(!wcsncmp(type_name, L"std::pair", 9))
     1285    if(!wcsncmp(type_name, L"std::pair", 9) ||
     1286       !wcsncmp(type_name, L"std::tr1::", 10))
    14161287        return INFO::CANNOT_HANDLE;
    14171288
     
    14201291    DWORD el_type_id;
    14211292    size_t el_size;
    1422     err = udt_get_child_type(L"value_type", num_children, children, &el_type_id, &el_size);
     1293    err = udt_get_child_type(L"value_type", numChildren, children, state, &el_type_id, &el_size);
    14231294    if(err != INFO::OK)
    14241295        goto not_valid_container;
     
    14431314        text = L"";
    14441315    // .. not one of the containers we can analyse.
    1445     if(err == ERR::STL_CNT_UNKNOWN)
     1316    else if(err == ERR::STL_CNT_UNKNOWN)
     1317        text = L"unknown ";
     1318    else if(err == ERR::STL_CNT_UNSUPPORTED)
    14461319        text = L"unsupported ";
    14471320    // .. container of a known type but contents are invalid.
    1448     if(err == ERR::STL_CNT_INVALID)
     1321    else if(err == ERR::STL_CNT_INVALID)
    14491322        text = L"uninitialized/invalid ";
    14501323    // .. some other error encountered
    14511324    else
    14521325    {
    1453         swprintf_s(buf, ARRAY_SIZE(buf), L"error %d while analyzing ", err);
     1326        wchar_t description[200];
     1327        (void)StatusDescription(err, description, ARRAY_SIZE(description));
     1328        swprintf_s(buf, ARRAY_SIZE(buf), L"error \"%ls\" while analyzing ", description);
    14541329        text = buf;
    14551330    }
     
    14571332    // (debug_stl modifies its input string in-place; type_name is
    14581333    // a const string returned by dbghelp)
    1459     wchar_t type_name_buf[DBG_SYMBOL_LEN];
     1334    wchar_t type_name_buf[DEBUG_SYMBOL_CHARS];
    14601335    wcscpy_s(type_name_buf, ARRAY_SIZE(type_name_buf), type_name);
    14611336
     
    15141389
    15151390
    1516 static Status udt_dump_suppressed(const wchar_t* type_name, const u8* UNUSED(p), size_t UNUSED(size), DumpState state, ULONG UNUSED(num_children), const DWORD* UNUSED(children))
     1391static Status udt_dump_suppressed(const wchar_t* type_name, const u8* UNUSED(p), size_t UNUSED(size), DumpState state, ULONG UNUSED(numChildren), const DWORD* UNUSED(children))
    15171392{
    15181393    if(!udt_should_suppress(type_name))
     
    15661441
    15671442
    1568 static Status udt_dump_normal(const wchar_t* type_name, const u8* p, size_t size, DumpState state, ULONG num_children, const DWORD* children)
    1569 {
    1570     const bool fits_on_one_line = udt_fits_on_one_line(type_name, num_children, size);
     1443static Status udt_dump_normal(const wchar_t* type_name, const u8* p, size_t size, DumpState state, ULONG numChildren, const DWORD* children)
     1444{
     1445    const bool fits_on_one_line = udt_fits_on_one_line(type_name, numChildren, size);
    15711446
    15721447    // prevent infinite recursion just to be safe (shouldn't happen)
    1573     if(state.level >= MAX_LEVEL)
     1448    if(state.level >= maxLevel)
    15741449        WARN_RETURN(ERR::SYM_NESTING_LIMIT);
    15751450    state.level++;
     
    15781453
    15791454    bool displayed_anything = false;
    1580     for(ULONG i = 0; i < num_children; i++)
     1455    for(ULONG i = 0; i < numChildren; i++)
    15811456    {
    15821457        const DWORD child_id = children[i];
     
    15851460        // (we only display data here, not e.g. typedefs)
    15861461        DWORD ofs = 0;
    1587         if(!pSymGetTypeInfo(hProcess, mod_base, child_id, TI_GET_OFFSET, &ofs))
     1462        if(!pSymGetTypeInfo(hProcess, state.moduleBase, child_id, TI_GET_OFFSET, &ofs))
    15881463            continue;
    15891464        if(ofs >= size)
     
    16261501
    16271502    // remove trailing comma separator
    1628     // note: we can't avoid writing it by checking if i == num_children-1:
     1503    // note: we can't avoid writing it by checking if i == numChildren-1:
    16291504    // each child might be the last valid data member.
    16301505    if(fits_on_one_line)
     
    16381513
    16391514
    1640 static Status dump_sym_udt(DWORD type_id, const u8* p, DumpState state)
    1641 {
    1642     ULONG64 size_ = 0;
    1643     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
    1644         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1645     const size_t size = (size_t)size_;
     1515static Status dump_sym_udt(DWORD type_id, const u8* p, DumpState& state)
     1516{
     1517    ULONG64 size64 = 0;
     1518    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_LENGTH, &size64))
     1519        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     1520    const size_t size = (size_t)size64;
    16461521
    16471522    // get array of child symbols (members/functions/base classes).
    1648     DWORD num_children;
    1649     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_CHILDRENCOUNT, &num_children))
    1650         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1651     TI_FINDCHILDREN_PARAMS2 fcp(num_children);
    1652     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_FINDCHILDREN, &fcp))
    1653         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1654     num_children = fcp.p.Count; // was truncated to MAX_CHILDREN
     1523    DWORD numChildren;
     1524    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_CHILDRENCOUNT, &numChildren))
     1525        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     1526    TI_FINDCHILDREN_PARAMS2 fcp(numChildren);
     1527    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_FINDCHILDREN, &fcp))
     1528        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     1529    numChildren = fcp.p.Count;  // was truncated to maxChildren
    16551530    const DWORD* children = fcp.p.ChildId;
    16561531
    16571532    const wchar_t* type_name;
    1658     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_SYMNAME, &type_name))
     1533    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_SYMNAME, &type_name))
    16591534        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    16601535
     
    16631538    // suppressing UDTs, which tosses out most other C++ stdlib classes)
    16641539
    1665     ret = udt_dump_std       (type_name, p, size, state, num_children, children);
     1540    ret = udt_dump_std       (type_name, p, size, state, numChildren, children);
    16661541    if(ret != INFO::CANNOT_HANDLE)
    16671542        goto done;
    16681543
    1669     ret = udt_dump_suppressed(type_name, p, size, state, num_children, children);
     1544    ret = udt_dump_suppressed(type_name, p, size, state, numChildren, children);
    16701545    if(ret != INFO::CANNOT_HANDLE)
    16711546        goto done;
    16721547
    1673     ret = udt_dump_normal    (type_name, p, size, state, num_children, children);
     1548    ret = udt_dump_normal    (type_name, p, size, state, numChildren, children);
    16741549    if(ret != INFO::CANNOT_HANDLE)
    16751550        goto done;
     
    16841559
    16851560
    1686 static Status dump_sym_vtable(DWORD UNUSED(type_id), const u8* UNUSED(p), DumpState UNUSED(state))
     1561static Status dump_sym_vtable(DWORD UNUSED(type_id), const u8* UNUSED(p), DumpState& UNUSED(state))
    16871562{
    16881563    // unsupported (vtable internals are undocumented; too much work).
     
    16941569
    16951570
    1696 static Status dump_sym_unknown(DWORD type_id, const u8* UNUSED(p), DumpState UNUSED(state))
     1571static Status dump_sym_unknown(DWORD type_id, const u8* UNUSED(p), DumpState& state)
    16971572{
    16981573    // redundant (already done in dump_sym), but this is rare.
    16991574    DWORD type_tag;
    1700     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_SYMTAG, &type_tag))
    1701         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1702 
    1703     debug_printf(L"SYM| unknown tag: %d\n", type_tag);
     1575    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_SYMTAG, &type_tag))
     1576        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     1577
     1578    debug_printf(L"SYM: unknown tag: %d\n", type_tag);
    17041579    out(L"(unknown symbol type)");
    17051580    return INFO::OK;
     
    17091584//-----------------------------------------------------------------------------
    17101585
     1586typedef Status (*DumpFunc)(DWORD typeId, const u8* p, DumpState& state);
     1587
     1588static DumpFunc DumpFuncFromTypeTag(DWORD typeTag)
     1589{
     1590    switch(typeTag)
     1591    {
     1592    case SymTagArrayType:
     1593        return dump_sym_array;
     1594    case SymTagBaseType:
     1595        return dump_sym_base_type;
     1596    case SymTagBaseClass:
     1597        return dump_sym_base_class;
     1598    case SymTagData:
     1599        return dump_sym_data;
     1600    case SymTagEnum:
     1601        return dump_sym_enum;
     1602    case SymTagFunction:
     1603        return dump_sym_function;
     1604    case SymTagFunctionType:
     1605        return dump_sym_function_type;
     1606    case SymTagPointerType:
     1607        return dump_sym_pointer;
     1608    case SymTagTypedef:
     1609        return dump_sym_typedef;
     1610    case SymTagUDT:
     1611        return dump_sym_udt;
     1612    case SymTagVTable:
     1613        return dump_sym_vtable;
     1614    default:
     1615        return dump_sym_unknown;
     1616    }
     1617}
     1618
    17111619
    17121620// write name and value of the symbol <type_id> to the output buffer.
    17131621// delegates to dump_sym_* depending on the symbol's tag.
    1714 static Status dump_sym(DWORD type_id, const u8* p, DumpState state)
     1622static Status dump_sym(DWORD type_id, const u8* p, DumpState& state)
    17151623{
    17161624    RETURN_STATUS_IF_ERR(out_check_limit());
    17171625
    1718     DWORD type_tag;
    1719     if(!pSymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_SYMTAG, &type_tag))
    1720         WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
    1721     switch(type_tag)
    1722     {
    1723     case SymTagArrayType:
    1724         return dump_sym_array         (type_id, p, state);
    1725     case SymTagBaseType:
    1726         return dump_sym_base_type     (type_id, p, state);
    1727     case SymTagBaseClass:
    1728         return dump_sym_base_class    (type_id, p, state);
    1729     case SymTagData:
    1730         return dump_sym_data          (type_id, p, state);
    1731     case SymTagEnum:
    1732         return dump_sym_enum          (type_id, p, state);
    1733     case SymTagFunction:
    1734         return dump_sym_function      (type_id, p, state);
    1735     case SymTagFunctionType:
    1736         return dump_sym_function_type (type_id, p, state);
    1737     case SymTagPointerType:
    1738         return dump_sym_pointer       (type_id, p, state);
    1739     case SymTagTypedef:
    1740         return dump_sym_typedef       (type_id, p, state);
    1741     case SymTagUDT:
    1742         return dump_sym_udt           (type_id, p, state);
    1743     case SymTagVTable:
    1744         return dump_sym_vtable        (type_id, p, state);
    1745     default:
    1746         return dump_sym_unknown       (type_id, p, state);
    1747     }
     1626    DWORD typeTag;
     1627    if(!pSymGetTypeInfo(hProcess, state.moduleBase, type_id, TI_GET_SYMTAG, &typeTag))
     1628        WARN_RETURN(ERR::SYM_TYPE_INFO_UNAVAILABLE);
     1629    const DumpFunc dumpFunc = DumpFuncFromTypeTag(typeTag);
     1630    return dumpFunc(type_id, p, state);
    17481631}
    17491632
     
    17521635// stack trace
    17531636//-----------------------------------------------------------------------------
    1754 
    1755 struct IMAGEHLP_STACK_FRAME2 : public IMAGEHLP_STACK_FRAME
    1756 {
    1757     IMAGEHLP_STACK_FRAME2(const _tagSTACKFRAME64* sf)
    1758     {
    1759         // apparently only PC, FP and SP are necessary, but
    1760         // we go whole-hog to be safe.
    1761         memset(this, 0, sizeof(IMAGEHLP_STACK_FRAME2));
    1762         InstructionOffset  = sf->AddrPC.Offset;
    1763         ReturnOffset       = sf->AddrReturn.Offset;
    1764         FrameOffset        = sf->AddrFrame.Offset;
    1765         StackOffset        = sf->AddrStack.Offset;
    1766         BackingStoreOffset = sf->AddrBStore.Offset;
    1767         FuncTableEntry     = (ULONG64)sf->FuncTableEntry;
    1768         Virtual            = sf->Virtual;
    1769         // (note: array of different types, can't copy directly)
    1770         for(int i = 0; i < 4; i++)
    1771             Params[i] = sf->Params[i];
    1772     }
    1773 };
    17741637
    17751638static bool ShouldSkipSymbol(const wchar_t* name)
     
    17841647// output the symbol's name and value via dump_sym*.
    17851648// called from dump_frame_cb for each local symbol; lock is held.
    1786 static BOOL CALLBACK dump_sym_cb(SYMBOL_INFOW* sym, ULONG UNUSED(size), void* UNUSED(ctx))
     1649static BOOL CALLBACK dump_sym_cb(SYMBOL_INFOW* sym, ULONG UNUSED(size), PVOID userContext)
    17871650{
    17881651    if(ShouldSkipSymbol(sym->Name))
     
    17901653
    17911654    out_latch_pos();    // see decl
    1792     mod_base = (uintptr_t)sym->ModBase;
    17931655    const u8* p = (const u8*)(uintptr_t)sym->Address;
    1794     DumpState state;
     1656    DumpState state((uintptr_t)sym->ModBase, (LPSTACKFRAME64)userContext);
    17951657
    17961658    INDENT;
     
    18061668
    18071669// called by wdbg_sym_WalkStack for each stack frame
    1808 static Status dump_frame_cb(const _tagSTACKFRAME64* sf, uintptr_t UNUSED(cbData))
    1809 {
    1810     current_stackframe64 = sf;
     1670static Status dump_frame_cb(const STACKFRAME64* sf, uintptr_t UNUSED(userContext))
     1671{
    18111672    void* func = (void*)(uintptr_t)sf->AddrPC.Offset;
    18121673
    1813     wchar_t func_name[DBG_SYMBOL_LEN]; wchar_t file[DBG_FILE_LEN]; int line;
     1674    wchar_t func_name[DEBUG_SYMBOL_CHARS]; wchar_t file[DEBUG_FILE_CHARS]; int line;
    18141675    Status ret = ResolveSymbol_lk(func, func_name, file, &line);
    18151676    if(ret == INFO::OK)
     
    18221683        // note: the stdcall mangled name includes parameter size, which is
    18231684        // different in 64-bit, so only check the first characters.
    1824         if(!wcsncmp(func_name, L"_BaseProcessStart", 17))
     1685        if(!wcsncmp(func_name, L"_BaseProcessStart", 17) ||
     1686           !wcscmp(func_name, L"BaseThreadInitThunk"))
     1687            return INFO::OK;
     1688
     1689        // skip any mainCRTStartup frames
     1690        if(!wcscmp(func_name, L"__tmainCRTStartup"))
     1691            return INFO::OK;
     1692        if(!wcscmp(func_name, L"mainCRTStartup"))
    18251693            return INFO::OK;
    18261694
     
    18361704    // problem: debug info is scope-aware, so we won't see any variables
    18371705    // declared in sub-blocks. we'd have to pass an address in that block,
    1838     // which isn't worth the trouble. since
    1839     IMAGEHLP_STACK_FRAME2 imghlp_frame(sf);
    1840     const PIMAGEHLP_CONTEXT context = 0;    // ignored
    1841     pSymSetContext(hProcess, &imghlp_frame, context);
     1706    // which isn't worth the trouble.
     1707    IMAGEHLP_STACK_FRAME isf = PopulateImageStackFrame(*sf);
     1708    const PIMAGEHLP_CONTEXT ic = 0; // ignored
     1709    // NB: this sometimes fails for reasons unknown in a static
     1710    // member function, possibly because the return address is in kernel32
     1711    (void)pSymSetContext(hProcess, &isf, ic);
    18421712
    18431713    const ULONG64 base = 0; const wchar_t* const mask = 0;  // use scope set by pSymSetContext
    1844     pSymEnumSymbolsW(hProcess, base, mask, dump_sym_cb, 0);
     1714    pSymEnumSymbolsW(hProcess, base, mask, dump_sym_cb, (PVOID)sf);
    18451715
    18461716    if(GetLastError() == ERROR_NOT_SUPPORTED)   // no debug info present?
     
    18481718
    18491719    out(L"\r\n");
    1850     return INFO::CONTINUE;
     1720    return INFO::OK;
    18511721}
    18521722
     
    18611731    ptr_reset_visited();
    18621732
    1863     Status ret = wdbg_sym_WalkStack(dump_frame_cb, 0, (const CONTEXT*)pcontext, lastFuncToSkip);
    1864 
     1733    wdbg_assert(pcontext != 0);
     1734    Status ret = wdbg_sym_WalkStack(dump_frame_cb, 0, *(CONTEXT*)pcontext, lastFuncToSkip);
     1735
     1736    COMPILER_FENCE;
    18651737    busy = 0;
    1866     COMPILER_FENCE;
    18671738
    18681739    return ret;
  • ps/trunk/source/lib/sysdep/os/win/wdbg_sym.h

    r9462 r9871  
    2828#define INCLUDED_WDBG_SYM
    2929
     30#include "lib/sysdep/os/win/win.h"  // CONTEXT, EXCEPTION_POINTERS
     31
    3032struct _tagSTACKFRAME64;
    31 struct _CONTEXT;
    32 struct _EXCEPTION_POINTERS;
    3333
    3434/**
     
    3636 *
    3737 * @param frame the dbghelp stack frame (we can't just pass the
    38  * instruction-pointer because dump_frame_cb needs the frame pointer to
    39  * locate frame-relative variables)
     38 *   instruction-pointer because dump_frame_cb needs the frame pointer to
     39 *   locate frame-relative variables)
    4040 * @param cbData the user-specified value that was passed to wdbg_sym_WalkStack
    41  * @return INFO::CONTINUE to continue, anything else to stop immediately
    42  * and return that value to wdbg_sym_WalkStack's caller.
     41 * @return Status (see RETURN_STATUS_FROM_CALLBACK).
    4342 **/
    4443typedef Status (*StackFrameCallback)(const _tagSTACKFRAME64* frame, uintptr_t cbData);
     
    4948 * @param cb
    5049 * @param cbData
    51  * @param pcontext Processor context from which to start (usually taken from
    52  *        an exception record), or 0 to walk the current stack.
     50 * @param context Processor context from which to start (taken from
     51 *   an exception record or debug_CaptureContext).
    5352 * @param lastFuncToSkip
    5453 *
    5554 * @note It is safe to use ENSURE/debug_warn/WARN_RETURN_STATUS_IF_ERR even during a
    56  * stack trace (which is triggered by ENSURE et al. in app code) because
    57  * nested stack traces are ignored and only the error is displayed.
     55 *   stack trace (which is triggered by ENSURE et al. in app code) because
     56 *   nested stack traces are ignored and only the error is displayed.
    5857 **/
    59 extern Status wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData = 0, const _CONTEXT* pcontext = 0, const wchar_t* lastFuncToSkip = 0);
     58LIB_API Status wdbg_sym_WalkStack(StackFrameCallback cb, uintptr_t cbData, CONTEXT& context, const wchar_t* lastFuncToSkip = 0);
    6059
    61 extern void wdbg_sym_WriteMinidump(_EXCEPTION_POINTERS* ep);
     60LIB_API void wdbg_sym_WriteMinidump(EXCEPTION_POINTERS* ep);
    6261
    6362#endif  // #ifndef INCLUDED_WDBG_SYM
  • ps/trunk/source/lib/sysdep/os/win/wposix/wmman.cpp

    r9462 r9871  
    8383    // .. if MAP_SHARED, writes are to change "the underlying [mapped]
    8484    //    object", but there is none here (we're backed by the page file).
    85     ENSURE(flags & MAP_PRIVATE);
     85    ENSURE(!(flags & MAP_SHARED));
    8686
    8787    // see explanation at MAP_NORESERVE definition.
     
    121121// read/write and copy-on-write, so we dumb it down to that and later
    122122// set the correct (and more restrictive) permission via mprotect.
    123 static Status mmap_file_access(int prot, int flags, DWORD& protect, DWORD& dwAccess)
    124 {
    125     // assume read-only; other cases handled below.
    126     protect = PAGE_READONLY;
    127     dwAccess  = FILE_MAP_READ;
     123static Status DecodeFlags(int prot, int flags, DWORD& protect, DWORD& access)
     124{
     125    // ensure exactly one of (MAP_SHARED, MAP_PRIVATE) is specified
     126    switch(flags & (MAP_SHARED|MAP_PRIVATE))
     127    {
     128    case 0:
     129    case MAP_SHARED|MAP_PRIVATE:
     130        WARN_RETURN(ERR::INVALID_PARAM);
     131    default:;
     132    }
    128133
    129134    if(prot & PROT_WRITE)
    130135    {
    131136        // determine write behavior: (whether they change the underlying file)
    132         switch(flags & (MAP_SHARED|MAP_PRIVATE))
     137        if(flags & MAP_SHARED)  // writes affect the file
    133138        {
    134             // .. changes are written to file.
    135         case MAP_SHARED:
    136139            protect = PAGE_READWRITE;
    137             dwAccess  = FILE_MAP_WRITE; // read and write
    138             break;
    139             // .. copy-on-write mapping; writes do not affect the file.
    140         case MAP_PRIVATE:
     140            access  = FILE_MAP_WRITE;   // read and write
     141        }
     142        else    // copy on write (file remains unchanged)
     143        {
    141144            protect = PAGE_WRITECOPY;
    142             dwAccess  = FILE_MAP_COPY;
    143             break;
    144             // .. either none or both of the flags are set. the latter is
    145             //    definitely illegal according to POSIX and some man pages
    146             //    say exactly one must be set, so abort.
    147         default:
    148             WARN_RETURN(ERR::INVALID_PARAM);
     145            access  = FILE_MAP_COPY;
    149146        }
     147    }
     148    else
     149    {
     150        protect = PAGE_READONLY;
     151        access  = FILE_MAP_READ;
    150152    }
    151153
     
    172174    // MapViewOfFile. these are weaker than what PROT_* allows and
    173175    // are augmented below by subsequently mprotect-ing.
    174     DWORD protect; DWORD dwAccess;
    175     RETURN_STATUS_IF_ERR(mmap_file_access(prot, flags, protect, dwAccess));
    176 
    177     // enough foreplay; now actually map.
     176    DWORD protect; DWORD access;
     177    RETURN_STATUS_IF_ERR(DecodeFlags(prot, flags, protect, access));
     178
    178179    const HANDLE hMap = CreateFileMapping(hFile, 0, protect, 0, 0, 0);
    179     // .. create failed; bail now to avoid overwriting the last error value.
    180180    if(!hMap)
    181181        WARN_RETURN(ERR::NO_MEM);
    182     const DWORD ofs_hi = u64_hi(ofs), ofs_lo = u64_lo(ofs);
    183     void* p = MapViewOfFileEx(hMap, dwAccess, ofs_hi, ofs_lo, (SIZE_T)len, start);
    184     // .. make sure we got the requested address if MAP_FIXED was passed.
     182    void* p = MapViewOfFileEx(hMap, access, u64_hi(ofs), u64_lo(ofs), (SIZE_T)len, start);
     183    // ensure we got the requested address if MAP_FIXED was passed.
    185184    ENSURE(!(flags & MAP_FIXED) || (p == start));
    186     // .. free the mapping object now, so that we don't have to hold on to its
    187     //    handle until munmap(). it's not actually released yet due to the
    188     //    reference held by MapViewOfFileEx (if it succeeded).
     185    // free the mapping object now, so that we don't have to hold on to its
     186    // handle until munmap(). it's not actually released yet due to the
     187    // reference held by MapViewOfFileEx (if it succeeded).
    189188    CloseHandle(hMap);
    190     // .. map failed; bail now to avoid "restoring" the last error value.
     189    // map failed; bail now to avoid "restoring" the last error value.
    191190    if(!p)
    192191        WARN_RETURN(ERR::NO_MEM);
    193192
    194     // slap on correct (more restrictive) permissions.
     193    // enforce the desired (more restrictive) protection.
    195194    (void)mprotect(p, len, prot);
    196195
     
    202201void* mmap(void* start, size_t len, int prot, int flags, int fd, off_t ofs)
    203202{
    204     if(len == 0)    // POSIX says this must cause mmap to fail
    205     {
    206         DEBUG_WARN_ERR(ERR::LOGIC);
    207         errno = EINVAL;
    208         return MAP_FAILED;
    209     }
     203    ASSERT(len != 0);
    210204
    211205    void* p;
  • ps/trunk/source/lib/sysdep/os/win/wposix/wmman.h

    r7316 r9871  
    3939#define MAP_FIXED   0x04
    4040// .. non-portable
    41 #define MAP_ANONYMOUS 0x10 
    42 #define MAP_NORESERVE 0x20
     41#define MAP_ANONYMOUS 0x10  // backed by the pagefile; fd should be -1
     42#define MAP_NORESERVE 0x20  // see below
    4343
    4444// note: we need a means of only "reserving" virtual address ranges
     
    5050// make sure of that in the future.
    5151
    52 #define MAP_FAILED ((void*)(intptr_t)-1L)
     52#define MAP_FAILED ((void*)intptr_t(-1))
    5353
    5454extern void* mmap(void* start, size_t len, int prot, int flags, int fd, off_t offset);
  • ps/trunk/source/lib/sysdep/os/win/wseh.cpp

    r9475 r9871  
    216216// return location at which the exception <er> occurred.
    217217// params: see debug_ResolveSymbol.
    218 static void GetExceptionLocus(const EXCEPTION_POINTERS* ep,
     218static void GetExceptionLocus(EXCEPTION_POINTERS* ep,
    219219    wchar_t* file, int* line, wchar_t* func)
    220220{
     
    271271    wchar_t descriptionBuf[150];
    272272    const wchar_t* description = GetExceptionDescription(ep, descriptionBuf, ARRAY_SIZE(descriptionBuf));
    273     wchar_t file[DBG_FILE_LEN] = {0};
     273    wchar_t file[DEBUG_FILE_CHARS] = {0};
    274274    int line = 0;
    275     wchar_t func[DBG_SYMBOL_LEN] = {0};
     275    wchar_t func[DEBUG_SYMBOL_CHARS] = {0};
    276276    GetExceptionLocus(ep, file, &line, func);
    277277
  • ps/trunk/source/ps/GameSetup/GameSetup.cpp

    r9819 r9871  
    761761    debug_filter_add(L"TIMER");
    762762
    763     cpu_ConfigureFloatingPoint();
    764 
    765763    timer_LatchStartTime();
    766764
  • ps/trunk/source/ps/scripting/JSInterface_VFS.cpp

    r9550 r9871  
    7373    jsval val = ToJSVal( CStrW(pathname.string()) );
    7474    JS_SetElement(s->cx, s->filename_array, s->cur_idx++, &val);
    75     return INFO::CONTINUE;
     75    return INFO::OK;
    7676}
    7777
Note: See TracChangeset for help on using the changeset viewer.