Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'trace-v5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing fixes from Steven Rostedt:

- Have recordmcount work with > 64K sections (to support LTO)

- kprobe RCU fixes

- Correct a kprobe critical section with missing mutex

- Remove redundant arch_disarm_kprobe() call

- Fix lockup when kretprobe triggers within kprobe_flush_task()

- Fix memory leak in fetch_op_data operations

- Fix sleep in atomic in ftrace trace array sample code

- Free up memory on failure in sample trace array code

- Fix incorrect reporting of function_graph fields in format file

- Fix quote within quote parsing in bootconfig

- Fix return value of bootconfig tool

- Add testcases for bootconfig tool

- Fix maybe uninitialized warning in ftrace pid file code

- Remove unused variable in tracing_iter_reset()

- Fix some typos

* tag 'trace-v5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
ftrace: Fix maybe-uninitialized compiler warning
tools/bootconfig: Add testcase for show-command and quotes test
tools/bootconfig: Fix to return 0 if succeeded to show the bootconfig
tools/bootconfig: Fix to use correct quotes for value
proc/bootconfig: Fix to use correct quotes for value
tracing: Remove unused event variable in tracing_iter_reset
tracing/probe: Fix memleak in fetch_op_data operations
trace: Fix typo in allocate_ftrace_ops()'s comment
tracing: Make ftrace packed events have align of 1
sample-trace-array: Remove trace_array 'sample-instance'
sample-trace-array: Fix sleeping function called from invalid context
kretprobe: Prevent triggering kretprobe from within kprobe_flush_task
kprobes: Remove redundant arch_disarm_kprobe() call
kprobes: Fix to protect kick_kprobe_optimizer() by kprobe_mutex
kprobes: Use non RCU traversal APIs on kprobe_tables if possible
kprobes: Suppress the suspicious RCU warning on kprobes
recordmcount: support >64k sections

