Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1283008 > unrolled thread

[RFC 00/17] ARC Dwarf unwinder improvements

Started byVineet Gupta <Vineet.Gupta1@synopsys.com>
First post2015-12-03 13:50 +0100
Last post2015-12-03 13:50 +0100
Articles 9 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [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

#1283008 — [RFC 00/17] ARC Dwarf unwinder improvements

FromVineet Gupta <Vineet.Gupta1@synopsys.com>
Date2015-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]


#1283010 — [PATCH 11/17] ARC: dw2 unwind: Elide REG_INVALID check

FromVineet Gupta <Vineet.Gupta1@synopsys.com>
Date2015-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]


#1283012 — [PATCH 13/17] ARC: dw2 unwind: Assume all regs to be unsigned long

FromVineet Gupta <Vineet.Gupta1@synopsys.com>
Date2015-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]


#1283013 — [PATCH 06/17] ARC: dw2 unwind: Don't verify Main FDE Table size everytime

FromVineet Gupta <Vineet.Gupta1@synopsys.com>
Date2015-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]


#1283014 — [PATCH 05/17] ARC: dw2 unwind: Better printing

FromVineet Gupta <Vineet.Gupta1@synopsys.com>
Date2015-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]


#1283016 — [PATCH 01/17] ARC: dw2 unwind: Elide generation of const propagated clones

FromVineet Gupta <Vineet.Gupta1@synopsys.com>
Date2015-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]


#1283018 — [PATCH 03/17] ARC: dw2 unwind: Remove handling of for signal frame

FromVineet Gupta <Vineet.Gupta1@synopsys.com>
Date2015-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]


#1283019 — [PATCH 10/17] ARC: dw2 unwind: CIE parsing/validation done only once at startup

FromVineet Gupta <Vineet.Gupta1@synopsys.com>
Date2015-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 == &not_fde)
+		if (cie == &not_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 != &not_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]


#1283020 — [PATCH 08/17] ARC: dw2 unwind: Don't verify FDE lookup table metadata

FromVineet Gupta <Vineet.Gupta1@synopsys.com>
Date2015-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