aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-11-18 19:33:51 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-11-18 19:33:51 +1100
commitc38c2e8d08e03e905b72334747a9f8795f3526c2 (patch)
tree94a7e5ec6124998eee1d1a27577370b03304c4e6
parent94796c825b0708c8c86e7135d60c435fc3fd00a5 (diff)
downloadskiboot-c38c2e8d08e03e905b72334747a9f8795f3526c2.zip
skiboot-c38c2e8d08e03e905b72334747a9f8795f3526c2.tar.gz
skiboot-c38c2e8d08e03e905b72334747a9f8795f3526c2.tar.bz2
Add symbolic backtraces and expose skiboot map to Linux
We use a double link technique, doing a first pass with a .o containing a dummy symbol map, then re-linking with a new .o Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--Makefile.main15
-rw-r--r--Makefile.rules3
-rw-r--r--asm/dummy_map.S3
-rw-r--r--asm/real_map.S20
-rw-r--r--core/opal.c2
-rw-r--r--core/stack.c51
-rw-r--r--core/utils.c27
-rw-r--r--hw/fsp/fsp-attn.c2
-rw-r--r--include/cpu.h2
-rw-r--r--include/skiboot.h6
-rw-r--r--include/stack.h2
-rw-r--r--skiboot.lds.S12
12 files changed, 113 insertions, 32 deletions
diff --git a/Makefile.main b/Makefile.main
index aff145e..129d38b 100644
--- a/Makefile.main
+++ b/Makefile.main
@@ -119,14 +119,19 @@ OBJS += $(LIBPORE)
endif
OBJS += $(LIBC) $(CCAN) $(DEVSRC_OBJ) gitid.o
+OBJS_1 = $(OBJS) asm/dummy_map.o
+OBJS_2 = $(OBJS) asm/real_map.o
+
$(TARGET).lid: $(TARGET).elf
$(call Q,OBJCOPY, $(OBJCOPY) -O binary -S $^ $@, $@)
-$(TARGET).elf: $(OBJS) $(TARGET).lds $(KERNEL)
- $(call Q,LD, $(CC) $(LDFLAGS) -T $(TARGET).lds $(OBJS) -o $@, $@)
+$(TARGET).tmp.elf: $(OBJS_1) $(TARGET).lds $(KERNEL)
+ $(call Q,LD, $(CC) $(LDFLAGS) -T $(TARGET).lds $(OBJS_1) -o $@, $@)
+
+asm/real_map.o : $(TARGET).tmp.map
-$(TARGET).map: $(TARGET).elf
- $(call Q,NM, $(NM) -n $< | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)' > $@, $@)
+$(TARGET).elf: $(OBJS_2) $(TARGET).lds $(KERNEL)
+ $(call Q,LD, $(CC) $(LDFLAGS) -T $(TARGET).lds $(OBJS_2) -o $@, $@)
$(SUBDIRS):
$(call Q,MKDIR,mkdir $@, $@)
@@ -165,7 +170,7 @@ cscope:
clean:
$(RM) *.[odsa] $(SUBDIRS:%=%/*.[odsa])
- $(RM) $(TARGET).elf $(TARGET).lid $(TARGET).map $(TARGET).lds
+ $(RM) *.elf $(TARGET).lid *.map $(TARGET).lds
$(RM) include/asm-offsets.h gitid.c
distclean: clean
diff --git a/Makefile.rules b/Makefile.rules
index 200abcb..3014c81 100644
--- a/Makefile.rules
+++ b/Makefile.rules
@@ -51,3 +51,6 @@ endef
%.lds : %.lds.S
$(call Q,CC, $(CC) $(CPPFLAGS) -P -E $< -o $@, $@)
+
+%.map: %.elf
+ $(call Q,NM, $(NM) -n $< | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)' > $@, $@)
diff --git a/asm/dummy_map.S b/asm/dummy_map.S
new file mode 100644
index 0000000..19a8d62
--- /dev/null
+++ b/asm/dummy_map.S
@@ -0,0 +1,3 @@
+ .section ".sym_map","a"
+ .byte 0
+
diff --git a/asm/real_map.S b/asm/real_map.S
new file mode 100644
index 0000000..fbbf2cc
--- /dev/null
+++ b/asm/real_map.S
@@ -0,0 +1,20 @@
+/* Copyright 2013-2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+ .section ".sym_map","a"
+ .incbin "skiboot.tmp.map"
+
diff --git a/core/opal.c b/core/opal.c
index 7e53486..345d619 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -119,6 +119,8 @@ static void add_opal_firmware_node(void)
dt_add_property_string(firmware, "compatible", "ibm,opal-firmware");
dt_add_property_string(firmware, "name", "firmware");
dt_add_property_string(firmware, "git-id", gitid);
+ dt_add_property(firmware, "symbol-map", __sym_map_start,
+ __sym_map_end - __sym_map_start);
}
void add_opal_node(void)
diff --git a/core/stack.c b/core/stack.c
index 15c6e54..1341175 100644
--- a/core/stack.c
+++ b/core/stack.c
@@ -20,8 +20,9 @@
#include <cpu.h>
#include <stack.h>
#include <mem_region.h>
+#include <unistd.h>
-#define STACK_BUF_ENTRIES 20
+#define STACK_BUF_ENTRIES 60
static struct bt_entry bt_buf[STACK_BUF_ENTRIES];
extern uint32_t _stext, _etext;
@@ -47,27 +48,27 @@ void __nomcount __backtrace(struct bt_entry *entries, unsigned int *count)
void __print_backtrace(unsigned int pir,
struct bt_entry *entries, unsigned int count,
- char *out_buf, unsigned int *len)
+ char *out_buf, unsigned int *len, bool symbols)
{
+ static char bt_text_buf[4096];
int i, l = 0, max;
char *buf = out_buf;
- unsigned long bottom, top, tbot, ttop;
+ unsigned long bottom, top, tbot, ttop, saddr = 0;
+ char *sym = NULL, *sym_end = NULL;
char mark;
- if (len)
+ if (!out_buf) {
+ buf = bt_text_buf;
+ max = sizeof(bt_text_buf) - 16;
+ } else
max = *len - 1;
- else
- max = INT_MAX;
bottom = cpu_stack_bottom(pir);
top = cpu_stack_top(pir);
- tbot = (unsigned long)&_stext;
+ tbot = SKIBOOT_BASE;
ttop = (unsigned long)&_etext;
- if (buf)
- l += snprintf(buf, max, "CPU %04x Backtrace:\n", pir);
- else
- l += printf("CPU %04x Backtrace:\n", pir);
+ l += snprintf(buf, max, "CPU %04x Backtrace:\n", pir);
for (i = 0; i < count && l < max; i++) {
if (entries->sp < bottom || entries->sp > top)
mark = '!';
@@ -75,19 +76,23 @@ void __print_backtrace(unsigned int pir,
mark = '*';
else
mark = ' ';
- if (buf)
- l += snprintf(buf + l, max - l,
- " S: %016lx R: %016lx %c\n",
- entries->sp, entries->pc, mark);
+ if (symbols)
+ saddr = get_symbol(entries->pc, &sym, &sym_end);
+ l += snprintf(buf + l, max - l,
+ " S: %016lx R: %016lx %c ",
+ entries->sp, entries->pc, mark);
+ while(sym < sym_end && l < max)
+ buf[l++] = *(sym++);
+ if (sym && l < max)
+ l += snprintf(buf + l, max - l, "+0x%lx\n",
+ entries->pc - saddr);
else
- l += printf(" S: %016lx R: %016lx %c\n",
- entries->sp, entries->pc, mark);
+ l += snprintf(buf + l, max - l, "\n");
entries++;
}
- if (buf)
- buf[l++] = 0;
- else
- l++;
+ if (!out_buf)
+ write(stdout->fd, bt_text_buf, l);
+ buf[l++] = 0;
if (len)
*len = l;
}
@@ -97,7 +102,7 @@ void backtrace(void)
unsigned int ents = STACK_BUF_ENTRIES;
__backtrace(bt_buf, &ents);
- __print_backtrace(mfspr(SPR_PIR), bt_buf, ents, NULL, NULL);
+ __print_backtrace(mfspr(SPR_PIR), bt_buf, ents, NULL, NULL, true);
}
void __noreturn __nomcount __stack_chk_fail(void);
@@ -189,7 +194,7 @@ void check_stacks(void)
lowest->pir, lowest->stack_bot_mark, lowest->stack_bot_pc,
lowest->stack_bot_tok);
__print_backtrace(lowest->pir, lowest->stack_bot_bt,
- lowest->stack_bot_bt_count, NULL, NULL);
+ lowest->stack_bot_bt_count, NULL, NULL, true);
unlock(&stack_check_lock);
}
diff --git a/core/utils.c b/core/utils.c
index 63046fc..1a81ae2 100644
--- a/core/utils.c
+++ b/core/utils.c
@@ -68,3 +68,30 @@ char __attrconst tohex(uint8_t nibble)
return __tohex[nibble];
}
+unsigned long get_symbol(unsigned long addr, char **sym, char **sym_end)
+{
+ unsigned long prev = 0, next;
+ char *psym = NULL, *p = __sym_map_start;
+
+ *sym = *sym_end = NULL;
+ while(p < __sym_map_end) {
+ next = strtoul(p, &p, 16) | SKIBOOT_BASE;
+ if (next > addr && prev <= addr) {
+ p = psym + 3;;
+ if (p >= __sym_map_end)
+ return 0;
+ *sym = p;
+ while(p < __sym_map_end && *p != 10)
+ p++;
+ *sym_end = p;
+ return prev;
+ }
+ prev = next;
+ psym = p;
+ while(p < __sym_map_end && *p != 10)
+ p++;
+ p++;
+ }
+ return 0;
+}
+
diff --git a/hw/fsp/fsp-attn.c b/hw/fsp/fsp-attn.c
index 036962c..02603a1 100644
--- a/hw/fsp/fsp-attn.c
+++ b/hw/fsp/fsp-attn.c
@@ -109,7 +109,7 @@ void update_sp_attn_area(const char *msg)
__backtrace(bt_buf, &ent_cnt);
len = BT_FRAME_LEN;
__print_backtrace(mfspr(SPR_PIR), bt_buf, ent_cnt,
- ti_attn->msg.bt_buf, &len);
+ ti_attn->msg.bt_buf, &len, false);
snprintf(ti_attn->msg.file_info, FILE_INFO_LEN, "%s", msg);
ti_attn->msg_len = GITID_LEN + BT_FRAME_LEN +
diff --git a/include/cpu.h b/include/cpu.h
index d7acd25..a871073 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -65,7 +65,7 @@ struct cpu_thread {
int64_t stack_bot_mark;
uint64_t stack_bot_pc;
uint64_t stack_bot_tok;
-#define CPU_BACKTRACE_SIZE 20
+#define CPU_BACKTRACE_SIZE 60
struct bt_entry stack_bot_bt[CPU_BACKTRACE_SIZE];
unsigned int stack_bot_bt_count;
#endif
diff --git a/include/skiboot.h b/include/skiboot.h
index 8750c70..79aece6 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -171,6 +171,12 @@ extern struct dt_node *dt_root;
/* Generated git id. */
extern const char gitid[];
+/* Debug support */
+extern char __sym_map_start[];
+extern char __sym_map_end[];
+extern unsigned long get_symbol(unsigned long addr,
+ char **sym, char **sym_end);
+
/* Fast reboot support */
extern void fast_reset(void);
extern void __secondary_cpu_entry(void);
diff --git a/include/stack.h b/include/stack.h
index d6a0609..02f1fe6 100644
--- a/include/stack.h
+++ b/include/stack.h
@@ -114,7 +114,7 @@ extern void __backtrace(struct bt_entry *entries, unsigned int *count);
/* Convert a backtrace to ASCII */
extern void __print_backtrace(unsigned int pir, struct bt_entry *entries,
unsigned int count, char *out_buf,
- unsigned int *len);
+ unsigned int *len, bool symbols);
/* For use by debug code, create and print backtrace, uses a static buffer */
extern void backtrace(void);
diff --git a/skiboot.lds.S b/skiboot.lds.S
index 4e905f8..a54ff5f 100644
--- a/skiboot.lds.S
+++ b/skiboot.lds.S
@@ -125,7 +125,17 @@ SECTIONS
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
- . = ALIGN(0x1000);
+ . = ALIGN(0x10);
+ .sym_map : {
+ __sym_map_start = . ;
+ KEEP(*(.sym_map))
+ __sym_map_end = . ;
+ KEEP(*(.sym_map))
+ }
+
+ /* We locate the BSS at 1M to leave room for the symbol map */
+ . = 0x100000;
+
_sbss = .;
.bss : {
*(.bss*)