Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | # HG changeset patch |
michael@0 | 2 | # User Julian Seward <jseward@acm.org> |
michael@0 | 3 | # Date 1372168568 -7200 |
michael@0 | 4 | # Tue Jun 25 15:56:08 2013 +0200 |
michael@0 | 5 | # Node ID 6d06a09b3f5624dd833bd6f905bfd88e3fdec00a |
michael@0 | 6 | # Parent 11f7a9321b7d5d85eddc2db16e58e6870a7c4e06 |
michael@0 | 7 | Bug 883126 - Improve performance of EXIDX unwinding in Breakpad. r=ted |
michael@0 | 8 | |
michael@0 | 9 | diff --git a/src/common/arm_ex_to_module.cc b/src/common/arm_ex_to_module.cc |
michael@0 | 10 | --- a/src/common/arm_ex_to_module.cc |
michael@0 | 11 | +++ b/src/common/arm_ex_to_module.cc |
michael@0 | 12 | @@ -66,141 +66,126 @@ WITH THE SOFTWARE OR THE USE OR OTHER DE |
michael@0 | 13 | |
michael@0 | 14 | #define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f) |
michael@0 | 15 | #define ARM_EXBUF_COUNT(x) ((x) & 0x0f) |
michael@0 | 16 | #define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x)) |
michael@0 | 17 | |
michael@0 | 18 | using google_breakpad::ustr__pc; |
michael@0 | 19 | using google_breakpad::ustr__lr; |
michael@0 | 20 | using google_breakpad::ustr__sp; |
michael@0 | 21 | +using google_breakpad::ustr__ZDra; |
michael@0 | 22 | +using google_breakpad::ustr__ZDcfa; |
michael@0 | 23 | using google_breakpad::Module; |
michael@0 | 24 | using google_breakpad::ToUniqueString; |
michael@0 | 25 | using google_breakpad::UniqueString; |
michael@0 | 26 | |
michael@0 | 27 | namespace arm_ex_to_module { |
michael@0 | 28 | |
michael@0 | 29 | // Translate command from extab_data to command for Module. |
michael@0 | 30 | int ARMExToModule::TranslateCmd(const struct extab_data* edata, |
michael@0 | 31 | - Module::StackFrameEntry* entry, string& vsp) { |
michael@0 | 32 | + Module::StackFrameEntry* entry, |
michael@0 | 33 | + Module::Expr& vsp) { |
michael@0 | 34 | int ret = 0; |
michael@0 | 35 | switch (edata->cmd) { |
michael@0 | 36 | case ARM_EXIDX_CMD_FINISH: |
michael@0 | 37 | /* Copy LR to PC if there isn't currently a rule for PC in force. */ |
michael@0 | 38 | if (entry->initial_rules.find(ustr__pc()) |
michael@0 | 39 | == entry->initial_rules.end()) { |
michael@0 | 40 | if (entry->initial_rules.find(ustr__lr()) |
michael@0 | 41 | == entry->initial_rules.end()) { |
michael@0 | 42 | - entry->initial_rules[ustr__pc()] = Module::Expr("lr"); |
michael@0 | 43 | + entry->initial_rules[ustr__pc()] = Module::Expr(ustr__lr(), |
michael@0 | 44 | + 0, false); // "lr" |
michael@0 | 45 | } else { |
michael@0 | 46 | entry->initial_rules[ustr__pc()] = entry->initial_rules[ustr__lr()]; |
michael@0 | 47 | } |
michael@0 | 48 | } |
michael@0 | 49 | break; |
michael@0 | 50 | case ARM_EXIDX_CMD_SUB_FROM_VSP: |
michael@0 | 51 | - { |
michael@0 | 52 | - char c[16]; |
michael@0 | 53 | - sprintf(c, " %d -", edata->data); |
michael@0 | 54 | - vsp += c; |
michael@0 | 55 | - } |
michael@0 | 56 | + vsp = vsp.add_delta(- static_cast<long>(edata->data)); |
michael@0 | 57 | break; |
michael@0 | 58 | case ARM_EXIDX_CMD_ADD_TO_VSP: |
michael@0 | 59 | - { |
michael@0 | 60 | - char c[16]; |
michael@0 | 61 | - sprintf(c, " %d +", edata->data); |
michael@0 | 62 | - vsp += c; |
michael@0 | 63 | - } |
michael@0 | 64 | + vsp = vsp.add_delta(static_cast<long>(edata->data)); |
michael@0 | 65 | break; |
michael@0 | 66 | case ARM_EXIDX_CMD_REG_POP: |
michael@0 | 67 | for (unsigned int i = 0; i < 16; i++) { |
michael@0 | 68 | if (edata->data & (1 << i)) { |
michael@0 | 69 | - entry->initial_rules[ToUniqueString(regnames[i])] |
michael@0 | 70 | - = Module::Expr(vsp + " ^"); |
michael@0 | 71 | - vsp += " 4 +"; |
michael@0 | 72 | + entry->initial_rules[ToUniqueString(regnames[i])] = vsp.deref(); |
michael@0 | 73 | + vsp = vsp.add_delta(4); |
michael@0 | 74 | } |
michael@0 | 75 | } |
michael@0 | 76 | /* Set cfa in case the SP got popped. */ |
michael@0 | 77 | if (edata->data & (1 << 13)) { |
michael@0 | 78 | - Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()]; |
michael@0 | 79 | - // It must be a postfix expression (we don't generate anything |
michael@0 | 80 | - // else here), so return -1 to fail out if it isn't. |
michael@0 | 81 | - if (!vsp_expr.isExprPostfix()) { |
michael@0 | 82 | - ret = -1; |
michael@0 | 83 | - break; |
michael@0 | 84 | - }; |
michael@0 | 85 | - vsp = vsp_expr.getExprPostfix(); |
michael@0 | 86 | + vsp = entry->initial_rules[ustr__sp()]; |
michael@0 | 87 | } |
michael@0 | 88 | break; |
michael@0 | 89 | case ARM_EXIDX_CMD_REG_TO_SP: { |
michael@0 | 90 | assert (edata->data < 16); |
michael@0 | 91 | const char* const regname = regnames[edata->data]; |
michael@0 | 92 | const UniqueString* regname_us = ToUniqueString(regname); |
michael@0 | 93 | if (entry->initial_rules.find(regname_us) == entry->initial_rules.end()) { |
michael@0 | 94 | - entry->initial_rules[ustr__sp()] = Module::Expr(regname); |
michael@0 | 95 | + entry->initial_rules[ustr__sp()] = Module::Expr(regname_us, |
michael@0 | 96 | + 0, false); // "regname" |
michael@0 | 97 | } else { |
michael@0 | 98 | entry->initial_rules[ustr__sp()] = entry->initial_rules[regname_us]; |
michael@0 | 99 | } |
michael@0 | 100 | - Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()]; |
michael@0 | 101 | - if (!vsp_expr.isExprPostfix()) { |
michael@0 | 102 | - ret = -1; |
michael@0 | 103 | - break; |
michael@0 | 104 | - }; |
michael@0 | 105 | - vsp = vsp_expr.getExprPostfix(); |
michael@0 | 106 | + vsp = entry->initial_rules[ustr__sp()]; |
michael@0 | 107 | break; |
michael@0 | 108 | } |
michael@0 | 109 | case ARM_EXIDX_CMD_VFP_POP: |
michael@0 | 110 | /* Don't recover VFP registers, but be sure to adjust the stack |
michael@0 | 111 | pointer. */ |
michael@0 | 112 | for (unsigned int i = ARM_EXBUF_START(edata->data); |
michael@0 | 113 | i <= ARM_EXBUF_END(edata->data); i++) { |
michael@0 | 114 | - vsp += " 8 +"; |
michael@0 | 115 | + vsp = vsp.add_delta(8); |
michael@0 | 116 | } |
michael@0 | 117 | if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) { |
michael@0 | 118 | - vsp += " 4 +"; |
michael@0 | 119 | + vsp = vsp.add_delta(4); |
michael@0 | 120 | } |
michael@0 | 121 | break; |
michael@0 | 122 | case ARM_EXIDX_CMD_WREG_POP: |
michael@0 | 123 | for (unsigned int i = ARM_EXBUF_START(edata->data); |
michael@0 | 124 | i <= ARM_EXBUF_END(edata->data); i++) { |
michael@0 | 125 | - vsp += " 8 +"; |
michael@0 | 126 | + vsp = vsp.add_delta(8); |
michael@0 | 127 | } |
michael@0 | 128 | break; |
michael@0 | 129 | case ARM_EXIDX_CMD_WCGR_POP: |
michael@0 | 130 | // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4" |
michael@0 | 131 | for (unsigned int i = 0; i < 4; i++) { |
michael@0 | 132 | if (edata->data & (1 << i)) { |
michael@0 | 133 | - vsp += " 4 +"; |
michael@0 | 134 | + vsp = vsp.add_delta(4); |
michael@0 | 135 | } |
michael@0 | 136 | } |
michael@0 | 137 | break; |
michael@0 | 138 | case ARM_EXIDX_CMD_REFUSED: |
michael@0 | 139 | case ARM_EXIDX_CMD_RESERVED: |
michael@0 | 140 | ret = -1; |
michael@0 | 141 | break; |
michael@0 | 142 | } |
michael@0 | 143 | return ret; |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) { |
michael@0 | 147 | stack_frame_entry_ = new Module::StackFrameEntry; |
michael@0 | 148 | stack_frame_entry_->address = addr; |
michael@0 | 149 | stack_frame_entry_->size = size; |
michael@0 | 150 | - stack_frame_entry_->initial_rules[ToUniqueString(kCFA)] = Module::Expr("sp"); |
michael@0 | 151 | - vsp_ = "sp"; |
michael@0 | 152 | + Module::Expr sp_expr = Module::Expr(ustr__sp(), 0, false); // "sp" |
michael@0 | 153 | + stack_frame_entry_->initial_rules[ustr__ZDcfa()] = sp_expr; // ".cfa" |
michael@0 | 154 | + vsp_ = sp_expr; |
michael@0 | 155 | } |
michael@0 | 156 | |
michael@0 | 157 | int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) { |
michael@0 | 158 | return TranslateCmd(edata, stack_frame_entry_, vsp_) ; |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | void ARMExToModule::DeleteStackFrame() { |
michael@0 | 162 | delete stack_frame_entry_; |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | void ARMExToModule::SubmitStackFrame() { |
michael@0 | 166 | // return address always winds up in pc |
michael@0 | 167 | - stack_frame_entry_->initial_rules[ToUniqueString(kRA)] |
michael@0 | 168 | + stack_frame_entry_->initial_rules[ustr__ZDra()] // ".ra" |
michael@0 | 169 | = stack_frame_entry_->initial_rules[ustr__pc()]; |
michael@0 | 170 | // the final value of vsp is the new value of sp |
michael@0 | 171 | stack_frame_entry_->initial_rules[ustr__sp()] = vsp_; |
michael@0 | 172 | module_->AddStackFrameEntry(stack_frame_entry_); |
michael@0 | 173 | } |
michael@0 | 174 | |
michael@0 | 175 | } // namespace arm_ex_to_module |
michael@0 | 176 | diff --git a/src/common/arm_ex_to_module.h b/src/common/arm_ex_to_module.h |
michael@0 | 177 | --- a/src/common/arm_ex_to_module.h |
michael@0 | 178 | +++ b/src/common/arm_ex_to_module.h |
michael@0 | 179 | @@ -89,19 +89,16 @@ struct extab_data { |
michael@0 | 180 | uint32_t data; |
michael@0 | 181 | }; |
michael@0 | 182 | |
michael@0 | 183 | enum extab_cmd_flags { |
michael@0 | 184 | ARM_EXIDX_VFP_SHIFT_16 = 1 << 16, |
michael@0 | 185 | ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX |
michael@0 | 186 | }; |
michael@0 | 187 | |
michael@0 | 188 | -const string kRA = ".ra"; |
michael@0 | 189 | -const string kCFA = ".cfa"; |
michael@0 | 190 | - |
michael@0 | 191 | static const char* const regnames[] = { |
michael@0 | 192 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
michael@0 | 193 | "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", |
michael@0 | 194 | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", |
michael@0 | 195 | "fps", "cpsr" |
michael@0 | 196 | }; |
michael@0 | 197 | |
michael@0 | 198 | // Receives information from arm_ex_reader::ExceptionTableInfo |
michael@0 | 199 | @@ -113,17 +110,17 @@ class ARMExToModule { |
michael@0 | 200 | ~ARMExToModule() { } |
michael@0 | 201 | void AddStackFrame(uintptr_t addr, size_t size); |
michael@0 | 202 | int ImproveStackFrame(const struct extab_data* edata); |
michael@0 | 203 | void DeleteStackFrame(); |
michael@0 | 204 | void SubmitStackFrame(); |
michael@0 | 205 | private: |
michael@0 | 206 | Module* module_; |
michael@0 | 207 | Module::StackFrameEntry* stack_frame_entry_; |
michael@0 | 208 | - string vsp_; |
michael@0 | 209 | + Module::Expr vsp_; |
michael@0 | 210 | int TranslateCmd(const struct extab_data* edata, |
michael@0 | 211 | Module::StackFrameEntry* entry, |
michael@0 | 212 | - string& vsp); |
michael@0 | 213 | + Module::Expr& vsp); |
michael@0 | 214 | }; |
michael@0 | 215 | |
michael@0 | 216 | } // namespace arm_ex_to_module |
michael@0 | 217 | |
michael@0 | 218 | #endif // COMMON_ARM_EX_TO_MODULE__ |
michael@0 | 219 | diff --git a/src/common/module.h b/src/common/module.h |
michael@0 | 220 | --- a/src/common/module.h |
michael@0 | 221 | +++ b/src/common/module.h |
michael@0 | 222 | @@ -39,16 +39,20 @@ |
michael@0 | 223 | #define COMMON_LINUX_MODULE_H__ |
michael@0 | 224 | |
michael@0 | 225 | #include <iostream> |
michael@0 | 226 | #include <map> |
michael@0 | 227 | #include <set> |
michael@0 | 228 | #include <string> |
michael@0 | 229 | #include <vector> |
michael@0 | 230 | |
michael@0 | 231 | +#include <assert.h> |
michael@0 | 232 | +#include <stdlib.h> |
michael@0 | 233 | +#include <stdio.h> |
michael@0 | 234 | + |
michael@0 | 235 | #include "common/symbol_data.h" |
michael@0 | 236 | #include "common/using_std_string.h" |
michael@0 | 237 | #include "common/unique_string.h" |
michael@0 | 238 | #include "google_breakpad/common/breakpad_types.h" |
michael@0 | 239 | |
michael@0 | 240 | namespace google_breakpad { |
michael@0 | 241 | |
michael@0 | 242 | using std::set; |
michael@0 | 243 | @@ -161,30 +165,98 @@ class Module { |
michael@0 | 244 | // Construct an invalid expression |
michael@0 | 245 | Expr() { |
michael@0 | 246 | postfix_ = ""; |
michael@0 | 247 | ident_ = NULL; |
michael@0 | 248 | offset_ = 0; |
michael@0 | 249 | how_ = kExprInvalid; |
michael@0 | 250 | } |
michael@0 | 251 | bool isExprInvalid() const { return how_ == kExprInvalid; } |
michael@0 | 252 | - bool isExprPostfix() const { return how_ == kExprPostfix; } |
michael@0 | 253 | |
michael@0 | 254 | - // Return the postfix expression string. This is only |
michael@0 | 255 | - // meaningful on Exprs for which isExprPostfix returns true. |
michael@0 | 256 | - // In all other cases it returns an empty string. |
michael@0 | 257 | - string getExprPostfix() const { return postfix_; } |
michael@0 | 258 | + // Return the postfix expression string, either directly, |
michael@0 | 259 | + // if this is a postfix expression, or by synthesising it |
michael@0 | 260 | + // for a simple expression. |
michael@0 | 261 | + string getExprPostfix() const { |
michael@0 | 262 | + switch (how_) { |
michael@0 | 263 | + case kExprPostfix: |
michael@0 | 264 | + return postfix_; |
michael@0 | 265 | + case kExprSimple: |
michael@0 | 266 | + case kExprSimpleMem: { |
michael@0 | 267 | + char buf[40]; |
michael@0 | 268 | + sprintf(buf, " %ld %c%s", labs(offset_), offset_ < 0 ? '-' : '+', |
michael@0 | 269 | + how_ == kExprSimple ? "" : " ^"); |
michael@0 | 270 | + return string(FromUniqueString(ident_)) + string(buf); |
michael@0 | 271 | + } |
michael@0 | 272 | + case kExprInvalid: |
michael@0 | 273 | + default: |
michael@0 | 274 | + assert(0 && "getExprPostfix: invalid Module::Expr type"); |
michael@0 | 275 | + return "Expr::genExprPostfix: kExprInvalid"; |
michael@0 | 276 | + } |
michael@0 | 277 | + } |
michael@0 | 278 | |
michael@0 | 279 | bool operator==(const Expr& other) const { |
michael@0 | 280 | return how_ == other.how_ && |
michael@0 | 281 | ident_ == other.ident_ && |
michael@0 | 282 | offset_ == other.offset_ && |
michael@0 | 283 | postfix_ == other.postfix_; |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | + // Returns an Expr which evaluates to |this| + |delta| |
michael@0 | 287 | + Expr add_delta(long delta) { |
michael@0 | 288 | + if (delta == 0) { |
michael@0 | 289 | + return *this; |
michael@0 | 290 | + } |
michael@0 | 291 | + // If it's a simple form expression of the form "identifier + offset", |
michael@0 | 292 | + // simply add |delta| on to |offset|. In the other two possible |
michael@0 | 293 | + // cases: |
michael@0 | 294 | + // *(identifier + offset) |
michael@0 | 295 | + // completely arbitrary postfix expression string |
michael@0 | 296 | + // the only option is to "downgrade" it to a postfix expression and add |
michael@0 | 297 | + // "+/- delta" at the end of the string, since the result can't be |
michael@0 | 298 | + // represented in the simple form. |
michael@0 | 299 | + switch (how_) { |
michael@0 | 300 | + case kExprSimpleMem: |
michael@0 | 301 | + case kExprPostfix: { |
michael@0 | 302 | + char buf[40]; |
michael@0 | 303 | + sprintf(buf, " %ld %c", labs(delta), delta < 0 ? '-' : '+'); |
michael@0 | 304 | + return Expr(getExprPostfix() + string(buf)); |
michael@0 | 305 | + } |
michael@0 | 306 | + case kExprSimple: |
michael@0 | 307 | + return Expr(ident_, offset_ + delta, false); |
michael@0 | 308 | + case kExprInvalid: |
michael@0 | 309 | + default: |
michael@0 | 310 | + assert(0 && "add_delta: invalid Module::Expr type"); |
michael@0 | 311 | + // Invalid inputs produce an invalid result |
michael@0 | 312 | + return Expr(); |
michael@0 | 313 | + } |
michael@0 | 314 | + } |
michael@0 | 315 | + |
michael@0 | 316 | + // Returns an Expr which evaluates to *|this| |
michael@0 | 317 | + Expr deref() { |
michael@0 | 318 | + // In the simplest case, a kExprSimple can be changed into a |
michael@0 | 319 | + // kExprSimpleMem. In all other cases it has to be dumped as a |
michael@0 | 320 | + // postfix string, and " ^" added at the end. |
michael@0 | 321 | + switch (how_) { |
michael@0 | 322 | + case kExprSimple: { |
michael@0 | 323 | + Expr t = *this; |
michael@0 | 324 | + t.how_ = kExprSimpleMem; |
michael@0 | 325 | + return t; |
michael@0 | 326 | + } |
michael@0 | 327 | + case kExprSimpleMem: |
michael@0 | 328 | + case kExprPostfix: { |
michael@0 | 329 | + return Expr(getExprPostfix() + " ^"); |
michael@0 | 330 | + } |
michael@0 | 331 | + case kExprInvalid: |
michael@0 | 332 | + default: |
michael@0 | 333 | + assert(0 && "deref: invalid Module::Expr type"); |
michael@0 | 334 | + // Invalid inputs produce an invalid result |
michael@0 | 335 | + return Expr(); |
michael@0 | 336 | + } |
michael@0 | 337 | + } |
michael@0 | 338 | + |
michael@0 | 339 | // The identifier that gives the starting value for simple expressions. |
michael@0 | 340 | const UniqueString* ident_; |
michael@0 | 341 | // The offset to add for simple expressions. |
michael@0 | 342 | long offset_; |
michael@0 | 343 | // The Postfix expression string to evaluate for non-simple expressions. |
michael@0 | 344 | string postfix_; |
michael@0 | 345 | // The operation expressed by this expression. |
michael@0 | 346 | ExprHow how_; |