mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
622c6ed12a
--HG-- rename : toolkit/crashreporter/breakpad-patches/12-sht-arm-exidx-define.patch => toolkit/crashreporter/breakpad-patches/16-sht-arm-exidx-define.patch
347 lines
12 KiB
Diff
347 lines
12 KiB
Diff
# HG changeset patch
|
|
# User Julian Seward <jseward@acm.org>
|
|
# Date 1372168568 -7200
|
|
# Tue Jun 25 15:56:08 2013 +0200
|
|
# Node ID 6d06a09b3f5624dd833bd6f905bfd88e3fdec00a
|
|
# Parent 11f7a9321b7d5d85eddc2db16e58e6870a7c4e06
|
|
Bug 883126 - Improve performance of EXIDX unwinding in Breakpad. r=ted
|
|
|
|
diff --git a/src/common/arm_ex_to_module.cc b/src/common/arm_ex_to_module.cc
|
|
--- a/src/common/arm_ex_to_module.cc
|
|
+++ b/src/common/arm_ex_to_module.cc
|
|
@@ -66,141 +66,126 @@ WITH THE SOFTWARE OR THE USE OR OTHER DE
|
|
|
|
#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f)
|
|
#define ARM_EXBUF_COUNT(x) ((x) & 0x0f)
|
|
#define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x))
|
|
|
|
using google_breakpad::ustr__pc;
|
|
using google_breakpad::ustr__lr;
|
|
using google_breakpad::ustr__sp;
|
|
+using google_breakpad::ustr__ZDra;
|
|
+using google_breakpad::ustr__ZDcfa;
|
|
using google_breakpad::Module;
|
|
using google_breakpad::ToUniqueString;
|
|
using google_breakpad::UniqueString;
|
|
|
|
namespace arm_ex_to_module {
|
|
|
|
// Translate command from extab_data to command for Module.
|
|
int ARMExToModule::TranslateCmd(const struct extab_data* edata,
|
|
- Module::StackFrameEntry* entry, string& vsp) {
|
|
+ Module::StackFrameEntry* entry,
|
|
+ Module::Expr& vsp) {
|
|
int ret = 0;
|
|
switch (edata->cmd) {
|
|
case ARM_EXIDX_CMD_FINISH:
|
|
/* Copy LR to PC if there isn't currently a rule for PC in force. */
|
|
if (entry->initial_rules.find(ustr__pc())
|
|
== entry->initial_rules.end()) {
|
|
if (entry->initial_rules.find(ustr__lr())
|
|
== entry->initial_rules.end()) {
|
|
- entry->initial_rules[ustr__pc()] = Module::Expr("lr");
|
|
+ entry->initial_rules[ustr__pc()] = Module::Expr(ustr__lr(),
|
|
+ 0, false); // "lr"
|
|
} else {
|
|
entry->initial_rules[ustr__pc()] = entry->initial_rules[ustr__lr()];
|
|
}
|
|
}
|
|
break;
|
|
case ARM_EXIDX_CMD_SUB_FROM_VSP:
|
|
- {
|
|
- char c[16];
|
|
- sprintf(c, " %d -", edata->data);
|
|
- vsp += c;
|
|
- }
|
|
+ vsp = vsp.add_delta(- static_cast<long>(edata->data));
|
|
break;
|
|
case ARM_EXIDX_CMD_ADD_TO_VSP:
|
|
- {
|
|
- char c[16];
|
|
- sprintf(c, " %d +", edata->data);
|
|
- vsp += c;
|
|
- }
|
|
+ vsp = vsp.add_delta(static_cast<long>(edata->data));
|
|
break;
|
|
case ARM_EXIDX_CMD_REG_POP:
|
|
for (unsigned int i = 0; i < 16; i++) {
|
|
if (edata->data & (1 << i)) {
|
|
- entry->initial_rules[ToUniqueString(regnames[i])]
|
|
- = Module::Expr(vsp + " ^");
|
|
- vsp += " 4 +";
|
|
+ entry->initial_rules[ToUniqueString(regnames[i])] = vsp.deref();
|
|
+ vsp = vsp.add_delta(4);
|
|
}
|
|
}
|
|
/* Set cfa in case the SP got popped. */
|
|
if (edata->data & (1 << 13)) {
|
|
- Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()];
|
|
- // It must be a postfix expression (we don't generate anything
|
|
- // else here), so return -1 to fail out if it isn't.
|
|
- if (!vsp_expr.isExprPostfix()) {
|
|
- ret = -1;
|
|
- break;
|
|
- };
|
|
- vsp = vsp_expr.getExprPostfix();
|
|
+ vsp = entry->initial_rules[ustr__sp()];
|
|
}
|
|
break;
|
|
case ARM_EXIDX_CMD_REG_TO_SP: {
|
|
assert (edata->data < 16);
|
|
const char* const regname = regnames[edata->data];
|
|
const UniqueString* regname_us = ToUniqueString(regname);
|
|
if (entry->initial_rules.find(regname_us) == entry->initial_rules.end()) {
|
|
- entry->initial_rules[ustr__sp()] = Module::Expr(regname);
|
|
+ entry->initial_rules[ustr__sp()] = Module::Expr(regname_us,
|
|
+ 0, false); // "regname"
|
|
} else {
|
|
entry->initial_rules[ustr__sp()] = entry->initial_rules[regname_us];
|
|
}
|
|
- Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()];
|
|
- if (!vsp_expr.isExprPostfix()) {
|
|
- ret = -1;
|
|
- break;
|
|
- };
|
|
- vsp = vsp_expr.getExprPostfix();
|
|
+ vsp = entry->initial_rules[ustr__sp()];
|
|
break;
|
|
}
|
|
case ARM_EXIDX_CMD_VFP_POP:
|
|
/* Don't recover VFP registers, but be sure to adjust the stack
|
|
pointer. */
|
|
for (unsigned int i = ARM_EXBUF_START(edata->data);
|
|
i <= ARM_EXBUF_END(edata->data); i++) {
|
|
- vsp += " 8 +";
|
|
+ vsp = vsp.add_delta(8);
|
|
}
|
|
if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) {
|
|
- vsp += " 4 +";
|
|
+ vsp = vsp.add_delta(4);
|
|
}
|
|
break;
|
|
case ARM_EXIDX_CMD_WREG_POP:
|
|
for (unsigned int i = ARM_EXBUF_START(edata->data);
|
|
i <= ARM_EXBUF_END(edata->data); i++) {
|
|
- vsp += " 8 +";
|
|
+ vsp = vsp.add_delta(8);
|
|
}
|
|
break;
|
|
case ARM_EXIDX_CMD_WCGR_POP:
|
|
// Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4"
|
|
for (unsigned int i = 0; i < 4; i++) {
|
|
if (edata->data & (1 << i)) {
|
|
- vsp += " 4 +";
|
|
+ vsp = vsp.add_delta(4);
|
|
}
|
|
}
|
|
break;
|
|
case ARM_EXIDX_CMD_REFUSED:
|
|
case ARM_EXIDX_CMD_RESERVED:
|
|
ret = -1;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) {
|
|
stack_frame_entry_ = new Module::StackFrameEntry;
|
|
stack_frame_entry_->address = addr;
|
|
stack_frame_entry_->size = size;
|
|
- stack_frame_entry_->initial_rules[ToUniqueString(kCFA)] = Module::Expr("sp");
|
|
- vsp_ = "sp";
|
|
+ Module::Expr sp_expr = Module::Expr(ustr__sp(), 0, false); // "sp"
|
|
+ stack_frame_entry_->initial_rules[ustr__ZDcfa()] = sp_expr; // ".cfa"
|
|
+ vsp_ = sp_expr;
|
|
}
|
|
|
|
int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) {
|
|
return TranslateCmd(edata, stack_frame_entry_, vsp_) ;
|
|
}
|
|
|
|
void ARMExToModule::DeleteStackFrame() {
|
|
delete stack_frame_entry_;
|
|
}
|
|
|
|
void ARMExToModule::SubmitStackFrame() {
|
|
// return address always winds up in pc
|
|
- stack_frame_entry_->initial_rules[ToUniqueString(kRA)]
|
|
+ stack_frame_entry_->initial_rules[ustr__ZDra()] // ".ra"
|
|
= stack_frame_entry_->initial_rules[ustr__pc()];
|
|
// the final value of vsp is the new value of sp
|
|
stack_frame_entry_->initial_rules[ustr__sp()] = vsp_;
|
|
module_->AddStackFrameEntry(stack_frame_entry_);
|
|
}
|
|
|
|
} // namespace arm_ex_to_module
|
|
diff --git a/src/common/arm_ex_to_module.h b/src/common/arm_ex_to_module.h
|
|
--- a/src/common/arm_ex_to_module.h
|
|
+++ b/src/common/arm_ex_to_module.h
|
|
@@ -89,19 +89,16 @@ struct extab_data {
|
|
uint32_t data;
|
|
};
|
|
|
|
enum extab_cmd_flags {
|
|
ARM_EXIDX_VFP_SHIFT_16 = 1 << 16,
|
|
ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX
|
|
};
|
|
|
|
-const string kRA = ".ra";
|
|
-const string kCFA = ".cfa";
|
|
-
|
|
static const char* const regnames[] = {
|
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
|
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
|
|
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
|
|
"fps", "cpsr"
|
|
};
|
|
|
|
// Receives information from arm_ex_reader::ExceptionTableInfo
|
|
@@ -113,17 +110,17 @@ class ARMExToModule {
|
|
~ARMExToModule() { }
|
|
void AddStackFrame(uintptr_t addr, size_t size);
|
|
int ImproveStackFrame(const struct extab_data* edata);
|
|
void DeleteStackFrame();
|
|
void SubmitStackFrame();
|
|
private:
|
|
Module* module_;
|
|
Module::StackFrameEntry* stack_frame_entry_;
|
|
- string vsp_;
|
|
+ Module::Expr vsp_;
|
|
int TranslateCmd(const struct extab_data* edata,
|
|
Module::StackFrameEntry* entry,
|
|
- string& vsp);
|
|
+ Module::Expr& vsp);
|
|
};
|
|
|
|
} // namespace arm_ex_to_module
|
|
|
|
#endif // COMMON_ARM_EX_TO_MODULE__
|
|
diff --git a/src/common/module.h b/src/common/module.h
|
|
--- a/src/common/module.h
|
|
+++ b/src/common/module.h
|
|
@@ -39,16 +39,20 @@
|
|
#define COMMON_LINUX_MODULE_H__
|
|
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
+#include <assert.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+
|
|
#include "common/symbol_data.h"
|
|
#include "common/using_std_string.h"
|
|
#include "common/unique_string.h"
|
|
#include "google_breakpad/common/breakpad_types.h"
|
|
|
|
namespace google_breakpad {
|
|
|
|
using std::set;
|
|
@@ -161,30 +165,98 @@ class Module {
|
|
// Construct an invalid expression
|
|
Expr() {
|
|
postfix_ = "";
|
|
ident_ = NULL;
|
|
offset_ = 0;
|
|
how_ = kExprInvalid;
|
|
}
|
|
bool isExprInvalid() const { return how_ == kExprInvalid; }
|
|
- bool isExprPostfix() const { return how_ == kExprPostfix; }
|
|
|
|
- // Return the postfix expression string. This is only
|
|
- // meaningful on Exprs for which isExprPostfix returns true.
|
|
- // In all other cases it returns an empty string.
|
|
- string getExprPostfix() const { return postfix_; }
|
|
+ // Return the postfix expression string, either directly,
|
|
+ // if this is a postfix expression, or by synthesising it
|
|
+ // for a simple expression.
|
|
+ string getExprPostfix() const {
|
|
+ switch (how_) {
|
|
+ case kExprPostfix:
|
|
+ return postfix_;
|
|
+ case kExprSimple:
|
|
+ case kExprSimpleMem: {
|
|
+ char buf[40];
|
|
+ sprintf(buf, " %ld %c%s", labs(offset_), offset_ < 0 ? '-' : '+',
|
|
+ how_ == kExprSimple ? "" : " ^");
|
|
+ return string(FromUniqueString(ident_)) + string(buf);
|
|
+ }
|
|
+ case kExprInvalid:
|
|
+ default:
|
|
+ assert(0 && "getExprPostfix: invalid Module::Expr type");
|
|
+ return "Expr::genExprPostfix: kExprInvalid";
|
|
+ }
|
|
+ }
|
|
|
|
bool operator==(const Expr& other) const {
|
|
return how_ == other.how_ &&
|
|
ident_ == other.ident_ &&
|
|
offset_ == other.offset_ &&
|
|
postfix_ == other.postfix_;
|
|
}
|
|
|
|
+ // Returns an Expr which evaluates to |this| + |delta|
|
|
+ Expr add_delta(long delta) {
|
|
+ if (delta == 0) {
|
|
+ return *this;
|
|
+ }
|
|
+ // If it's a simple form expression of the form "identifier + offset",
|
|
+ // simply add |delta| on to |offset|. In the other two possible
|
|
+ // cases:
|
|
+ // *(identifier + offset)
|
|
+ // completely arbitrary postfix expression string
|
|
+ // the only option is to "downgrade" it to a postfix expression and add
|
|
+ // "+/- delta" at the end of the string, since the result can't be
|
|
+ // represented in the simple form.
|
|
+ switch (how_) {
|
|
+ case kExprSimpleMem:
|
|
+ case kExprPostfix: {
|
|
+ char buf[40];
|
|
+ sprintf(buf, " %ld %c", labs(delta), delta < 0 ? '-' : '+');
|
|
+ return Expr(getExprPostfix() + string(buf));
|
|
+ }
|
|
+ case kExprSimple:
|
|
+ return Expr(ident_, offset_ + delta, false);
|
|
+ case kExprInvalid:
|
|
+ default:
|
|
+ assert(0 && "add_delta: invalid Module::Expr type");
|
|
+ // Invalid inputs produce an invalid result
|
|
+ return Expr();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Returns an Expr which evaluates to *|this|
|
|
+ Expr deref() {
|
|
+ // In the simplest case, a kExprSimple can be changed into a
|
|
+ // kExprSimpleMem. In all other cases it has to be dumped as a
|
|
+ // postfix string, and " ^" added at the end.
|
|
+ switch (how_) {
|
|
+ case kExprSimple: {
|
|
+ Expr t = *this;
|
|
+ t.how_ = kExprSimpleMem;
|
|
+ return t;
|
|
+ }
|
|
+ case kExprSimpleMem:
|
|
+ case kExprPostfix: {
|
|
+ return Expr(getExprPostfix() + " ^");
|
|
+ }
|
|
+ case kExprInvalid:
|
|
+ default:
|
|
+ assert(0 && "deref: invalid Module::Expr type");
|
|
+ // Invalid inputs produce an invalid result
|
|
+ return Expr();
|
|
+ }
|
|
+ }
|
|
+
|
|
// The identifier that gives the starting value for simple expressions.
|
|
const UniqueString* ident_;
|
|
// The offset to add for simple expressions.
|
|
long offset_;
|
|
// The Postfix expression string to evaluate for non-simple expressions.
|
|
string postfix_;
|
|
// The operation expressed by this expression.
|
|
ExprHow how_;
|