+239 -67
+3 -13
arch/x86/kernel/kprobes/core.c
··· 754 754 NOKPROBE_SYMBOL(kretprobe_trampoline); 755 755 STACK_FRAME_NON_STANDARD(kretprobe_trampoline); 756 756 757 - static struct kprobe kretprobe_kprobe = { 758 - .addr = (void *)kretprobe_trampoline, 759 - }; 760 - 761 757 /* 762 758 * Called from kretprobe_trampoline 763 759 */ 764 760 __used __visible void *trampoline_handler(struct pt_regs *regs) 765 761 { 766 - struct kprobe_ctlblk *kcb; 767 762 struct kretprobe_instance *ri = NULL; 768 763 struct hlist_head *head, empty_rp; 769 764 struct hlist_node *tmp; ··· 768 773 void *frame_pointer; 769 774 bool skipped = false; 770 775 771 - preempt_disable(); 772 - 773 776 /* 774 777 * Set a dummy kprobe for avoiding kretprobe recursion. 775 778 * Since kretprobe never run in kprobe handler, kprobe must not 776 779 * be running at this point. 777 780 */ 778 - kcb = get_kprobe_ctlblk(); 779 - __this_cpu_write(current_kprobe, &kretprobe_kprobe); 780 - kcb->kprobe_status = KPROBE_HIT_ACTIVE; 781 + kprobe_busy_begin(); 781 782 782 783 INIT_HLIST_HEAD(&empty_rp); 783 784 kretprobe_hash_lock(current, &head, &flags); ··· 849 858 __this_cpu_write(current_kprobe, &ri->rp->kp); 850 859 ri->ret_addr = correct_ret_addr; 851 860 ri->rp->handler(ri, regs); 852 - __this_cpu_write(current_kprobe, &kretprobe_kprobe); 861 + __this_cpu_write(current_kprobe, &kprobe_busy); 853 862 } 854 863 855 864 recycle_rp_inst(ri, &empty_rp); ··· 865 874 866 875 kretprobe_hash_unlock(current, &flags); 867 876 868 - __this_cpu_write(current_kprobe, NULL); 869 - preempt_enable(); 877 + kprobe_busy_end(); 870 878 871 879 hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { 872 880 hlist_del(&ri->hlist);
+10 -5
fs/proc/bootconfig.c
··· 26 26 static int __init copy_xbc_key_value_list(char *dst, size_t size) 27 27 { 28 28 struct xbc_node *leaf, *vnode; 29 - const char *val; 30 29 char *key, *end = dst + size; 30 + const char *val; 31 + char q; 31 32 int ret = 0; 32 33 33 34 key = kzalloc(XBC_KEYLEN_MAX, GFP_KERNEL); ··· 42 41 break; 43 42 dst += ret; 44 43 vnode = xbc_node_get_child(leaf); 45 - if (vnode && xbc_node_is_array(vnode)) { 44 + if (vnode) { 46 45 xbc_array_for_each_value(vnode, val) { 47 - ret = snprintf(dst, rest(dst, end), "\"%s\"%s", 48 - val, vnode->next ? ", " : "\n"); 46 + if (strchr(val, '"')) 47 + q = '\''; 48 + else 49 + q = '"'; 50 + ret = snprintf(dst, rest(dst, end), "%c%s%c%s", 51 + q, val, q, vnode->next ? ", " : "\n"); 49 52 if (ret < 0) 50 53 goto out; 51 54 dst += ret; 52 55 } 53 56 } else { 54 - ret = snprintf(dst, rest(dst, end), "\"%s\"\n", val); 57 + ret = snprintf(dst, rest(dst, end), "\"\"\n"); 55 58 if (ret < 0) 56 59 break; 57 60 dst += ret;
+4
include/linux/kprobes.h
··· 350 350 return this_cpu_ptr(&kprobe_ctlblk); 351 351 } 352 352 353 + extern struct kprobe kprobe_busy; 354 + void kprobe_busy_begin(void); 355 + void kprobe_busy_end(void); 356 + 353 357 kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset); 354 358 int register_kprobe(struct kprobe *p); 355 359 void unregister_kprobe(struct kprobe *p);
+48 -13
kernel/kprobes.c
··· 46 46 47 47 48 48 static int kprobes_initialized; 49 + /* kprobe_table can be accessed by 50 + * - Normal hlist traversal and RCU add/del under kprobe_mutex is held. 51 + * Or 52 + * - RCU hlist traversal under disabling preempt (breakpoint handlers) 53 + */ 49 54 static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; 50 55 static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; 51 56 ··· 331 326 struct kprobe *p; 332 327 333 328 head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)]; 334 - hlist_for_each_entry_rcu(p, head, hlist) { 329 + hlist_for_each_entry_rcu(p, head, hlist, 330 + lockdep_is_held(&kprobe_mutex)) { 335 331 if (p->addr == addr) 336 332 return p; 337 333 } ··· 592 586 mutex_unlock(&module_mutex); 593 587 mutex_unlock(&text_mutex); 594 588 cpus_read_unlock(); 595 - mutex_unlock(&kprobe_mutex); 596 589 597 590 /* Step 5: Kick optimizer again if needed */ 598 591 if (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list)) 599 592 kick_kprobe_optimizer(); 593 + 594 + mutex_unlock(&kprobe_mutex); 600 595 } 601 596 602 597 /* Wait for completing optimization and unoptimization */ ··· 675 668 lockdep_assert_cpus_held(); 676 669 arch_unoptimize_kprobe(op); 677 670 op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED; 678 - if (kprobe_disabled(&op->kp)) 679 - arch_disarm_kprobe(&op->kp); 680 671 } 681 672 682 673 /* Unoptimize a kprobe if p is optimized */ ··· 854 849 kprobes_allow_optimization = true; 855 850 for (i = 0; i < KPROBE_TABLE_SIZE; i++) { 856 851 head = &kprobe_table[i]; 857 - hlist_for_each_entry_rcu(p, head, hlist) 852 + hlist_for_each_entry(p, head, hlist) 858 853 if (!kprobe_disabled(p)) 859 854 optimize_kprobe(p); 860 855 } ··· 881 876 kprobes_allow_optimization = false; 882 877 for (i = 0; i < KPROBE_TABLE_SIZE; i++) { 883 878 head = &kprobe_table[i]; 884 - hlist_for_each_entry_rcu(p, head, hlist) { 879 + hlist_for_each_entry(p, head, hlist) { 885 880 if (!kprobe_disabled(p)) 886 881 unoptimize_kprobe(p, false); 887 882 } ··· 1241 1236 } 1242 1237 NOKPROBE_SYMBOL(kretprobe_table_unlock); 1243 1238 1239 + struct kprobe kprobe_busy = { 1240 + .addr = (void *) get_kprobe, 1241 + }; 1242 + 1243 + void kprobe_busy_begin(void) 1244 + { 1245 + struct kprobe_ctlblk *kcb; 1246 + 1247 + preempt_disable(); 1248 + __this_cpu_write(current_kprobe, &kprobe_busy); 1249 + kcb = get_kprobe_ctlblk(); 1250 + kcb->kprobe_status = KPROBE_HIT_ACTIVE; 1251 + } 1252 + 1253 + void kprobe_busy_end(void) 1254 + { 1255 + __this_cpu_write(current_kprobe, NULL); 1256 + preempt_enable(); 1257 + } 1258 + 1244 1259 /* 1245 1260 * This function is called from finish_task_switch when task tk becomes dead, 1246 1261 * so that we can recycle any function-return probe instances associated ··· 1278 1253 /* Early boot. kretprobe_table_locks not yet initialized. */ 1279 1254 return; 1280 1255 1256 + kprobe_busy_begin(); 1257 + 1281 1258 INIT_HLIST_HEAD(&empty_rp); 1282 1259 hash = hash_ptr(tk, KPROBE_HASH_BITS); 1283 1260 head = &kretprobe_inst_table[hash]; ··· 1293 1266 hlist_del(&ri->hlist); 1294 1267 kfree(ri); 1295 1268 } 1269 + 1270 + kprobe_busy_end(); 1296 1271 } 1297 1272 NOKPROBE_SYMBOL(kprobe_flush_task); 1298 1273 ··· 1528 1499 { 1529 1500 struct kprobe *ap, *list_p; 1530 1501 1502 + lockdep_assert_held(&kprobe_mutex); 1503 + 1531 1504 ap = get_kprobe(p->addr); 1532 1505 if (unlikely(!ap)) 1533 1506 return NULL; 1534 1507 1535 1508 if (p != ap) { 1536 - list_for_each_entry_rcu(list_p, &ap->list, list) 1509 + list_for_each_entry(list_p, &ap->list, list) 1537 1510 if (list_p == p) 1538 1511 /* kprobe p is a valid probe */ 1539 1512 goto valid; ··· 1700 1669 { 1701 1670 struct kprobe *kp; 1702 1671 1703 - list_for_each_entry_rcu(kp, &ap->list, list) 1672 + lockdep_assert_held(&kprobe_mutex); 1673 + 1674 + list_for_each_entry(kp, &ap->list, list) 1704 1675 if (!kprobe_disabled(kp)) 1705 1676 /* 1706 1677 * There is an active probe on the list. ··· 1781 1748 else { 1782 1749 /* If disabling probe has special handlers, update aggrprobe */ 1783 1750 if (p->post_handler && !kprobe_gone(p)) { 1784 - list_for_each_entry_rcu(list_p, &ap->list, list) { 1751 + list_for_each_entry(list_p, &ap->list, list) { 1785 1752 if ((list_p != p) && (list_p->post_handler)) 1786 1753 goto noclean; 1787 1754 } ··· 2095 2062 { 2096 2063 struct kprobe *kp; 2097 2064 2065 + lockdep_assert_held(&kprobe_mutex); 2066 + 2098 2067 p->flags |= KPROBE_FLAG_GONE; 2099 2068 if (kprobe_aggrprobe(p)) { 2100 2069 /* 2101 2070 * If this is an aggr_kprobe, we have to list all the 2102 2071 * chained probes and mark them GONE. 2103 2072 */ 2104 - list_for_each_entry_rcu(kp, &p->list, list) 2073 + list_for_each_entry(kp, &p->list, list) 2105 2074 kp->flags |= KPROBE_FLAG_GONE; 2106 2075 p->post_handler = NULL; 2107 2076 kill_optimized_kprobe(p); ··· 2347 2312 mutex_lock(&kprobe_mutex); 2348 2313 for (i = 0; i < KPROBE_TABLE_SIZE; i++) { 2349 2314 head = &kprobe_table[i]; 2350 - hlist_for_each_entry_rcu(p, head, hlist) 2315 + hlist_for_each_entry(p, head, hlist) 2351 2316 if (within_module_init((unsigned long)p->addr, mod) || 2352 2317 (checkcore && 2353 2318 within_module_core((unsigned long)p->addr, mod))) { ··· 2585 2550 for (i = 0; i < KPROBE_TABLE_SIZE; i++) { 2586 2551 head = &kprobe_table[i]; 2587 2552 /* Arm all kprobes on a best-effort basis */ 2588 - hlist_for_each_entry_rcu(p, head, hlist) { 2553 + hlist_for_each_entry(p, head, hlist) { 2589 2554 if (!kprobe_disabled(p)) { 2590 2555 err = arm_kprobe(p); 2591 2556 if (err) { ··· 2628 2593 for (i = 0; i < KPROBE_TABLE_SIZE; i++) { 2629 2594 head = &kprobe_table[i]; 2630 2595 /* Disarm all kprobes on a best-effort basis */ 2631 - hlist_for_each_entry_rcu(p, head, hlist) { 2596 + hlist_for_each_entry(p, head, hlist) { 2632 2597 if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p)) { 2633 2598 err = disarm_kprobe(p, false); 2634 2599 if (err) {
+10 -2
kernel/trace/ftrace.c
··· 2260 2260 2261 2261 if (hash_contains_ip(ip, op->func_hash)) 2262 2262 return op; 2263 - } 2263 + } 2264 2264 2265 2265 return NULL; 2266 2266 } ··· 3599 3599 if (direct) 3600 3600 seq_printf(m, "\n\tdirect-->%pS", (void *)direct); 3601 3601 } 3602 - } 3602 + } 3603 3603 3604 3604 seq_putc(m, '\n'); 3605 3605 ··· 7151 7151 case TRACE_NO_PIDS: 7152 7152 seq_ops = &ftrace_no_pid_sops; 7153 7153 break; 7154 + default: 7155 + trace_array_put(tr); 7156 + WARN_ON_ONCE(1); 7157 + return -EINVAL; 7154 7158 } 7155 7159 7156 7160 ret = seq_open(file, seq_ops); ··· 7233 7229 other_pids = rcu_dereference_protected(tr->function_pids, 7234 7230 lockdep_is_held(&ftrace_lock)); 7235 7231 break; 7232 + default: 7233 + ret = -EINVAL; 7234 + WARN_ON_ONCE(1); 7235 + goto out; 7236 7236 } 7237 7237 7238 7238 ret = trace_pid_write(filtered_pids, &pid_list, ubuf, cnt);
+1 -2
kernel/trace/trace.c
··· 3570 3570 3571 3571 void tracing_iter_reset(struct trace_iterator *iter, int cpu) 3572 3572 { 3573 - struct ring_buffer_event *event; 3574 3573 struct ring_buffer_iter *buf_iter; 3575 3574 unsigned long entries = 0; 3576 3575 u64 ts; ··· 3587 3588 * that a reset never took place on a cpu. This is evident 3588 3589 * by the timestamp being before the start of the buffer. 3589 3590 */ 3590 - while ((event = ring_buffer_iter_peek(buf_iter, &ts))) { 3591 + while (ring_buffer_iter_peek(buf_iter, &ts)) { 3591 3592 if (ts >= iter->array_buffer->time_start) 3592 3593 break; 3593 3594 entries++;
+3
kernel/trace/trace.h
··· 61 61 #undef __field_desc 62 62 #define __field_desc(type, container, item) 63 63 64 + #undef __field_packed 65 + #define __field_packed(type, container, item) 66 + 64 67 #undef __array 65 68 #define __array(type, item, size) type item[size]; 66 69
+7 -7
kernel/trace/trace_entries.h
··· 78 78 79 79 F_STRUCT( 80 80 __field_struct( struct ftrace_graph_ent, graph_ent ) 81 - __field_desc( unsigned long, graph_ent, func ) 82 - __field_desc( int, graph_ent, depth ) 81 + __field_packed( unsigned long, graph_ent, func ) 82 + __field_packed( int, graph_ent, depth ) 83 83 ), 84 84 85 85 F_printk("--> %ps (%d)", (void *)__entry->func, __entry->depth) ··· 92 92 93 93 F_STRUCT( 94 94 __field_struct( struct ftrace_graph_ret, ret ) 95 - __field_desc( unsigned long, ret, func ) 96 - __field_desc( unsigned long, ret, overrun ) 97 - __field_desc( unsigned long long, ret, calltime) 98 - __field_desc( unsigned long long, ret, rettime ) 99 - __field_desc( int, ret, depth ) 95 + __field_packed( unsigned long, ret, func ) 96 + __field_packed( unsigned long, ret, overrun ) 97 + __field_packed( unsigned long long, ret, calltime) 98 + __field_packed( unsigned long long, ret, rettime ) 99 + __field_packed( int, ret, depth ) 100 100 ), 101 101 102 102 F_printk("<-- %ps (%d) (start: %llx end: %llx) over: %d",
+16
kernel/trace/trace_export.c
··· 45 45 #undef __field_desc 46 46 #define __field_desc(type, container, item) type item; 47 47 48 + #undef __field_packed 49 + #define __field_packed(type, container, item) type item; 50 + 48 51 #undef __array 49 52 #define __array(type, item, size) type item[size]; 50 53 ··· 88 85 .size = sizeof(_type), .align = __alignof__(_type), \ 89 86 is_signed_type(_type), .filter_type = _filter_type }, 90 87 88 + 89 + #undef __field_ext_packed 90 + #define __field_ext_packed(_type, _item, _filter_type) { \ 91 + .type = #_type, .name = #_item, \ 92 + .size = sizeof(_type), .align = 1, \ 93 + is_signed_type(_type), .filter_type = _filter_type }, 94 + 91 95 #undef __field 92 96 #define __field(_type, _item) __field_ext(_type, _item, FILTER_OTHER) 93 97 ··· 103 93 104 94 #undef __field_desc 105 95 #define __field_desc(_type, _container, _item) __field_ext(_type, _item, FILTER_OTHER) 96 + 97 + #undef __field_packed 98 + #define __field_packed(_type, _container, _item) __field_ext_packed(_type, _item, FILTER_OTHER) 106 99 107 100 #undef __array 108 101 #define __array(_type, _item, _len) { \ ··· 141 128 142 129 #undef __field_desc 143 130 #define __field_desc(type, container, item) 131 + 132 + #undef __field_packed 133 + #define __field_packed(type, container, item) 144 134 145 135 #undef __array 146 136 #define __array(type, item, len)
+1 -1
kernel/trace/trace_functions.c
··· 42 42 if (!ops) 43 43 return -ENOMEM; 44 44 45 - /* Currently only the non stack verision is supported */ 45 + /* Currently only the non stack version is supported */ 46 46 ops->func = function_trace_call; 47 47 ops->flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_PID; 48 48
+2 -2
kernel/trace/trace_probe.c
··· 639 639 ret = -EINVAL; 640 640 goto fail; 641 641 } 642 - if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM) || 643 - parg->count) { 642 + if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM || 643 + code->op == FETCH_OP_DATA) || parg->count) { 644 644 /* 645 645 * IMM, DATA and COMM is pointing actual address, those 646 646 * must be kept, and if parg->count != 0, this is an
+18 -6
samples/ftrace/sample-trace-array.c
··· 6 6 #include <linux/timer.h> 7 7 #include <linux/err.h> 8 8 #include <linux/jiffies.h> 9 + #include <linux/workqueue.h> 9 10 10 11 /* 11 12 * Any file that uses trace points, must include the header. ··· 21 20 static void mytimer_handler(struct timer_list *unused); 22 21 static struct task_struct *simple_tsk; 23 22 23 + static void trace_work_fn(struct work_struct *work) 24 + { 25 + /* 26 + * Disable tracing for event "sample_event". 27 + */ 28 + trace_array_set_clr_event(tr, "sample-subsystem", "sample_event", 29 + false); 30 + } 31 + static DECLARE_WORK(trace_work, trace_work_fn); 32 + 24 33 /* 25 34 * mytimer: Timer setup to disable tracing for event "sample_event". This 26 35 * timer is only for the purposes of the sample module to demonstrate access of ··· 40 29 41 30 static void mytimer_handler(struct timer_list *unused) 42 31 { 43 - /* 44 - * Disable tracing for event "sample_event". 45 - */ 46 - trace_array_set_clr_event(tr, "sample-subsystem", "sample_event", 47 - false); 32 + schedule_work(&trace_work); 48 33 } 49 34 50 35 static void simple_thread_func(int count) ··· 83 76 simple_thread_func(count++); 84 77 85 78 del_timer(&mytimer); 79 + cancel_work_sync(&trace_work); 86 80 87 81 /* 88 82 * trace_array_put() decrements the reference counter associated with ··· 115 107 trace_printk_init_buffers(); 116 108 117 109 simple_tsk = kthread_run(simple_thread, NULL, "sample-instance"); 118 - if (IS_ERR(simple_tsk)) 110 + if (IS_ERR(simple_tsk)) { 111 + trace_array_put(tr); 112 + trace_array_destroy(tr); 119 113 return -1; 114 + } 115 + 120 116 return 0; 121 117 } 122 118
+92 -6
scripts/recordmcount.h
··· 29 29 #undef has_rel_mcount 30 30 #undef tot_relsize 31 31 #undef get_mcountsym 32 + #undef find_symtab 33 + #undef get_shnum 34 + #undef set_shnum 35 + #undef get_shstrndx 36 + #undef get_symindex 32 37 #undef get_sym_str_and_relp 33 38 #undef do_func 34 39 #undef Elf_Addr ··· 63 58 # define __has_rel_mcount __has64_rel_mcount 64 59 # define has_rel_mcount has64_rel_mcount 65 60 # define tot_relsize tot64_relsize 61 + # define find_symtab find_symtab64 62 + # define get_shnum get_shnum64 63 + # define set_shnum set_shnum64 64 + # define get_shstrndx get_shstrndx64 65 + # define get_symindex get_symindex64 66 66 # define get_sym_str_and_relp get_sym_str_and_relp_64 67 67 # define do_func do64 68 68 # define get_mcountsym get_mcountsym_64 ··· 101 91 # define __has_rel_mcount __has32_rel_mcount 102 92 # define has_rel_mcount has32_rel_mcount 103 93 # define tot_relsize tot32_relsize 94 + # define find_symtab find_symtab32 95 + # define get_shnum get_shnum32 96 + # define set_shnum set_shnum32 97 + # define get_shstrndx get_shstrndx32 98 + # define get_symindex get_symindex32 104 99 # define get_sym_str_and_relp get_sym_str_and_relp_32 105 100 # define do_func do32 106 101 # define get_mcountsym get_mcountsym_32 ··· 188 173 return is_fake; 189 174 } 190 175 176 + static unsigned int get_symindex(Elf_Sym const *sym, Elf32_Word const *symtab, 177 + Elf32_Word const *symtab_shndx) 178 + { 179 + unsigned long offset; 180 + int index; 181 + 182 + if (sym->st_shndx != SHN_XINDEX) 183 + return w2(sym->st_shndx); 184 + 185 + offset = (unsigned long)sym - (unsigned long)symtab; 186 + index = offset / sizeof(*sym); 187 + 188 + return w(symtab_shndx[index]); 189 + } 190 + 191 + static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0) 192 + { 193 + if (shdr0 && !ehdr->e_shnum) 194 + return w(shdr0->sh_size); 195 + 196 + return w2(ehdr->e_shnum); 197 + } 198 + 199 + static void set_shnum(Elf_Ehdr *ehdr, Elf_Shdr *shdr0, unsigned int new_shnum) 200 + { 201 + if (new_shnum >= SHN_LORESERVE) { 202 + ehdr->e_shnum = 0; 203 + shdr0->sh_size = w(new_shnum); 204 + } else 205 + ehdr->e_shnum = w2(new_shnum); 206 + } 207 + 208 + static int get_shstrndx(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0) 209 + { 210 + if (ehdr->e_shstrndx != SHN_XINDEX) 211 + return w2(ehdr->e_shstrndx); 212 + 213 + return w(shdr0->sh_link); 214 + } 215 + 216 + static void find_symtab(Elf_Ehdr *const ehdr, Elf_Shdr const *shdr0, 217 + unsigned const nhdr, Elf32_Word **symtab, 218 + Elf32_Word **symtab_shndx) 219 + { 220 + Elf_Shdr const *relhdr; 221 + unsigned k; 222 + 223 + *symtab = NULL; 224 + *symtab_shndx = NULL; 225 + 226 + for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { 227 + if (relhdr->sh_type == SHT_SYMTAB) 228 + *symtab = (void *)ehdr + relhdr->sh_offset; 229 + else if (relhdr->sh_type == SHT_SYMTAB_SHNDX) 230 + *symtab_shndx = (void *)ehdr + relhdr->sh_offset; 231 + 232 + if (*symtab && *symtab_shndx) 233 + break; 234 + } 235 + } 236 + 191 237 /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */ 192 238 static int append_func(Elf_Ehdr *const ehdr, 193 239 Elf_Shdr *const shstr, ··· 264 188 char const *mc_name = (sizeof(Elf_Rela) == rel_entsize) 265 189 ? ".rela__mcount_loc" 266 190 : ".rel__mcount_loc"; 267 - unsigned const old_shnum = w2(ehdr->e_shnum); 268 191 uint_t const old_shoff = _w(ehdr->e_shoff); 269 192 uint_t const old_shstr_sh_size = _w(shstr->sh_size); 270 193 uint_t const old_shstr_sh_offset = _w(shstr->sh_offset); 194 + Elf_Shdr *const shdr0 = (Elf_Shdr *)(old_shoff + (void *)ehdr); 195 + unsigned int const old_shnum = get_shnum(ehdr, shdr0); 196 + unsigned int const new_shnum = 2 + old_shnum; /* {.rel,}__mcount_loc */ 271 197 uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size); 272 198 uint_t new_e_shoff; 273 199 ··· 278 200 t += sb.st_size; 279 201 t += (_align & -t); /* word-byte align */ 280 202 new_e_shoff = t; 203 + 204 + set_shnum(ehdr, shdr0, new_shnum); 281 205 282 206 /* body for new shstrtab */ 283 207 if (ulseek(sb.st_size, SEEK_SET) < 0) ··· 335 255 return -1; 336 256 337 257 ehdr->e_shoff = _w(new_e_shoff); 338 - ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */ 339 258 if (ulseek(0, SEEK_SET) < 0) 340 259 return -1; 341 260 if (uwrite(ehdr, sizeof(*ehdr)) < 0) ··· 513 434 uint_t *const recvalp, 514 435 unsigned int *sym_index, 515 436 Elf_Shdr const *const symhdr, 437 + Elf32_Word const *symtab, 438 + Elf32_Word const *symtab_shndx, 516 439 Elf_Ehdr const *const ehdr) 517 440 { 518 441 Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset) ··· 526 445 for (symp = sym0, t = nsym; t; --t, ++symp) { 527 446 unsigned int const st_bind = ELF_ST_BIND(symp->st_info); 528 447 529 - if (txtndx == w2(symp->st_shndx) 448 + if (txtndx == get_symindex(symp, symtab, symtab_shndx) 530 449 /* avoid STB_WEAK */ 531 450 && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) { 532 451 /* function symbols on ARM have quirks, avoid them */ ··· 597 516 return totrelsz; 598 517 } 599 518 600 - 601 519 /* Overall supervision for Elf32 ET_REL file. */ 602 520 static int do_func(Elf_Ehdr *const ehdr, char const *const fname, 603 521 unsigned const reltype) 604 522 { 605 523 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) 606 524 + (void *)ehdr); 607 - unsigned const nhdr = w2(ehdr->e_shnum); 608 - Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)]; 525 + unsigned const nhdr = get_shnum(ehdr, shdr0); 526 + Elf_Shdr *const shstr = &shdr0[get_shstrndx(ehdr, shdr0)]; 609 527 char const *const shstrtab = (char const *)(_w(shstr->sh_offset) 610 528 + (void *)ehdr); 611 529 612 530 Elf_Shdr const *relhdr; 613 531 unsigned k; 532 + 533 + Elf32_Word *symtab; 534 + Elf32_Word *symtab_shndx; 614 535 615 536 /* Upper bound on space: assume all relevant relocs are for mcount. */ 616 537 unsigned totrelsz; ··· 644 561 return -1; 645 562 } 646 563 564 + find_symtab(ehdr, shdr0, nhdr, &symtab, &symtab_shndx); 565 + 647 566 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { 648 567 char const *const txtname = has_rel_mcount(relhdr, shdr0, 649 568 shstrtab, fname); ··· 662 577 result = find_secsym_ndx(w(relhdr->sh_info), txtname, 663 578 &recval, &recsym, 664 579 &shdr0[symsec_sh_link], 580 + symtab, symtab_shndx, 665 581 ehdr); 666 582 if (result) 667 583 goto out;
+14 -10
tools/bootconfig/main.c
··· 14 14 #include <linux/kernel.h> 15 15 #include <linux/bootconfig.h> 16 16 17 - static int xbc_show_array(struct xbc_node *node) 17 + static int xbc_show_value(struct xbc_node *node) 18 18 { 19 19 const char *val; 20 + char q; 20 21 int i = 0; 21 22 22 23 xbc_array_for_each_value(node, val) { 23 - printf("\"%s\"%s", val, node->next ? ", " : ";\n"); 24 + if (strchr(val, '"')) 25 + q = '\''; 26 + else 27 + q = '"'; 28 + printf("%c%s%c%s", q, val, q, node->next ? ", " : ";\n"); 24 29 i++; 25 30 } 26 31 return i; ··· 53 48 continue; 54 49 } else if (cnode && xbc_node_is_value(cnode)) { 55 50 printf("%s = ", xbc_node_get_data(node)); 56 - if (cnode->next) 57 - xbc_show_array(cnode); 58 - else 59 - printf("\"%s\";\n", xbc_node_get_data(cnode)); 51 + xbc_show_value(cnode); 60 52 } else { 61 53 printf("%s;\n", xbc_node_get_data(node)); 62 54 } ··· 207 205 } 208 206 209 207 ret = load_xbc_from_initrd(fd, &buf); 210 - if (ret < 0) 208 + if (ret < 0) { 211 209 pr_err("Failed to load a boot config from initrd: %d\n", ret); 212 - else 213 - xbc_show_compact_tree(); 214 - 210 + goto out; 211 + } 212 + xbc_show_compact_tree(); 213 + ret = 0; 214 + out: 215 215 close(fd); 216 216 free(buf); 217 217
+10
tools/bootconfig/test-bootconfig.sh
··· 55 55 xpass $BOOTCONF -a $TEMPCONF $INITRD 56 56 new_size=$(stat -c %s $INITRD) 57 57 58 + echo "Show command test" 59 + xpass $BOOTCONF $INITRD 60 + 58 61 echo "File size check" 59 62 xpass test $new_size -eq $(expr $bconf_size + $initrd_size + 9 + 12) 60 63 ··· 116 113 xpass grep -q "bar" $OUTFILE 117 114 xpass grep -q "baz" $OUTFILE 118 115 xpass grep -q "qux" $OUTFILE 116 + 117 + echo "Double/single quotes test" 118 + echo "key = '\"string\"';" > $TEMPCONF 119 + $BOOTCONF -a $TEMPCONF $INITRD 120 + $BOOTCONF $INITRD > $TEMPCONF 121 + cat $TEMPCONF 122 + xpass grep \'\"string\"\' $TEMPCONF 119 123 120 124 echo "=== expected failure cases ===" 121 125 for i in samples/bad-* ; do