|
@@ -147,3 +147,71 @@ static const struct unwind_idx *search_index(unsigned long addr,
|
|
|
start = mid;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if (likely(start->addr_offset <= addr_prel31))
|
|
|
+ return start;
|
|
|
+ else {
|
|
|
+ pr_warning("unwind: Unknown symbol address %08lx\n", addr);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static const struct unwind_idx *unwind_find_origin(
|
|
|
+ const struct unwind_idx *start, const struct unwind_idx *stop)
|
|
|
+{
|
|
|
+ pr_debug("%s(%p, %p)\n", __func__, start, stop);
|
|
|
+ while (start < stop) {
|
|
|
+ const struct unwind_idx *mid = start + ((stop - start) >> 1);
|
|
|
+
|
|
|
+ if (mid->addr_offset >= 0x40000000)
|
|
|
+ /* negative offset */
|
|
|
+ start = mid + 1;
|
|
|
+ else
|
|
|
+ /* positive offset */
|
|
|
+ stop = mid;
|
|
|
+ }
|
|
|
+ pr_debug("%s -> %p\n", __func__, stop);
|
|
|
+ return stop;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct unwind_idx *unwind_find_idx(unsigned long addr)
|
|
|
+{
|
|
|
+ const struct unwind_idx *idx = NULL;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ pr_debug("%s(%08lx)\n", __func__, addr);
|
|
|
+
|
|
|
+ if (core_kernel_text(addr)) {
|
|
|
+ if (unlikely(!__origin_unwind_idx))
|
|
|
+ __origin_unwind_idx =
|
|
|
+ unwind_find_origin(__start_unwind_idx,
|
|
|
+ __stop_unwind_idx);
|
|
|
+
|
|
|
+ /* main unwind table */
|
|
|
+ idx = search_index(addr, __start_unwind_idx,
|
|
|
+ __origin_unwind_idx,
|
|
|
+ __stop_unwind_idx);
|
|
|
+ } else {
|
|
|
+ /* module unwind tables */
|
|
|
+ struct unwind_table *table;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&unwind_lock, flags);
|
|
|
+ list_for_each_entry(table, &unwind_tables, list) {
|
|
|
+ if (addr >= table->begin_addr &&
|
|
|
+ addr < table->end_addr) {
|
|
|
+ idx = search_index(addr, table->start,
|
|
|
+ table->origin,
|
|
|
+ table->stop);
|
|
|
+ /* Move-to-front to exploit common traces */
|
|
|
+ list_move(&table->list, &unwind_tables);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&unwind_lock, flags);
|
|
|
+ }
|
|
|
+
|
|
|
+ pr_debug("%s: idx = %p\n", __func__, idx);
|
|
|
+ return idx;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
|