Source/dwarf_stack.hpp (96 lines of code) (raw):

/* * Copyright (c) 2013 Plausible Labs Cooperative, Inc. * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef PLCRASH_ASYNC_DWARF_STACK_H #define PLCRASH_ASYNC_DWARF_STACK_H 1 #include <cstddef> #include "PLCrashFeatureConfig.h" #include "PLCrashMacros.h" #if PLCRASH_FEATURE_UNWIND_DWARF /** * @internal * @ingroup plcrash_async_dwarf_private_stack * @{ */ PLCR_CPP_BEGIN_NS namespace async { /** * @internal * * A simple machine pointer stack for use with DWARF opcode/CFA evaluation. */ template <typename T, size_t S> class dwarf_stack { T mem[S]; T *sp = mem; public: inline bool push (T value); inline bool peek (T *value); inline bool pop (T *value); inline bool pick (size_t index); inline bool drop (void); inline bool dup (void); inline bool swap (void); inline bool rotate (void); }; /** * Push a single value onto the stack. * * @param value The value to push. * @return Returns true on success, or false if the stack is full. */ template <typename T, size_t S> inline bool dwarf_stack<T,S>::push (T value) { /* Refuse to exceed the allocated stack size */ if (sp == &mem[S]) return false; *sp = value; sp++; return true; } /** * Pop a single value from the stack. * * @param value An address to which the popped value will be written. * @return Returns true on success, or false if the stack is empty. */ template <typename T, size_t S> inline bool dwarf_stack<T,S>::pop (T *value) { /* Refuse to pop the final value */ if (sp == mem) return false; sp--; *value = *sp; return true; } /** * Peek at the top of the stack. * * @param value An address to which the peeked value will be written. * @return Returns true on success, or false if the stack is empty. */ template <typename T, size_t S> inline bool dwarf_stack<T,S>::peek (T *value) { /* Refuse to peek an empty stack */ if (sp == mem) return false; *value = *(sp-1); return true; } /** * Pop and discard an element from the stack. * * @return Returns true on success, or false if the stack is empty. */ template <typename T, size_t S> inline bool dwarf_stack<T,S>::drop (void) { /* Refuse to pop the final value */ if (sp == mem) return false; sp--; return true; } /** * Duplicate the value at the top of the stack. * * @return Returns true on success, or false if the stack is full. */ template <class T, size_t S> inline bool dwarf_stack<T,S>::dup (void) { /* Refuse to exceed the allocated stack size */ if (sp == &mem[S]) return false; /* Peek and push the current value */ T val; if (!peek(&val)) return false; return push(val); } /** * Pick the stack entry with the specified index, and push its value on * the top of the stack. * * @param index The index of the entry to be picked * @return Returns true on success, or false if the index is outside the stack bounds. */ template <typename T, size_t S> inline bool dwarf_stack<T,S>::pick (size_t index) { /* Validate the index range */ if (sp - mem <= index) return false; push(*(sp-1-index)); return true; } /** * Swap the top two stack entries. * * @return Returns true on success, or false if less than two values are available on * the stack. */ template <typename T, size_t S> inline bool dwarf_stack<T,S>::swap (void) { T v1; T v2; /* Fetch the current values */ if (!pop(&v1)) return false; if (!pop(&v2)) return false; /* Pushing two just-popped values should never fail */ if (!push(v1)) return false; if (!push(v2)) return false; return true; } /** * Rotate the top three stack entries. The entry at the top of the stack * is becomes the third stack entry, the second entry becomes the top of the stack, * and the third entry becomes the second entry. * * @return Returns true on success, or false if less than three values are available on * the stack. */ template <typename T, size_t S> inline bool dwarf_stack<T,S>::rotate (void) { T v1; T v2; T v3; /* Fetch the current values */ if (!pop(&v1)) return false; if (!pop(&v2)) return false; if (!pop(&v3)) return false; /* Pushing three just-popped values should never fail */ if (!push(v1)) return false; if (!push(v3)) return false; if (!push(v2)) return false; return true; } PLCR_CPP_END_NS } /* * @} */ #endif /* PLCRASH_FEATURE_UNWIND_DWARF */ #endif /* PLCRASH_ASYNC_DWARF_STACK_H */