diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-11-18 19:33:51 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-11-18 19:33:51 +1100 |
commit | c38c2e8d08e03e905b72334747a9f8795f3526c2 (patch) | |
tree | 94a7e5ec6124998eee1d1a27577370b03304c4e6 | |
parent | 94796c825b0708c8c86e7135d60c435fc3fd00a5 (diff) | |
download | skiboot-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.main | 15 | ||||
-rw-r--r-- | Makefile.rules | 3 | ||||
-rw-r--r-- | asm/dummy_map.S | 3 | ||||
-rw-r--r-- | asm/real_map.S | 20 | ||||
-rw-r--r-- | core/opal.c | 2 | ||||
-rw-r--r-- | core/stack.c | 51 | ||||
-rw-r--r-- | core/utils.c | 27 | ||||
-rw-r--r-- | hw/fsp/fsp-attn.c | 2 | ||||
-rw-r--r-- | include/cpu.h | 2 | ||||
-rw-r--r-- | include/skiboot.h | 6 | ||||
-rw-r--r-- | include/stack.h | 2 | ||||
-rw-r--r-- | skiboot.lds.S | 12 |
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*) |