|  | // -*- mode: C++ -*- | 
|  |  | 
|  | // Copyright (c) 2010, Google Inc. | 
|  | // All rights reserved. | 
|  | // | 
|  | // Redistribution and use in source and binary forms, with or without | 
|  | // modification, are permitted provided that the following conditions are | 
|  | // met: | 
|  | // | 
|  | //     * Redistributions of source code must retain the above copyright | 
|  | // notice, this list of conditions and the following disclaimer. | 
|  | //     * Redistributions in binary form must reproduce the above | 
|  | // copyright notice, this list of conditions and the following disclaimer | 
|  | // in the documentation and/or other materials provided with the | 
|  | // distribution. | 
|  | //     * Neither the name of Google Inc. nor the names of its | 
|  | // contributors may be used to endorse or promote products derived from | 
|  | // this software without specific prior written permission. | 
|  | // | 
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  |  | 
|  | // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> | 
|  |  | 
|  | // cfi_frame_info-inl.h: Definitions for cfi_frame_info.h inlined functions. | 
|  |  | 
|  | #ifndef PROCESSOR_CFI_FRAME_INFO_INL_H_ | 
|  | #define PROCESSOR_CFI_FRAME_INFO_INL_H_ | 
|  |  | 
|  | #include <string.h> | 
|  |  | 
|  | namespace google_breakpad { | 
|  |  | 
|  | template <typename RegisterType, class RawContextType> | 
|  | bool SimpleCFIWalker<RegisterType, RawContextType>::FindCallerRegisters( | 
|  | const MemoryRegion &memory, | 
|  | const CFIFrameInfo &cfi_frame_info, | 
|  | const RawContextType &callee_context, | 
|  | int callee_validity, | 
|  | RawContextType *caller_context, | 
|  | int *caller_validity) const { | 
|  | typedef CFIFrameInfo::RegisterValueMap<RegisterType> ValueMap; | 
|  | ValueMap callee_registers; | 
|  | ValueMap caller_registers; | 
|  | // Just for brevity. | 
|  | typename ValueMap::const_iterator caller_none = caller_registers.end(); | 
|  |  | 
|  | // Populate callee_registers with register values from callee_context. | 
|  | for (size_t i = 0; i < map_size_; i++) { | 
|  | const RegisterSet &r = register_map_[i]; | 
|  | if (callee_validity & r.validity_flag) | 
|  | callee_registers[r.name] = callee_context.*r.context_member; | 
|  | } | 
|  |  | 
|  | // Apply the rules, and see what register values they yield. | 
|  | if (!cfi_frame_info.FindCallerRegs<RegisterType>(callee_registers, memory, | 
|  | &caller_registers)) | 
|  | return false; | 
|  |  | 
|  | // Populate *caller_context with the values the rules placed in | 
|  | // caller_registers. | 
|  | memset(caller_context, 0xda, sizeof(*caller_context)); | 
|  | *caller_validity = 0; | 
|  | for (size_t i = 0; i < map_size_; i++) { | 
|  | const RegisterSet &r = register_map_[i]; | 
|  | typename ValueMap::const_iterator caller_entry; | 
|  |  | 
|  | // Did the rules provide a value for this register by its name? | 
|  | caller_entry = caller_registers.find(r.name); | 
|  | if (caller_entry != caller_none) { | 
|  | caller_context->*r.context_member = caller_entry->second; | 
|  | *caller_validity |= r.validity_flag; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Did the rules provide a value for this register under its | 
|  | // alternate name? | 
|  | if (r.alternate_name) { | 
|  | caller_entry = caller_registers.find(r.alternate_name); | 
|  | if (caller_entry != caller_none) { | 
|  | caller_context->*r.context_member = caller_entry->second; | 
|  | *caller_validity |= r.validity_flag; | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Is this a callee-saves register? The walker assumes that these | 
|  | // still hold the caller's value if the CFI doesn't mention them. | 
|  | // | 
|  | // Note that other frame walkers may fail to recover callee-saves | 
|  | // registers; for example, the x86 "traditional" strategy only | 
|  | // recovers %eip, %esp, and %ebp, even though %ebx, %esi, and %edi | 
|  | // are callee-saves, too. It is not correct to blindly set the | 
|  | // valid bit for all callee-saves registers, without first | 
|  | // checking its validity bit in the callee. | 
|  | if (r.callee_saves && (callee_validity & r.validity_flag) != 0) { | 
|  | caller_context->*r.context_member = callee_context.*r.context_member; | 
|  | *caller_validity |= r.validity_flag; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Otherwise, the register's value is unknown. | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | } // namespace google_breakpad | 
|  |  | 
|  | #endif // PROCESSOR_CFI_FRAME_INFO_INL_H_ |