mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
Bug 883126 - Improve performance of EXIDX unwinding in Breakpad. r=ted
This commit is contained in:
parent
1808439874
commit
b58fb25691
@ -71,6 +71,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
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;
|
||||
@ -79,7 +81,8 @@ 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:
|
||||
@ -88,44 +91,29 @@ int ARMExToModule::TranslateCmd(const struct extab_data* edata,
|
||||
== 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: {
|
||||
@ -133,16 +121,12 @@ int ARMExToModule::TranslateCmd(const struct extab_data* edata,
|
||||
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:
|
||||
@ -150,23 +134,23 @@ int ARMExToModule::TranslateCmd(const struct extab_data* edata,
|
||||
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;
|
||||
@ -182,8 +166,9 @@ 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) {
|
||||
@ -196,7 +181,7 @@ void ARMExToModule::DeleteStackFrame() {
|
||||
|
||||
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_;
|
||||
|
@ -94,9 +94,6 @@ enum extab_cmd_flags {
|
||||
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",
|
||||
@ -118,10 +115,10 @@ class ARMExToModule {
|
||||
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
|
||||
|
@ -44,6 +44,10 @@
|
||||
#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"
|
||||
@ -166,12 +170,27 @@ class Module {
|
||||
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_ &&
|
||||
@ -180,6 +199,59 @@ class Module {
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user