Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1283008 > unrolled thread
| Started by | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| First post | 2015-12-03 13:50 +0100 |
| Last post | 2015-12-03 13:50 +0100 |
| Articles | 9 — 1 participant |
Back to article view | Back to linux.kernel
[RFC 00/17] ARC Dwarf unwinder improvements Vineet Gupta <Vineet.Gupta1@synopsys.com> - 2015-12-03 13:50 +0100
[PATCH 11/17] ARC: dw2 unwind: Elide REG_INVALID check Vineet Gupta <Vineet.Gupta1@synopsys.com> - 2015-12-03 13:50 +0100
[PATCH 13/17] ARC: dw2 unwind: Assume all regs to be unsigned long Vineet Gupta <Vineet.Gupta1@synopsys.com> - 2015-12-03 13:50 +0100
[PATCH 06/17] ARC: dw2 unwind: Don't verify Main FDE Table size everytime Vineet Gupta <Vineet.Gupta1@synopsys.com> - 2015-12-03 13:50 +0100
[PATCH 05/17] ARC: dw2 unwind: Better printing Vineet Gupta <Vineet.Gupta1@synopsys.com> - 2015-12-03 13:50 +0100
[PATCH 01/17] ARC: dw2 unwind: Elide generation of const propagated clones Vineet Gupta <Vineet.Gupta1@synopsys.com> - 2015-12-03 13:50 +0100
[PATCH 03/17] ARC: dw2 unwind: Remove handling of for signal frame Vineet Gupta <Vineet.Gupta1@synopsys.com> - 2015-12-03 13:50 +0100
[PATCH 10/17] ARC: dw2 unwind: CIE parsing/validation done only once at startup Vineet Gupta <Vineet.Gupta1@synopsys.com> - 2015-12-03 13:50 +0100
[PATCH 08/17] ARC: dw2 unwind: Don't verify FDE lookup table metadata Vineet Gupta <Vineet.Gupta1@synopsys.com> - 2015-12-03 13:50 +0100
| From | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| Date | 2015-12-03 13:50 +0100 |
| Subject | [RFC 00/17] ARC Dwarf unwinder improvements |
| Message-ID | <qBBuF-53y-3@gated-at.bofh.it> |
Hi guys, In light of perf -g stalling (as unwinder was taking ~3million cycles for non existent entries), I've revamped the dwarf unwinder. There are some optim tweaks and much of it is "De-generalization" for things which we can safely assume on ARC. Crude Instrumentation shows following improvements per unwinder call: - Avg time come down from ~4650 cycles to ~2794 cycles (+40%) - Max time come down 9793 cycles to 5987 cycles This is on a SMP FPGA config @ 75 MHz It seems much of time (65%) is taken for binary lookup thru ~12k FDE entries, roughly 13 lookups, each likely a dcache miss. git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc # topic-unwinder-rework-4-instrument -Vineet Vineet Gupta (17): ARC: dw2 unwind: Elide generation of const propagated clones ARC: dw2 unwind: remove unused cruft ARC: dw2 unwind: Remove handling of for signal frame ARC: dw2 unwind: Remove FP based unwinding ARC: dw2 unwind: Better printing ARC: dw2 unwind: Don't verify Main FDE Table size everytime ARC: dw2 unwind: Refactor the FDE lookup table (eh_frame_header) code ARC: dw2 unwind: Don't verify FDE lookup table metadata ARC: dw2 unwind: Use striaght forward code to implement binary lookup ARC: dw2 unwind: CIE parsing/validation done only once at startup ARC: dw2 unwind: Elide REG_INVALID check ARC: dw2 unwind: Elide a loop if DW_CFA_register not present ARC: dw2 unwind: Assume all regs to be unsigned long ARC: dw2 unwind: No need for __get_user ARC: dw2 unwind: Single exit point for instrumentation ARC: dw2 unwind: skip regs not updated xxx: instrument arch/arc/include/asm/unwind.h | 47 +-- arch/arc/kernel/Makefile | 1 + arch/arc/kernel/unwind.c | 806 ++++++++++++++++-------------------------- 3 files changed, 313 insertions(+), 541 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| Date | 2015-12-03 13:50 +0100 |
| Subject | [PATCH 11/17] ARC: dw2 unwind: Elide REG_INVALID check |
| Message-ID | <qBBuH-53y-39@gated-at.bofh.it> |
| In reply to | #1283008 |
REG_INVALID checks if reg_info[*].width is zero, which is compile time
contant set to NON zero. No point in checking it.
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
---
arch/arc/kernel/unwind.c | 20 ++------------------
1 file changed, 2 insertions(+), 18 deletions(-)
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index f2a486d9dac2..b1a520afcbcb 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -48,10 +48,6 @@ static const struct {
unsigned width:BITS_PER_LONG / 2;
} reg_info[] = { UNW_REGISTER_INFO };
-#ifndef REG_INVALID
-#define REG_INVALID(r) (reg_info[r].width == 0)
-#endif
-
#define DW_CFA_nop 0x00
#define DW_CFA_set_loc 0x01
#define DW_CFA_advance_loc1 0x02
@@ -868,9 +864,7 @@ static int cie_validate(const u32 *cie, struct cie *t_cie)
t_cie->fde_pointer_type = ptrType;
if (ptr > end
- || retAddrReg >= ARRAY_SIZE(reg_info)
- || REG_INVALID(retAddrReg)
- || reg_info[retAddrReg].width != sizeof(unsigned long))
+ || retAddrReg >= ARRAY_SIZE(reg_info))
return 0;
unw_debug("\nDwarf Unwinder setup: CIE Info:\n");
@@ -1017,19 +1011,11 @@ int arc_unwind(struct unwind_frame_info *frame)
state.cfa.reg, state.cfa.offs, cfa);
for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
- if (REG_INVALID(i)) {
- if (state.regs[i].where == Nowhere)
- continue;
- return -EIO;
- }
switch (state.regs[i].where) {
default:
break;
case Register:
- if (state.regs[i].value >= ARRAY_SIZE(reg_info)
- || REG_INVALID(state.regs[i].value)
- || reg_info[i].width >
- reg_info[state.regs[i].value].width)
+ if (state.regs[i].value >= ARRAY_SIZE(reg_info))
return -EIO;
switch (reg_info[state.regs[i].value].width) {
case sizeof(u8):
@@ -1061,8 +1047,6 @@ int arc_unwind(struct unwind_frame_info *frame)
fptr = (unsigned long *)(&frame->regs);
for (i = 0; i < ARRAY_SIZE(state.regs); ++i, fptr++) {
- if (REG_INVALID(i))
- continue;
switch (state.regs[i].where) {
case Nowhere:
if (reg_info[i].width != sizeof(UNW_SP(frame))
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| Date | 2015-12-03 13:50 +0100 |
| Subject | [PATCH 13/17] ARC: dw2 unwind: Assume all regs to be unsigned long |
| Message-ID | <qBBuH-53y-45@gated-at.bofh.it> |
| In reply to | #1283008 |
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
---
arch/arc/include/asm/unwind.h | 3 +-
arch/arc/kernel/unwind.c | 74 +++----------------------------------------
2 files changed, 6 insertions(+), 71 deletions(-)
diff --git a/arch/arc/include/asm/unwind.h b/arch/arc/include/asm/unwind.h
index 03ace2cc8bc5..a1dbcf6cb361 100644
--- a/arch/arc/include/asm/unwind.h
+++ b/arch/arc/include/asm/unwind.h
@@ -66,8 +66,7 @@ struct unwind_frame_info {
BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
% FIELD_SIZEOF(struct unwind_frame_info, f)) \
+ offsetof(struct unwind_frame_info, f) \
- / FIELD_SIZEOF(struct unwind_frame_info, f), \
- FIELD_SIZEOF(struct unwind_frame_info, f) \
+ / FIELD_SIZEOF(struct unwind_frame_info, f) \
}
#define PTREGS_INFO(f) EXTRA_INFO(regs.f)
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 6eb377c102c6..b2053b55d076 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -45,7 +45,6 @@ do { \
static const struct {
unsigned offs:BITS_PER_LONG / 2;
- unsigned width:BITS_PER_LONG / 2;
} reg_info[] = { UNW_REGISTER_INFO };
#define DW_CFA_nop 0x00
@@ -996,7 +995,6 @@ int arc_unwind(struct unwind_frame_info *frame)
|| state.loc > endLoc
/* || state.regs[retAddrReg].where == Nowhere */
|| state.cfa.reg >= ARRAY_SIZE(reg_info)
- || reg_info[state.cfa.reg].width != sizeof(unsigned long)
|| state.cfa.offs % sizeof(unsigned long))
return -EIO;
@@ -1025,28 +1023,8 @@ int arc_unwind(struct unwind_frame_info *frame)
if (state.regs[i].where == Register) {
if (state.regs[i].value >= ARRAY_SIZE(reg_info))
return -EIO;
- switch (reg_info[state.regs[i].value].width) {
- case sizeof(u8):
- state.regs[i].value =
- FRAME_REG(state.regs[i].value, const u8);
- break;
- case sizeof(u16):
- state.regs[i].value =
- FRAME_REG(state.regs[i].value, const u16);
- break;
- case sizeof(u32):
- state.regs[i].value =
- FRAME_REG(state.regs[i].value, const u32);
- break;
-#ifdef CONFIG_64BIT
- case sizeof(u64):
- state.regs[i].value =
- FRAME_REG(state.regs[i].value, const u64);
- break;
-#endif
- default:
- return -EIO;
- }
+
+ state.regs[i].value = FRAME_REG(state.regs[i].value, unsigned long);
}
}
@@ -1056,35 +1034,15 @@ int arc_unwind(struct unwind_frame_info *frame)
switch (state.regs[i].where) {
case Nowhere:
- if (reg_info[i].width != sizeof(UNW_SP(frame))
- || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
+ if (&FRAME_REG(i, __typeof__(UNW_SP(frame)))
!= &UNW_SP(frame))
continue;
UNW_SP(frame) = cfa;
break;
case Register:
- switch (reg_info[i].width) {
- case sizeof(u8):
- FRAME_REG(i, u8) = state.regs[i].value;
- break;
- case sizeof(u16):
- FRAME_REG(i, u16) = state.regs[i].value;
- break;
- case sizeof(u32):
- FRAME_REG(i, u32) = state.regs[i].value;
- break;
-#ifdef CONFIG_64BIT
- case sizeof(u64):
- FRAME_REG(i, u64) = state.regs[i].value;
- break;
-#endif
- default:
- return -EIO;
- }
+ FRAME_REG(i, unsigned long) = state.regs[i].value;
break;
case Value:
- if (reg_info[i].width != sizeof(unsigned long))
- return -EIO;
FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
* state.dataAlign;
break;
@@ -1098,29 +1056,7 @@ int arc_unwind(struct unwind_frame_info *frame)
|| addr + sizeof(unsigned long) > endLoc)
return -EIO;
- switch (reg_info[i].width) {
- case sizeof(u8):
- __get_user(FRAME_REG(i, u8),
- (u8 __user *)addr);
- break;
- case sizeof(u16):
- __get_user(FRAME_REG(i, u16),
- (u16 __user *)addr);
- break;
- case sizeof(u32):
- __get_user(FRAME_REG(i, u32),
- (u32 __user *)addr);
- break;
-#ifdef CONFIG_64BIT
- case sizeof(u64):
- __get_user(FRAME_REG(i, u64),
- (u64 __user *)addr);
- break;
-#endif
- default:
- return -EIO;
- }
-
+ __get_user(FRAME_REG(i, unsigned long), (unsigned long __user *)addr);
break;
}
unw_debug("r%d: 0x%lx\n", i, *fptr);
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| Date | 2015-12-03 13:50 +0100 |
| Subject | [PATCH 06/17] ARC: dw2 unwind: Don't verify Main FDE Table size everytime |
| Message-ID | <qBBuI-53y-51@gated-at.bofh.it> |
| In reply to | #1283008 |
This is already done at boot time in setup_unwind_table()
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
---
arch/arc/kernel/unwind.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 2bb3c1c048bb..f57a0d50185c 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -892,8 +892,7 @@ int arc_unwind(struct unwind_frame_info *frame)
#endif
table = find_table(pc);
- if (table != NULL
- && !(table->size & (sizeof(*fde) - 1))) {
+ if (table != NULL) {
const u8 *hdr = table->header;
unsigned long tableSize;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| Date | 2015-12-03 13:50 +0100 |
| Subject | [PATCH 05/17] ARC: dw2 unwind: Better printing |
| Message-ID | <qBBuI-53y-47@gated-at.bofh.it> |
| In reply to | #1283008 |
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
---
arch/arc/kernel/unwind.c | 123 +++++++++++++++++------------------------------
1 file changed, 45 insertions(+), 78 deletions(-)
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 0993a81e112b..2bb3c1c048bb 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -629,40 +629,40 @@ static signed fde_pointer_type(const u32 *cie)
return DW_EH_PE_native | DW_EH_PE_abs;
}
-static int advance_loc(unsigned long delta, struct unwind_state *state)
+static int advance_loc(unsigned long delta, struct unwind_state *state, char *str)
{
state->loc += delta * state->codeAlign;
/* FIXME_Rajesh: Probably we are defining for the initial range as well;
return delta > 0;
*/
- unw_debug("delta %3lu => loc 0x%lx: ", delta, state->loc);
+ unw_debug("%sdelta %3lu => loc 0x%lx\n", str, delta, state->loc);
return 1;
}
static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value,
- struct unwind_state *state)
+ struct unwind_state *state, char *str)
{
if (reg < ARRAY_SIZE(state->regs)) {
state->regs[reg].where = where;
state->regs[reg].value = value;
#ifdef UNWIND_DEBUG
- unw_debug("r%lu: ", reg);
switch (where) {
case Nowhere:
- unw_debug("s ");
+ unw_debug("%sr%lu: s \n", str, reg);
break;
case Memory:
- unw_debug("c(%lu) ", value);
+ unw_debug("%sr%lu: c(%lu) \n", str, reg, value);
break;
case Register:
- unw_debug("r(%lu) ", value);
+ unw_debug("%sr%lu: r(%lu) \n", str, reg, value);
break;
case Value:
- unw_debug("v(%lu) ", value);
+ unw_debug("%sr%lu: v(%lu) \n", str, reg, value);
break;
default:
+ unw_debug("%sr%lu: ???\n", str, reg);
break;
}
#endif
@@ -689,6 +689,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
return result;
}
for (ptr.p8 = start; result && ptr.p8 < end;) {
+ char *str = NULL;
switch (*ptr.p8 >> 6) {
uleb128_t value;
@@ -707,59 +708,52 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
unw_debug("cfa_set_loc: 0x%lx ", state->loc);
break;
case DW_CFA_advance_loc1:
- unw_debug("\ncfa advance loc1:");
+ str = "cfa advance loc1:";
result = ptr.p8 < end
- && advance_loc(*ptr.p8++, state);
+ && advance_loc(*ptr.p8++, state, str);
break;
case DW_CFA_advance_loc2:
value = *ptr.p8++;
value += *ptr.p8++ << 8;
- unw_debug("\ncfa advance loc2:");
+ str = "cfa advance loc2:";
result = ptr.p8 <= end + 2
- /* && advance_loc(*ptr.p16++, state); */
- && advance_loc(value, state);
+ /* && advance_loc(*ptr.p16++, state, str); */
+ && advance_loc(value, state, str);
break;
case DW_CFA_advance_loc4:
- unw_debug("\ncfa advance loc4:");
+ str = "cfa advance loc4:";
result = ptr.p8 <= end + 4
- && advance_loc(*ptr.p32++, state);
+ && advance_loc(*ptr.p32++, state, str);
break;
case DW_CFA_offset_extended:
value = get_uleb128(&ptr.p8, end);
- unw_debug("cfa_offset_extended: ");
- set_rule(value, Memory,
- get_uleb128(&ptr.p8, end), state);
+ str = "cfa_offset_extended: ";
+ set_rule(value, Memory, get_uleb128(&ptr.p8, end), state, str);
break;
case DW_CFA_val_offset:
value = get_uleb128(&ptr.p8, end);
- set_rule(value, Value,
- get_uleb128(&ptr.p8, end), state);
+ set_rule(value, Value, get_uleb128(&ptr.p8, end), state, str);
break;
case DW_CFA_offset_extended_sf:
value = get_uleb128(&ptr.p8, end);
- set_rule(value, Memory,
- get_sleb128(&ptr.p8, end), state);
+ set_rule(value, Memory, get_sleb128(&ptr.p8, end), state, str);
break;
case DW_CFA_val_offset_sf:
value = get_uleb128(&ptr.p8, end);
- set_rule(value, Value,
- get_sleb128(&ptr.p8, end), state);
+ set_rule(value, Value, get_sleb128(&ptr.p8, end), state, str);
break;
case DW_CFA_restore_extended:
- unw_debug("cfa_restore_extended: ");
+ str = "cfa_restore_extended: ";
case DW_CFA_undefined:
- unw_debug("cfa_undefined: ");
+ str = "cfa_undefined: ";
case DW_CFA_same_value:
- unw_debug("cfa_same_value: ");
- set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0,
- state);
+ str = "cfa_same_value: ";
+ set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state, str);
break;
case DW_CFA_register:
- unw_debug("cfa_register: ");
+ str = "cfa_register: ";
value = get_uleb128(&ptr.p8, end);
- set_rule(value,
- Register,
- get_uleb128(&ptr.p8, end), state);
+ set_rule(value, Register, get_uleb128(&ptr.p8, end), state, str);
break;
case DW_CFA_remember_state:
unw_debug("cfa_remember_state: ");
@@ -798,8 +792,8 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
/*nobreak*/
case DW_CFA_def_cfa_offset:
state->cfa.offs = get_uleb128(&ptr.p8, end);
- unw_debug("cfa_def_cfa_offset: 0x%lx ",
- state->cfa.offs);
+ unw_debug("cfa_def_cfa_offset: r%ld: %ld\n",
+ state->cfa.reg, state->cfa.offs);
break;
case DW_CFA_def_cfa_sf:
state->cfa.reg = get_uleb128(&ptr.p8, end);
@@ -824,7 +818,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
Memory,
(uleb128_t) 0 - get_uleb128(&ptr.p8,
end),
- state);
+ state, str);
break;
case DW_CFA_GNU_window_save:
default:
@@ -834,18 +828,17 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
}
break;
case 1:
- unw_debug("\ncfa_adv_loc: ");
- result = advance_loc(*ptr.p8++ & 0x3f, state);
+ str = "cfa_adv_loc: ";
+ result = advance_loc(*ptr.p8++ & 0x3f, state, str);
break;
case 2:
- unw_debug("cfa_offset: ");
+ str = "cfa_offset: ";
value = *ptr.p8++ & 0x3f;
- set_rule(value, Memory, get_uleb128(&ptr.p8, end),
- state);
+ set_rule(value, Memory, get_uleb128(&ptr.p8, end), state, str);
break;
case 3:
- unw_debug("cfa_restore: ");
- set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
+ str = "cfa_restore: ";
+ set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state, str);
break;
}
@@ -879,15 +872,16 @@ int arc_unwind(struct unwind_frame_info *frame)
unsigned long *fptr;
unsigned long addr;
- unw_debug("\n\nUNWIND FRAME:\n");
- unw_debug("PC: 0x%lx BLINK: 0x%lx, SP: 0x%lx, FP: 0x%x\n",
- UNW_PC(frame), UNW_BLINK(frame), UNW_SP(frame),
- UNW_FP(frame));
+ unw_debug("\nUNWIND FRAME: -------------------------------------\n");
+ unw_debug("PC\t\t: 0x%lx %pS\nr31 [BLINK]\t: 0x%lx %pS\nr28 [SP]\t: 0x%lx\nr27 [FP]\t: 0x%lx\n",
+ UNW_PC(frame), (void *)UNW_PC(frame),
+ UNW_BLINK(frame), (void *)UNW_BLINK(frame),
+ UNW_SP(frame), UNW_FP(frame));
if (UNW_PC(frame) == 0)
return -EINVAL;
-#ifdef UNWIND_DEBUG
+#ifdef UNWIND_DEBUG0
{
unsigned long *sptr = (unsigned long *)UNW_SP(frame);
unw_debug("\nStack Dump:\n");
@@ -1063,7 +1057,7 @@ int arc_unwind(struct unwind_frame_info *frame)
state.org = startLoc;
memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
- unw_debug("\nProcess instructions\n");
+ unw_debug("\nProcess CFA\n");
/* process instructions
* For ARC, we optimize by having blink(retAddrReg) with
@@ -1078,33 +1072,6 @@ int arc_unwind(struct unwind_frame_info *frame)
|| state.cfa.offs % sizeof(unsigned long))
return -EIO;
-#ifdef UNWIND_DEBUG
- unw_debug("\n");
-
- unw_debug("\nRegister State Based on the rules parsed from FDE:\n");
- for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
-
- if (REG_INVALID(i))
- continue;
-
- switch (state.regs[i].where) {
- case Nowhere:
- break;
- case Memory:
- unw_debug(" r%d: c(%lu),", i, state.regs[i].value);
- break;
- case Register:
- unw_debug(" r%d: r(%lu),", i, state.regs[i].value);
- break;
- case Value:
- unw_debug(" r%d: v(%lu),", i, state.regs[i].value);
- break;
- }
- }
-
- unw_debug("\n");
-#endif
-
cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
startLoc = min_t(unsigned long, UNW_SP(frame), cfa);
endLoc = max_t(unsigned long, UNW_SP(frame), cfa);
@@ -1113,7 +1080,7 @@ int arc_unwind(struct unwind_frame_info *frame)
endLoc = max(STACK_LIMIT(cfa), cfa);
}
- unw_debug("\nCFA reg: 0x%lx, offset: 0x%lx => 0x%lx\n",
+ unw_debug("\nCFA reg: r%ld, off: %ld => [SP] 0x%lx\n",
state.cfa.reg, state.cfa.offs, cfa);
for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
@@ -1232,7 +1199,7 @@ int arc_unwind(struct unwind_frame_info *frame)
break;
}
- unw_debug("r%d: 0x%lx ", i, *fptr);
+ unw_debug("r%d: 0x%lx\n", i, *fptr);
}
return 0;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| Date | 2015-12-03 13:50 +0100 |
| Subject | [PATCH 01/17] ARC: dw2 unwind: Elide generation of const propagated clones |
| Message-ID | <qBBuI-53y-55@gated-at.bofh.it> |
| In reply to | #1283008 |
arc_unwind_core() is entry point into the actual dwarf unwinder and it gets called by various kernel APIs which provide the unwinding context (e.g. current task vs. a specific task, current pt_regs vs. some other crash context's pt_regs...) Currently multiple const propagated clones of arc_unwind_core() are generated, which seems superfluous. The only performance critical call is for perf callgrap unwinding, which being in a different compilation unit, uses ths vanilla, non cp version anyways. So prevent the clone functions generation bloat-o-meter report | add/remove: 0/1 grow/shrink: 4/0 up/down: 40/-1152 (-1112) | function old new delta | save_stack_trace 4 16 +12 | save_stack_trace_tsk 4 14 +10 | get_wchan 4 14 +10 | show_stacktrace 40 48 +8 | arc_unwind_core.constprop 1152 - -1152 Signed-off-by: Vineet Gupta <vgupta@synopsys.com> --- arch/arc/kernel/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index e7f3625a19b5..f90e5fd6d5c8 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile @@ -7,6 +7,7 @@ # Pass UTS_MACHINE for user_regset definition CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' +CFLAGS_stacktrace.o += -fno-ipa-cp-clone obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o clk.o -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| Date | 2015-12-03 13:50 +0100 |
| Subject | [PATCH 03/17] ARC: dw2 unwind: Remove handling of for signal frame |
| Message-ID | <qBBuI-53y-57@gated-at.bofh.it> |
| In reply to | #1283008 |
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
---
arch/arc/include/asm/unwind.h | 3 ---
arch/arc/kernel/unwind.c | 11 ++---------
2 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/arch/arc/include/asm/unwind.h b/arch/arc/include/asm/unwind.h
index 0e7f48e2686a..559ef55abce1 100644
--- a/arch/arc/include/asm/unwind.h
+++ b/arch/arc/include/asm/unwind.h
@@ -116,9 +116,6 @@ struct unwind_frame_info {
PTREGS_INFO(r31), \
PTREGS_INFO(r63)
-#define UNW_DEFAULT_RA(raItem, dataAlign) \
- ((raItem).where == Memory && !((raItem).value * (dataAlign) + 4))
-
extern int arc_unwind(struct unwind_frame_info *frame);
extern void arc_unwind_init(void);
extern void arc_unwind_setup(void);
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 44983b4d9e78..2f4a67f5a863 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -869,7 +869,7 @@ int arc_unwind(struct unwind_frame_info *frame)
#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
const u32 *fde = NULL, *cie = NULL;
const u8 *ptr = NULL, *end = NULL;
- unsigned long pc = UNW_PC(frame) - frame->call_frame;
+ unsigned long pc = UNW_PC(frame);
unsigned long startLoc = 0, endLoc = 0, cfa;
unsigned i;
signed ptrType = -1;
@@ -988,7 +988,6 @@ int arc_unwind(struct unwind_frame_info *frame)
state.cieEnd = ptr; /* keep here temporarily */
ptr = (const u8 *)(cie + 2);
end = (const u8 *)(cie + 1) + *cie;
- frame->call_frame = 1;
if ((state.version = *ptr) != 1)
cie = NULL; /* unsupported version */
else if (*++ptr) {
@@ -1003,7 +1002,7 @@ int arc_unwind(struct unwind_frame_info *frame)
case 'R':
continue;
case 'S':
- frame->call_frame = 0;
+ /* signal frame not handled */
continue;
default:
break;
@@ -1147,12 +1146,6 @@ int arc_unwind(struct unwind_frame_info *frame)
unw_debug("\n");
#endif
- /* update frame */
-#ifndef CONFIG_AS_CFI_SIGNAL_FRAME
- if (frame->call_frame
- && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
- frame->call_frame = 0;
-#endif
cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
startLoc = min_t(unsigned long, UNW_SP(frame), cfa);
endLoc = max_t(unsigned long, UNW_SP(frame), cfa);
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| Date | 2015-12-03 13:50 +0100 |
| Subject | [PATCH 10/17] ARC: dw2 unwind: CIE parsing/validation done only once at startup |
| Message-ID | <qBBuI-53y-65@gated-at.bofh.it> |
| In reply to | #1283008 |
There is only 1 CIE per unwind table and applicable to all FDEs, so
validate it only once. No need to do validate it when prcoessing the FDE
itself.
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
---
arch/arc/kernel/unwind.c | 336 +++++++++++++++++++++--------------------------
1 file changed, 153 insertions(+), 183 deletions(-)
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 6a09ffa0b697..f2a486d9dac2 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -122,6 +122,13 @@ static struct unwind_table {
} core, init;
const void *address;
unsigned long size;
+ struct cie {
+ unsigned version:8, aug:8, pad:16;
+ uleb128_t codeAlign;
+ sleb128_t dataAlign;
+ int fde_pointer_type;
+ uleb128_t retAddrReg;
+ } cie;
struct eh_frame_header *header;
unsigned long hdrsz;
struct unwind_table *link;
@@ -140,20 +147,18 @@ struct unwind_item {
struct unwind_state {
uleb128_t loc, org;
- const u8 *cieStart, *cieEnd;
uleb128_t codeAlign;
sleb128_t dataAlign;
struct cfa {
uleb128_t reg, offs;
} cfa;
struct unwind_item regs[ARRAY_SIZE(reg_info)];
- unsigned stackDepth:8;
- unsigned version:8;
+ unsigned stackDepth;
const u8 *label;
const u8 *stack[MAX_STACK_DEPTH];
};
-static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
+static struct cfa seed_CFA = { ARRAY_SIZE(reg_info), 1 };
static struct unwind_table *find_table(unsigned long pc)
{
@@ -214,7 +219,7 @@ void __init arc_unwind_init(void)
static const u32 bad_cie, not_fde;
static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *);
-static signed fde_pointer_type(const u32 *cie);
+static int cie_validate(const u32 *cie, struct cie *t_cie);
static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2)
{
@@ -245,7 +250,10 @@ static void __init setup_unwind_table(struct unwind_table *table,
unsigned long tableSize = table->size, hdrSize;
unsigned n;
const u32 *fde;
+ int ptrType;
struct eh_frame_header *header;
+ int n_cie = 0, len = 0;
+ char cie_orig[64];
if (table->header)
return;
@@ -261,19 +269,26 @@ static void __init setup_unwind_table(struct unwind_table *table,
tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
const u32 *cie = cie_for_fde(fde, table);
- signed ptrType;
- if (cie == ¬_fde)
+ if (cie == ¬_fde) {
+ if (n_cie++ == 0) {
+ len = cie_validate(&fde[0], &table->cie);
+ if (!len)
+ panic("Invalid CIE\n");
+
+ memcpy(&cie_orig[0], &fde[0], len);
+ } else {
+ if (memcmp(&fde[0], &cie_orig[0], len) != 0)
+ panic("Multiple CIEs not same\n");
+ }
continue;
+ }
if (cie == NULL || cie == &bad_cie)
return;
- ptrType = fde_pointer_type(cie);
- if (ptrType < 0)
- return;
ptr = (const u8 *)(fde + 2);
if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde,
- ptrType)) {
+ table->cie.fde_pointer_type)) {
/* FIXME_Rajesh We have 4 instances of null addresses
* instead of the initial loc addr
* return;
@@ -303,19 +318,17 @@ static void __init setup_unwind_table(struct unwind_table *table,
BUILD_BUG_ON(offsetof(typeof(*header), table)
% __alignof(typeof(*header->table)));
+
+ ptrType = table->cie.fde_pointer_type;
for (fde = table->address, tableSize = table->size, n = 0;
tableSize;
tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
- /* const u32 *cie = fde + 1 - fde[1] / sizeof(*fde); */
- const u32 *cie = (const u32 *)(fde[1]);
-
if (fde[1] == 0xffffffff)
continue; /* this is a CIE */
ptr = (const u8 *)(fde + 2);
header->table[n].start = read_pointer(&ptr,
- (const u8 *)(fde + 1) +
- *fde,
- fde_pointer_type(cie));
+ (const u8 *)(fde + 1) + *fde,
+ ptrType);
header->table[n].fde = (unsigned long)fde;
++n;
}
@@ -572,65 +585,6 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end,
return value;
}
-static signed fde_pointer_type(const u32 *cie)
-{
- const u8 *ptr = (const u8 *)(cie + 2);
- unsigned version = *ptr;
-
- if (version != 1)
- return -1; /* unsupported */
-
- if (*++ptr) {
- const char *aug;
- const u8 *end = (const u8 *)(cie + 1) + *cie;
- uleb128_t len;
-
- /* check if augmentation size is first (and thus present) */
- if (*ptr != 'z')
- return -1;
-
- /* check if augmentation string is nul-terminated */
- aug = (const void *)ptr;
- ptr = memchr(aug, 0, end - ptr);
- if (ptr == NULL)
- return -1;
-
- ++ptr; /* skip terminator */
- get_uleb128(&ptr, end); /* skip code alignment */
- get_sleb128(&ptr, end); /* skip data alignment */
- /* skip return address column */
- version <= 1 ? (void) ++ptr : (void)get_uleb128(&ptr, end);
- len = get_uleb128(&ptr, end); /* augmentation length */
-
- if (ptr + len < ptr || ptr + len > end)
- return -1;
-
- end = ptr + len;
- while (*++aug) {
- if (ptr >= end)
- return -1;
- switch (*aug) {
- case 'L':
- ++ptr;
- break;
- case 'P':{
- signed ptrType = *ptr++;
-
- if (!read_pointer(&ptr, end, ptrType)
- || ptr > end)
- return -1;
- }
- break;
- case 'R':
- return *ptr;
- default:
- return -1;
- }
- }
- }
- return DW_EH_PE_native | DW_EH_PE_abs;
-}
-
static int advance_loc(unsigned long delta, struct unwind_state *state, char *str)
{
state->loc += delta * state->codeAlign;
@@ -682,14 +636,6 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
int result = 1;
u8 opcode;
- if (start != state->cieStart) {
- state->loc = state->org;
- result =
- processCFI(state->cieStart, state->cieEnd, 0, ptrType,
- state);
- if (targetLoc == 0 && state->label == NULL)
- return result;
- }
for (ptr.p8 = start; result && ptr.p8 < end;) {
char *str = NULL;
switch (*ptr.p8 >> 6) {
@@ -775,7 +721,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
state->label =
state->stack[state->stackDepth - 1];
- memcpy(&state->cfa, &badCFA,
+ memcpy(&state->cfa, &seed_CFA,
sizeof(state->cfa));
memset(state->regs, 0,
sizeof(state->regs));
@@ -857,12 +803,102 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
targetLoc < state->loc && */ state->label == NULL));
}
+/*
+ * Returns length of CIE (0 if invalid)
+ */
+static int cie_validate(const u32 *cie, struct cie *t_cie)
+{
+ const u8 *ptr = NULL, *end = NULL;
+ u8 version;
+ uleb128_t retAddrReg = 0;
+ int ptrType = DW_EH_PE_native | DW_EH_PE_abs;
+ struct unwind_state state;
+
+ if (cie == NULL)
+ return 0;
+
+ ptr = (const u8 *)(cie + 2);
+ end = (const u8 *)(cie + 1) + *cie;
+ if ((version = *ptr) != 1)
+ return 0; /* unsupported version */
+
+ t_cie->version = version;
+
+ if (*++ptr) {
+ /* check if augmentation size is first (thus present) */
+ if (*ptr == 'z') {
+ t_cie->aug = 1;
+ while (++ptr < end && *ptr) {
+ switch (*ptr) {
+ /* chk for ignorable or already handled
+ * nul-terminated augmentation string */
+ case 'L':
+ case 'P':
+ case 'R':
+ continue;
+ case 'S': /* signal frame */
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ if (ptr >= end || *ptr)
+ return 0;
+ }
+ ++ptr; /* skip terminator */
+
+ t_cie->codeAlign = get_uleb128(&ptr, end);
+ t_cie->dataAlign = get_sleb128(&ptr, end);
+
+ if (t_cie->codeAlign == 0 || t_cie->dataAlign == 0 || ptr >= end)
+ return 0;
+
+ retAddrReg = version <= 1 ? *ptr++ : get_uleb128(&ptr, end);
+ t_cie->retAddrReg = retAddrReg;
+
+ /* skip augmentation data */
+ if (((const char *)(cie + 2))[1] == 'z') {
+ get_uleb128(&ptr, end); /* augSize */
+
+ if (*ptr++ == 'R') /* FDE pointer encoding type */
+ ptrType = *ptr;
+ }
+ t_cie->fde_pointer_type = ptrType;
+
+ if (ptr > end
+ || retAddrReg >= ARRAY_SIZE(reg_info)
+ || REG_INVALID(retAddrReg)
+ || reg_info[retAddrReg].width != sizeof(unsigned long))
+ return 0;
+
+ unw_debug("\nDwarf Unwinder setup: CIE Info:\n");
+ unw_debug("code Align: %lu\n", t_cie->codeAlign);
+ unw_debug("data Align: %ld\n", t_cie->dataAlign);
+ unw_debug("Return Address register r%d\n", (int)t_cie->retAddrReg);
+ unw_debug("FDE pointer type %d\n", ptrType);
+ unw_debug("CFI Instructions for CIE:\n");
+
+ memset(&state, sizeof(state), 0);
+
+ /* CIE has rules for Default CFA */
+ if (!processCFI(ptr, end, 0, ptrType, &state)
+ || state.cfa.reg >= ARRAY_SIZE(reg_info)
+ || state.cfa.offs % sizeof(unsigned long))
+ return 0;
+
+ memcpy(&seed_CFA, &state.cfa, sizeof(state.cfa));
+
+ return end - (const u8 *)cie;
+}
+
/* Unwind to previous to frame. Returns 0 if successful, negative
* number in case of an error. */
int arc_unwind(struct unwind_frame_info *frame)
{
#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
- const u32 *fde = NULL, *cie = NULL;
+ const u32 *fde = NULL;
const u8 *ptr = NULL, *end = NULL;
unsigned long pc = UNW_PC(frame);
unsigned long startLoc = 0, endLoc = 0, cfa;
@@ -920,107 +956,41 @@ int arc_unwind(struct unwind_frame_info *frame)
else
return -EINVAL;
- if (fde != NULL) {
- cie = cie_for_fde(fde, table);
- ptr = (const u8 *)(fde + 2);
- if (cie != NULL
- && cie != &bad_cie
- && cie != ¬_fde
- && (ptrType = fde_pointer_type(cie)) >= 0
- && read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType) == startLoc) {
- if (!(ptrType & DW_EH_PE_indirect))
- ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed;
- endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
- if (pc >= endLoc) {
- fde = NULL;
- cie = NULL;
- }
- } else {
- fde = NULL;
- cie = NULL;
- }
- }
- if (cie != NULL) {
- memset(&state, 0, sizeof(state));
- state.cieEnd = ptr; /* keep here temporarily */
- ptr = (const u8 *)(cie + 2);
- end = (const u8 *)(cie + 1) + *cie;
- if ((state.version = *ptr) != 1)
- cie = NULL; /* unsupported version */
- else if (*++ptr) {
- /* check if augmentation size is first (thus present) */
- if (*ptr == 'z') {
- while (++ptr < end && *ptr) {
- switch (*ptr) {
- /* chk for ignorable or already handled
- * nul-terminated augmentation string */
- case 'L':
- case 'P':
- case 'R':
- continue;
- case 'S':
- /* signal frame not handled */
- continue;
- default:
- break;
- }
- break;
- }
- }
- if (ptr >= end || *ptr)
- cie = NULL;
- }
- ++ptr;
- }
- if (cie != NULL) {
- /* get code aligment factor */
- state.codeAlign = get_uleb128(&ptr, end);
- /* get data aligment factor */
- state.dataAlign = get_sleb128(&ptr, end);
- if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
- cie = NULL;
- else {
- retAddrReg =
- state.version <= 1 ? *ptr++ : get_uleb128(&ptr,
- end);
- unw_debug("CIE Frame Info:\n");
- unw_debug("return Address register 0x%lx\n",
- retAddrReg);
- unw_debug("data Align: %ld\n", state.dataAlign);
- unw_debug("code Align: %lu\n", state.codeAlign);
- /* skip augmentation */
- if (((const char *)(cie + 2))[1] == 'z') {
- uleb128_t augSize = get_uleb128(&ptr, end);
-
- ptr += augSize;
- }
- if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info)
- || REG_INVALID(retAddrReg)
- || reg_info[retAddrReg].width !=
- sizeof(unsigned long))
- cie = NULL;
- }
+ memset(&state, 0, sizeof(state));
+ ptr = (const u8 *)(fde + 2);
+ end = (const u8 *)(fde + 1) + *fde;
+
+ ptrType = table->cie.fde_pointer_type;
+ if (read_pointer(&ptr, end, ptrType) != startLoc)
+ return -EINVAL;
+
+ if (!(ptrType & DW_EH_PE_indirect))
+ ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed;
+
+ endLoc = startLoc + read_pointer(&ptr, end, ptrType);
+
+ /* For symbols not present, this is mostly hit (not startLoc check above) */
+ if (pc >= endLoc) {
+ unw_debug("Unwindo info missing for PC %lx: {%lx,%lx}\n",
+ pc, startLoc, endLoc);
+ return -EINVAL;
}
- if (cie != NULL) {
- state.cieStart = ptr;
- ptr = state.cieEnd;
- state.cieEnd = end;
- end = (const u8 *)(fde + 1) + *fde;
- /* skip augmentation */
- if (((const char *)(cie + 2))[1] == 'z') {
- uleb128_t augSize = get_uleb128(&ptr, end);
-
- if ((ptr += augSize) > end)
- fde = NULL;
- }
+
+ if (table->cie.aug) {
+ uleb128_t augSize = get_uleb128(&ptr, end);
+
+ if ((ptr += augSize) > end)
+ return -EINVAL;
}
- if (cie == NULL || fde == NULL)
- return -ENXIO;
- state.org = startLoc;
- memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
+ state.org = state.loc = startLoc;
+ memcpy(&state.cfa, &seed_CFA, sizeof(state.cfa));
+ state.codeAlign = table->cie.codeAlign;
+ state.dataAlign = table->cie.dataAlign;
+
+ retAddrReg = table->cie.retAddrReg;
- unw_debug("\nProcess CFA\n");
+ unw_debug("\nProcess FDE:\n");
/* process instructions
* For ARC, we optimize by having blink(retAddrReg) with
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Vineet Gupta <Vineet.Gupta1@synopsys.com> |
|---|---|
| Date | 2015-12-03 13:50 +0100 |
| Subject | [PATCH 08/17] ARC: dw2 unwind: Don't verify FDE lookup table metadata |
| Message-ID | <qBBuI-53y-67@gated-at.bofh.it> |
| In reply to | #1283008 |
FDE Lookup table (eh_frame_header or it's equivalent constructed by hand)
is already setup correctly in setup_unwind_table(). There's no point
to re-parse it's header for every unwind call
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
---
arch/arc/kernel/unwind.c | 37 ++++++++-----------------------------
1 file changed, 8 insertions(+), 29 deletions(-)
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 9f5ed6873c52..9b34038a7582 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -900,35 +900,16 @@ int arc_unwind(struct unwind_frame_info *frame)
return -EINVAL;
hdr = table->header;
+ if (hdr == NULL)
+ return -EINVAL;
- smp_rmb();
- if (hdr && hdr->version == 1) {
- switch (hdr->table_enc & DW_EH_PE_FORM) {
- case DW_EH_PE_native:
- hdrEntrySz = sizeof(unsigned long);
- break;
- case DW_EH_PE_data2:
- hdrEntrySz = 2;
- break;
- case DW_EH_PE_data4:
- hdrEntrySz = 4;
- break;
- case DW_EH_PE_data8:
- hdrEntrySz = 8;
- break;
- default:
- hdrEntrySz = 0;
- break;
- }
+ hdrEntrySz = sizeof(unsigned long);
+ BUILD_BUG_ON(hdrEntrySz != sizeof(hdr->table[0].start));
+
+ ptr = (const u8*)(hdr->table);
+ end = (const u8*)(hdr) + table->hdrsz;
+ i = hdr->fde_count;
- ptr = (const u8*)(hdr->eh_frame_ptr);
- end = (const u8*)(hdr) + table->hdrsz;
- if (hdrEntrySz
- && read_pointer(&ptr, end, hdr->eh_frame_ptr_enc) /* eh_frame_ptr */
- == (unsigned long)table->address
- && (i = read_pointer(&ptr, end, hdr->fde_count_enc)) > 0 /* fde_count */
- && i == (end - ptr) / (2 * hdrEntrySz)
- && !((end - ptr) % (2 * hdrEntrySz))) {
do {
const u8 *cur = ptr + (i / 2) * (2 * hdrEntrySz);
@@ -944,8 +925,6 @@ int arc_unwind(struct unwind_frame_info *frame)
&& (startLoc = read_pointer(&ptr, ptr + hdrEntrySz, hdr->table_enc)) != 0
&& pc >= startLoc)
fde = (void *)read_pointer(&ptr, ptr + hdrEntrySz, hdr->table_enc);
- }
- }
if (fde != NULL) {
cie = cie_for_fde(fde, table);
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web