1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/profiler/LulExidxExt.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,233 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 + 1.7 +/* libunwind - a platform-independent unwind library 1.8 + Copyright 2011 Linaro Limited 1.9 + 1.10 +This file is part of libunwind. 1.11 + 1.12 +Permission is hereby granted, free of charge, to any person obtaining 1.13 +a copy of this software and associated documentation files (the 1.14 +"Software"), to deal in the Software without restriction, including 1.15 +without limitation the rights to use, copy, modify, merge, publish, 1.16 +distribute, sublicense, and/or sell copies of the Software, and to 1.17 +permit persons to whom the Software is furnished to do so, subject to 1.18 +the following conditions: 1.19 + 1.20 +The above copyright notice and this permission notice shall be 1.21 +included in all copies or substantial portions of the Software. 1.22 + 1.23 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1.24 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1.25 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1.26 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 1.27 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 1.28 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1.29 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 1.30 + 1.31 + 1.32 +// Copyright (c) 2010, 2011 Google Inc. 1.33 +// All rights reserved. 1.34 +// 1.35 +// Redistribution and use in source and binary forms, with or without 1.36 +// modification, are permitted provided that the following conditions are 1.37 +// met: 1.38 +// 1.39 +// * Redistributions of source code must retain the above copyright 1.40 +// notice, this list of conditions and the following disclaimer. 1.41 +// * Redistributions in binary form must reproduce the above 1.42 +// copyright notice, this list of conditions and the following disclaimer 1.43 +// in the documentation and/or other materials provided with the 1.44 +// distribution. 1.45 +// * Neither the name of Google Inc. nor the names of its 1.46 +// contributors may be used to endorse or promote products derived from 1.47 +// this software without specific prior written permission. 1.48 +// 1.49 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.50 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.51 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.52 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.53 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.54 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.55 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.56 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.57 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.58 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.59 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.60 + 1.61 + 1.62 +// Derived from libunwind, with extensive modifications. 1.63 +// This file is derived from the following files in 1.64 +// toolkit/crashreporter/google-breakpad: 1.65 +// src/common/arm_ex_to_module.h 1.66 +// src/common/memory_range.h 1.67 +// src/common/arm_ex_reader.h 1.68 + 1.69 +#ifndef LulExidxExt_h 1.70 +#define LulExidxExt_h 1.71 + 1.72 +#include "LulMainInt.h" 1.73 + 1.74 +using lul::LExpr; 1.75 +using lul::RuleSet; 1.76 +using lul::SecMap; 1.77 + 1.78 +namespace lul { 1.79 + 1.80 +typedef enum extab_cmd { 1.81 + ARM_EXIDX_CMD_FINISH, 1.82 + ARM_EXIDX_CMD_SUB_FROM_VSP, 1.83 + ARM_EXIDX_CMD_ADD_TO_VSP, 1.84 + ARM_EXIDX_CMD_REG_POP, 1.85 + ARM_EXIDX_CMD_REG_TO_SP, 1.86 + ARM_EXIDX_CMD_VFP_POP, 1.87 + ARM_EXIDX_CMD_WREG_POP, 1.88 + ARM_EXIDX_CMD_WCGR_POP, 1.89 + ARM_EXIDX_CMD_RESERVED, 1.90 + ARM_EXIDX_CMD_REFUSED, 1.91 +} extab_cmd_t; 1.92 + 1.93 +struct exidx_entry { 1.94 + uint32_t addr; 1.95 + uint32_t data; 1.96 +}; 1.97 + 1.98 +struct extab_data { 1.99 + extab_cmd_t cmd; 1.100 + uint32_t data; 1.101 +}; 1.102 + 1.103 +enum extab_cmd_flags { 1.104 + ARM_EXIDX_VFP_SHIFT_16 = 1 << 16, 1.105 + ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX 1.106 +}; 1.107 + 1.108 +// Receives information from arm_ex_reader::ExceptionTableInfo 1.109 +// and adds it to the SecMap object 1.110 +// This is in effect the EXIDX summariser. 1.111 +class ARMExToModule { 1.112 + public: 1.113 + ARMExToModule(SecMap* smap, void(*log)(const char*)) : smap_(smap) 1.114 + , log_(log) { } 1.115 + ~ARMExToModule() { } 1.116 + void AddStackFrame(uintptr_t addr, size_t size); 1.117 + int ImproveStackFrame(const struct extab_data* edata); 1.118 + void DeleteStackFrame(); 1.119 + void SubmitStackFrame(); 1.120 + private: 1.121 + SecMap* smap_; 1.122 + LExpr vsp_; // Always appears to be of the form "sp + offset" 1.123 + RuleSet curr_rules_; // Also holds the address range being summarised 1.124 + // debugging message sink 1.125 + void (*log_)(const char*); 1.126 + int TranslateCmd(const struct extab_data* edata, LExpr& vsp); 1.127 +}; 1.128 + 1.129 + 1.130 +// (derived from) 1.131 +// memory_range.h: Define the google_breakpad::MemoryRange class, which 1.132 +// is a lightweight wrapper with a pointer and a length to encapsulate 1.133 +// a contiguous range of memory. 1.134 + 1.135 +// A lightweight wrapper with a pointer and a length to encapsulate a 1.136 +// contiguous range of memory. It provides helper methods for checked 1.137 +// access of a subrange of the memory. Its implemementation does not 1.138 +// allocate memory or call into libc functions, and is thus safer to use 1.139 +// in a crashed environment. 1.140 +class MemoryRange { 1.141 + public: 1.142 + 1.143 + MemoryRange(const void* data, size_t length) { 1.144 + Set(data, length); 1.145 + } 1.146 + 1.147 + // Sets this memory range to point to |data| and its length to |length|. 1.148 + void Set(const void* data, size_t length) { 1.149 + data_ = reinterpret_cast<const uint8_t*>(data); 1.150 + // Always set |length_| to zero if |data_| is NULL. 1.151 + length_ = data ? length : 0; 1.152 + } 1.153 + 1.154 + // Returns true if this range covers a subrange of |sub_length| bytes 1.155 + // at |sub_offset| bytes of this memory range, or false otherwise. 1.156 + bool Covers(size_t sub_offset, size_t sub_length) const { 1.157 + // The following checks verify that: 1.158 + // 1. sub_offset is within [ 0 .. length_ - 1 ] 1.159 + // 2. sub_offset + sub_length is within 1.160 + // [ sub_offset .. length_ ] 1.161 + return sub_offset < length_ && 1.162 + sub_offset + sub_length >= sub_offset && 1.163 + sub_offset + sub_length <= length_; 1.164 + } 1.165 + 1.166 + // Returns a pointer to the beginning of this memory range. 1.167 + const uint8_t* data() const { return data_; } 1.168 + 1.169 + // Returns the length, in bytes, of this memory range. 1.170 + size_t length() const { return length_; } 1.171 + 1.172 + private: 1.173 + // Pointer to the beginning of this memory range. 1.174 + const uint8_t* data_; 1.175 + 1.176 + // Length, in bytes, of this memory range. 1.177 + size_t length_; 1.178 +}; 1.179 + 1.180 + 1.181 +// This class is a reader for ARM unwind information 1.182 +// from .ARM.exidx and .ARM.extab sections. 1.183 +class ExceptionTableInfo { 1.184 + public: 1.185 + ExceptionTableInfo(const char* exidx, size_t exidx_size, 1.186 + const char* extab, size_t extab_size, 1.187 + uint32_t text_last_svma, 1.188 + lul::ARMExToModule* handler, 1.189 + const char* mapping_addr, 1.190 + uint32_t loading_addr, 1.191 + uintptr_t text_bias, 1.192 + void (*log)(const char*)) 1.193 + : mr_exidx_(lul::MemoryRange(exidx, exidx_size)), 1.194 + mr_extab_(lul::MemoryRange(extab, extab_size)), 1.195 + text_last_svma_(text_last_svma), 1.196 + handler_(handler), mapping_addr_(mapping_addr), 1.197 + loading_addr_(loading_addr), 1.198 + text_bias_(text_bias), 1.199 + log_(log) { } 1.200 + 1.201 + ~ExceptionTableInfo() { } 1.202 + 1.203 + // Parses the entries in .ARM.exidx and possibly 1.204 + // in .ARM.extab tables, reports what we find to 1.205 + // arm_ex_to_module::ARMExToModule. 1.206 + void Start(); 1.207 + 1.208 + private: 1.209 + lul::MemoryRange mr_exidx_; 1.210 + lul::MemoryRange mr_extab_; 1.211 + uint32_t text_last_svma_; 1.212 + lul::ARMExToModule* handler_; 1.213 + const char* mapping_addr_; 1.214 + uint32_t loading_addr_; 1.215 + uintptr_t text_bias_; 1.216 + // debugging message sink 1.217 + void (*log_)(const char*); 1.218 + enum ExExtractResult { 1.219 + ExSuccess, // success 1.220 + ExInBufOverflow, // out-of-range while reading .exidx 1.221 + ExOutBufOverflow, // output buffer is too small 1.222 + ExCantUnwind, // this function is marked CANT_UNWIND 1.223 + ExCantRepresent, // entry valid, but we can't represent it 1.224 + ExInvalid // entry is invalid 1.225 + }; 1.226 + ExExtractResult 1.227 + ExtabEntryExtract(const struct lul::exidx_entry* entry, 1.228 + uint8_t* buf, size_t buf_size, 1.229 + /*OUT*/size_t* buf_used); 1.230 + 1.231 + int ExtabEntryDecode(const uint8_t* buf, size_t buf_size); 1.232 +}; 1.233 + 1.234 +} // namespace lul 1.235 + 1.236 +#endif // LulExidxExt_h