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__pc;
|
||||||
using google_breakpad::ustr__lr;
|
using google_breakpad::ustr__lr;
|
||||||
using google_breakpad::ustr__sp;
|
using google_breakpad::ustr__sp;
|
||||||
|
using google_breakpad::ustr__ZDra;
|
||||||
|
using google_breakpad::ustr__ZDcfa;
|
||||||
using google_breakpad::Module;
|
using google_breakpad::Module;
|
||||||
using google_breakpad::ToUniqueString;
|
using google_breakpad::ToUniqueString;
|
||||||
using google_breakpad::UniqueString;
|
using google_breakpad::UniqueString;
|
||||||
@ -79,7 +81,8 @@ namespace arm_ex_to_module {
|
|||||||
|
|
||||||
// Translate command from extab_data to command for Module.
|
// Translate command from extab_data to command for Module.
|
||||||
int ARMExToModule::TranslateCmd(const struct extab_data* edata,
|
int ARMExToModule::TranslateCmd(const struct extab_data* edata,
|
||||||
Module::StackFrameEntry* entry, string& vsp) {
|
Module::StackFrameEntry* entry,
|
||||||
|
Module::Expr& vsp) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
switch (edata->cmd) {
|
switch (edata->cmd) {
|
||||||
case ARM_EXIDX_CMD_FINISH:
|
case ARM_EXIDX_CMD_FINISH:
|
||||||
@ -88,44 +91,29 @@ int ARMExToModule::TranslateCmd(const struct extab_data* edata,
|
|||||||
== entry->initial_rules.end()) {
|
== entry->initial_rules.end()) {
|
||||||
if (entry->initial_rules.find(ustr__lr())
|
if (entry->initial_rules.find(ustr__lr())
|
||||||
== entry->initial_rules.end()) {
|
== 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 {
|
} else {
|
||||||
entry->initial_rules[ustr__pc()] = entry->initial_rules[ustr__lr()];
|
entry->initial_rules[ustr__pc()] = entry->initial_rules[ustr__lr()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARM_EXIDX_CMD_SUB_FROM_VSP:
|
case ARM_EXIDX_CMD_SUB_FROM_VSP:
|
||||||
{
|
vsp = vsp.add_delta(- static_cast<long>(edata->data));
|
||||||
char c[16];
|
|
||||||
sprintf(c, " %d -", edata->data);
|
|
||||||
vsp += c;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ARM_EXIDX_CMD_ADD_TO_VSP:
|
case ARM_EXIDX_CMD_ADD_TO_VSP:
|
||||||
{
|
vsp = vsp.add_delta(static_cast<long>(edata->data));
|
||||||
char c[16];
|
|
||||||
sprintf(c, " %d +", edata->data);
|
|
||||||
vsp += c;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ARM_EXIDX_CMD_REG_POP:
|
case ARM_EXIDX_CMD_REG_POP:
|
||||||
for (unsigned int i = 0; i < 16; i++) {
|
for (unsigned int i = 0; i < 16; i++) {
|
||||||
if (edata->data & (1 << i)) {
|
if (edata->data & (1 << i)) {
|
||||||
entry->initial_rules[ToUniqueString(regnames[i])]
|
entry->initial_rules[ToUniqueString(regnames[i])] = vsp.deref();
|
||||||
= Module::Expr(vsp + " ^");
|
vsp = vsp.add_delta(4);
|
||||||
vsp += " 4 +";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Set cfa in case the SP got popped. */
|
/* Set cfa in case the SP got popped. */
|
||||||
if (edata->data & (1 << 13)) {
|
if (edata->data & (1 << 13)) {
|
||||||
Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()];
|
vsp = 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();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARM_EXIDX_CMD_REG_TO_SP: {
|
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 char* const regname = regnames[edata->data];
|
||||||
const UniqueString* regname_us = ToUniqueString(regname);
|
const UniqueString* regname_us = ToUniqueString(regname);
|
||||||
if (entry->initial_rules.find(regname_us) == entry->initial_rules.end()) {
|
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 {
|
} else {
|
||||||
entry->initial_rules[ustr__sp()] = entry->initial_rules[regname_us];
|
entry->initial_rules[ustr__sp()] = entry->initial_rules[regname_us];
|
||||||
}
|
}
|
||||||
Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()];
|
vsp = entry->initial_rules[ustr__sp()];
|
||||||
if (!vsp_expr.isExprPostfix()) {
|
|
||||||
ret = -1;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
vsp = vsp_expr.getExprPostfix();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ARM_EXIDX_CMD_VFP_POP:
|
case ARM_EXIDX_CMD_VFP_POP:
|
||||||
@ -150,23 +134,23 @@ int ARMExToModule::TranslateCmd(const struct extab_data* edata,
|
|||||||
pointer. */
|
pointer. */
|
||||||
for (unsigned int i = ARM_EXBUF_START(edata->data);
|
for (unsigned int i = ARM_EXBUF_START(edata->data);
|
||||||
i <= ARM_EXBUF_END(edata->data); i++) {
|
i <= ARM_EXBUF_END(edata->data); i++) {
|
||||||
vsp += " 8 +";
|
vsp = vsp.add_delta(8);
|
||||||
}
|
}
|
||||||
if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) {
|
if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) {
|
||||||
vsp += " 4 +";
|
vsp = vsp.add_delta(4);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARM_EXIDX_CMD_WREG_POP:
|
case ARM_EXIDX_CMD_WREG_POP:
|
||||||
for (unsigned int i = ARM_EXBUF_START(edata->data);
|
for (unsigned int i = ARM_EXBUF_START(edata->data);
|
||||||
i <= ARM_EXBUF_END(edata->data); i++) {
|
i <= ARM_EXBUF_END(edata->data); i++) {
|
||||||
vsp += " 8 +";
|
vsp = vsp.add_delta(8);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARM_EXIDX_CMD_WCGR_POP:
|
case ARM_EXIDX_CMD_WCGR_POP:
|
||||||
// Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4"
|
// Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4"
|
||||||
for (unsigned int i = 0; i < 4; i++) {
|
for (unsigned int i = 0; i < 4; i++) {
|
||||||
if (edata->data & (1 << i)) {
|
if (edata->data & (1 << i)) {
|
||||||
vsp += " 4 +";
|
vsp = vsp.add_delta(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -182,8 +166,9 @@ void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) {
|
|||||||
stack_frame_entry_ = new Module::StackFrameEntry;
|
stack_frame_entry_ = new Module::StackFrameEntry;
|
||||||
stack_frame_entry_->address = addr;
|
stack_frame_entry_->address = addr;
|
||||||
stack_frame_entry_->size = size;
|
stack_frame_entry_->size = size;
|
||||||
stack_frame_entry_->initial_rules[ToUniqueString(kCFA)] = Module::Expr("sp");
|
Module::Expr sp_expr = Module::Expr(ustr__sp(), 0, false); // "sp"
|
||||||
vsp_ = "sp";
|
stack_frame_entry_->initial_rules[ustr__ZDcfa()] = sp_expr; // ".cfa"
|
||||||
|
vsp_ = sp_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) {
|
int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) {
|
||||||
@ -196,7 +181,7 @@ void ARMExToModule::DeleteStackFrame() {
|
|||||||
|
|
||||||
void ARMExToModule::SubmitStackFrame() {
|
void ARMExToModule::SubmitStackFrame() {
|
||||||
// return address always winds up in pc
|
// 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()];
|
= stack_frame_entry_->initial_rules[ustr__pc()];
|
||||||
// the final value of vsp is the new value of sp
|
// the final value of vsp is the new value of sp
|
||||||
stack_frame_entry_->initial_rules[ustr__sp()] = vsp_;
|
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
|
ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX
|
||||||
};
|
};
|
||||||
|
|
||||||
const string kRA = ".ra";
|
|
||||||
const string kCFA = ".cfa";
|
|
||||||
|
|
||||||
static const char* const regnames[] = {
|
static const char* const regnames[] = {
|
||||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||||
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
|
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
|
||||||
@ -118,10 +115,10 @@ class ARMExToModule {
|
|||||||
private:
|
private:
|
||||||
Module* module_;
|
Module* module_;
|
||||||
Module::StackFrameEntry* stack_frame_entry_;
|
Module::StackFrameEntry* stack_frame_entry_;
|
||||||
string vsp_;
|
Module::Expr vsp_;
|
||||||
int TranslateCmd(const struct extab_data* edata,
|
int TranslateCmd(const struct extab_data* edata,
|
||||||
Module::StackFrameEntry* entry,
|
Module::StackFrameEntry* entry,
|
||||||
string& vsp);
|
Module::Expr& vsp);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace arm_ex_to_module
|
} // namespace arm_ex_to_module
|
||||||
|
@ -44,6 +44,10 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "common/symbol_data.h"
|
#include "common/symbol_data.h"
|
||||||
#include "common/using_std_string.h"
|
#include "common/using_std_string.h"
|
||||||
#include "common/unique_string.h"
|
#include "common/unique_string.h"
|
||||||
@ -166,12 +170,27 @@ class Module {
|
|||||||
how_ = kExprInvalid;
|
how_ = kExprInvalid;
|
||||||
}
|
}
|
||||||
bool isExprInvalid() const { return how_ == kExprInvalid; }
|
bool isExprInvalid() const { return how_ == kExprInvalid; }
|
||||||
bool isExprPostfix() const { return how_ == kExprPostfix; }
|
|
||||||
|
|
||||||
// Return the postfix expression string. This is only
|
// Return the postfix expression string, either directly,
|
||||||
// meaningful on Exprs for which isExprPostfix returns true.
|
// if this is a postfix expression, or by synthesising it
|
||||||
// In all other cases it returns an empty string.
|
// for a simple expression.
|
||||||
string getExprPostfix() const { return postfix_; }
|
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 {
|
bool operator==(const Expr& other) const {
|
||||||
return how_ == other.how_ &&
|
return how_ == other.how_ &&
|
||||||
@ -180,6 +199,59 @@ class Module {
|
|||||||
postfix_ == other.postfix_;
|
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.
|
// The identifier that gives the starting value for simple expressions.
|
||||||
const UniqueString* ident_;
|
const UniqueString* ident_;
|
||||||
// The offset to add for simple expressions.
|
// The offset to add for simple expressions.
|
||||||
|
Loading…
Reference in New Issue
Block a user