Re: PROBLEM: DoS Attack on Fragment Cache
Note that there are two completely separate sysctls here - the timeout on fragments, and the amount of memory available for fragment reassembly. You have to multiply them together to reach the "Mbps of lost or deliberately-lost fragments before we start dropping all future fragments". See the calculation in the description of the patch I mentioned above for exact details, but turning the time down to 1s already gives you 32Mbps, and you can tune the memory usage separately (eg 128MB, really 256 between v4 and v6, would give you 1Gbps of "lost" fragments). Its true, an attacker can use a lot of memory in that case, but 128MiB isn't actually something that rises to the level of "trivial for an attacker to use all the memory you allowed" or "cause OOM". I only chimed in on this thread to note that this isn't just a theoretical attack concern, however - this is a real-world non-attack-scenario issue that's pretty trivial to hit. Just losing 1Mbps of traffic on a modern residential internet connection is pretty doable, make that flow mostly frags and suddenly your VPN drops out for 30 seconds at a time just because. I agree with others here that actually solving the DoS issue isn't trivial, but making it less absurdly trivial to have 30 second dropouts of your VPN connection would also be a nice change. Matt On 4/19/21 05:43, Eric Dumazet wrote: On Sun, Apr 18, 2021 at 4:31 PM Matt Corallo wrote: Should the default, though, be so low? If someone is still using a old modem they can crank up the sysctl, it does seem like such things are pretty rare these days :). Its rather trivial to, without any kind of attack, hit 1Mbps of lost fragments in today's networks, at which point all fragments are dropped. After all, I submitted the patch to "scratch my own itch" :). Again, even if you increase the values by 1000x, it is trivial for an attacker to use all the memory you allowed. And allowing a significant portion of memory to be eaten like that might cause OOM on hosts where jobs are consuming all physical memory. It is a sysctl, I changed things so that one could really reserve/use 16GB of memory if she/he is desperate about frags. Matt On 4/18/21 00:39, Willy Tarreau wrote: I do agree that we shouldn't keep them that long nowadays, we can't go too low without risking to break some slow transmission stacks (SLIP/PPP over modems for example).
Re: PROBLEM: DoS Attack on Fragment Cache
Should the default, though, be so low? If someone is still using a old modem they can crank up the sysctl, it does seem like such things are pretty rare these days :). Its rather trivial to, without any kind of attack, hit 1Mbps of lost fragments in today's networks, at which point all fragments are dropped. After all, I submitted the patch to "scratch my own itch" :). Matt On 4/18/21 00:39, Willy Tarreau wrote: I do agree that we shouldn't keep them that long nowadays, we can't go too low without risking to break some slow transmission stacks (SLIP/PPP over modems for example).
Re: PROBLEM: DoS Attack on Fragment Cache
Sure, there are better ways to handle the reassembly cache overflowing, but that is pretty unrelated to the fact that waiting 30 full seconds for a fragment to come in doesn't really make sense in today's networks (the 30 second delay that is used today appears to even be higher than RFC 791 suggested in 1981!). You get a lot more bang for your buck if you don't wait around so long (or we could restructure things to kick out the oldest fragments, but that is a lot more work, and probably extra indexes that just aren't worth it). Matt On 4/17/21 21:38, Keyu Man wrote: Willy's words make sense to me and I agree that the existing fragments should be evicted when the new one comes in and the cache is full. Though the attacker can still leverage this to flush the victim's cache, as mentioned previously, since fragments are likely to be assembled in a very short time, it would be hard to launch the attack(evicting the legit fragment before it's assembled requires a large packet sending rate). And this seems better than the existing solution (drop all incoming fragments when full). Keyu On Sat, Apr 17, 2021 at 6:30 PM Matt Corallo wrote: See-also "[PATCH] Reduce IP_FRAG_TIME fragment-reassembly timeout to 1s, from 30s" (and the two resends of it) - given the size of the default cache (4MB) and the time that it takes before we flush the cache (30 seconds) you only need about 1Mbps of fragments to hit this issue. While DoS attacks are concerning, its also incredibly practical (and I do) hit this issue in normal non-adversarial conditions. Matt On 4/17/21 03:50, Willy Tarreau wrote: On Sat, Apr 17, 2021 at 12:42:39AM -0700, Keyu Man wrote: How about at least allow the existing queue to finish? Currently a tiny new fragment would potentially invalid all previous fragments by letting them timeout without allowing the fragments to come in to finish the assembly. Because this is exactly the principle of how attacks are built: reserve resources claiming that you'll send everything so that others can't make use of the resources that are reserved to you. The best solution precisely is *not* to wait for anyone to finish, hence *not* to reserve valuable resources that are unusuable by others. Willy
Re: PROBLEM: DoS Attack on Fragment Cache
See-also "[PATCH] Reduce IP_FRAG_TIME fragment-reassembly timeout to 1s, from 30s" (and the two resends of it) - given the size of the default cache (4MB) and the time that it takes before we flush the cache (30 seconds) you only need about 1Mbps of fragments to hit this issue. While DoS attacks are concerning, its also incredibly practical (and I do) hit this issue in normal non-adversarial conditions. Matt On 4/17/21 03:50, Willy Tarreau wrote: On Sat, Apr 17, 2021 at 12:42:39AM -0700, Keyu Man wrote: How about at least allow the existing queue to finish? Currently a tiny new fragment would potentially invalid all previous fragments by letting them timeout without allowing the fragments to come in to finish the assembly. Because this is exactly the principle of how attacks are built: reserve resources claiming that you'll send everything so that others can't make use of the resources that are reserved to you. The best solution precisely is *not* to wait for anyone to finish, hence *not* to reserve valuable resources that are unusuable by others. Willy
[PATCH] misc: hpilo: MAINTAINERS: add entry for hpilo
From: Matt Hsiao The original maintainer left the company, add myself as the successor. Signed-off-by: Matt Hsiao --- MAINTAINERS | 5 + 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fb2a3633b719..0546e7f84a4e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7890,6 +7890,11 @@ W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git F: drivers/media/usb/hdpvr/ +HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER +M: Matt Hsiao +S: Supported +F: drivers/misc/hpilo.[ch] + HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER M: Jerry Hoemann S: Supported -- 2.16.6
Re: [PATCH v6 03/24] iio: make use of devm_iio_kfifo_buffer_setup() helper
On Tue, Feb 16, 2021 at 3:46 PM Gwendal Grignou wrote: > > Reviewed-by: Gwendal Grignou Looks fine to me as well. Reviewed-by: Matt Ranostay > > On Mon, Feb 15, 2021 at 4:11 AM Jonathan Cameron wrote: > > > > On Mon, 15 Feb 2021 12:40:22 +0200 > > Alexandru Ardelean wrote: > > > > > All drivers that already call devm_iio_kfifo_allocate() & > > > iio_device_attach_buffer() are simple to convert to > > > iio_device_attach_kfifo_buffer() in a single go. > > > > > > This change does that; the unwind order is preserved. > > > What is important, is that the devm_iio_kfifo_buffer_setup() be called > > > after the indio_dev->modes is assigned, to make sure that > > > INDIO_BUFFER_SOFTWARE flag is set and not overridden by the assignment to > > > indio_dev->modes. > > > > > > Also, the INDIO_BUFFER_SOFTWARE has been removed from the assignments of > > > 'indio_dev->modes' because it is set by devm_iio_kfifo_buffer_setup(). > > > > > > Signed-off-by: Alexandru Ardelean > > I 'think' this one is is in the obviously correct category so I've > > applied it to the togreg branch of iio.git and pushed out as testing. > > Note there is still plenty of time for any additional feedback, > > particularly as the CC list was a little sparse. > > > > I've +CCd those who I know are still active maintainers of some > > of the affected drivers. > > > > Jonathan > > > > > --- > > > drivers/iio/accel/ssp_accel_sensor.c | 14 --- > > > drivers/iio/adc/ina2xx-adc.c | 14 +-- > > > drivers/iio/adc/ti_am335x_adc.c | 18 --- > > > .../cros_ec_sensors/cros_ec_sensors_core.c| 13 --- > > > drivers/iio/gyro/ssp_gyro_sensor.c| 14 --- > > > drivers/iio/health/max30100.c | 16 ++--- > > > drivers/iio/health/max30102.c | 16 ++--- > > > .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 14 +-- > > > .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 13 +-- > > > .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c| 15 +--- > > > drivers/iio/light/acpi-als.c | 12 -- > > > drivers/iio/light/apds9960.c | 16 ++--- > > > .../staging/iio/impedance-analyzer/ad5933.c | 23 --- > > > 13 files changed, 74 insertions(+), 124 deletions(-) > > > > > > diff --git a/drivers/iio/accel/ssp_accel_sensor.c > > > b/drivers/iio/accel/ssp_accel_sensor.c > > > index 474477e91b5e..04dcb2b657ee 100644 > > > --- a/drivers/iio/accel/ssp_accel_sensor.c > > > +++ b/drivers/iio/accel/ssp_accel_sensor.c > > > @@ -96,7 +96,6 @@ static int ssp_accel_probe(struct platform_device *pdev) > > > int ret; > > > struct iio_dev *indio_dev; > > > struct ssp_sensor_data *spd; > > > - struct iio_buffer *buffer; > > > > > > indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd)); > > > if (!indio_dev) > > > @@ -109,18 +108,15 @@ static int ssp_accel_probe(struct platform_device > > > *pdev) > > > > > > indio_dev->name = ssp_accel_device_name; > > > indio_dev->info = &ssp_accel_iio_info; > > > - indio_dev->modes = INDIO_BUFFER_SOFTWARE; > > > indio_dev->channels = ssp_acc_channels; > > > indio_dev->num_channels = ARRAY_SIZE(ssp_acc_channels); > > > indio_dev->available_scan_masks = ssp_accel_scan_mask; > > > > > > - buffer = devm_iio_kfifo_allocate(&pdev->dev); > > > - if (!buffer) > > > - return -ENOMEM; > > > - > > > - iio_device_attach_buffer(indio_dev, buffer); > > > - > > > - indio_dev->setup_ops = &ssp_accel_buffer_ops; > > > + ret = devm_iio_kfifo_buffer_setup(&pdev->dev, indio_dev, > > > + INDIO_BUFFER_SOFTWARE, > > > + &ssp_accel_buffer_ops); > > > + if (ret) > > > + return ret; > > > > > > platform_set_drvdata(pdev, indio_dev); > > > > > > diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c > > > index b573ec60a8b8..2ae54258b221 100644 > > > --- a/drivers/iio/adc/ina2xx-adc.c > > >
Re: [PATCH] iio:light:apds9960 add detection for MSHW0184 ACPI device in apds9960 driver
On Sat, Dec 19, 2020 at 5:51 PM Max Leiter wrote: > > The device is used in the Microsoft Surface Book 3 and Surface Pro 7 > > Signed-off-by: Max Leiter Reviewed-by: Matt Ranostay > --- > drivers/iio/light/apds9960.c | 8 > 1 file changed, 8 insertions(+) > > diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c > index 9afb3fcc74e6..20719141c03a 100644 > --- a/drivers/iio/light/apds9960.c > +++ b/drivers/iio/light/apds9960.c > @@ -8,6 +8,7 @@ > * TODO: gesture + proximity calib offsets > */ > > +#include > #include > #include > #include > @@ -1113,6 +1114,12 @@ static const struct i2c_device_id apds9960_id[] = { > }; > MODULE_DEVICE_TABLE(i2c, apds9960_id); > > +static const struct acpi_device_id apds9960_acpi_match[] = { > + { "MSHW0184" }, > + { } > +}; > +MODULE_DEVICE_TABLE(acpi, apds9960_acpi_match); > + > static const struct of_device_id apds9960_of_match[] = { > { .compatible = "avago,apds9960" }, > { } > @@ -1124,6 +1131,7 @@ static struct i2c_driver apds9960_driver = { > .name = APDS9960_DRV_NAME, > .of_match_table = apds9960_of_match, > .pm = &apds9960_pm_ops, > + .acpi_match_table = apds9960_acpi_match, > }, > .probe = apds9960_probe, > .remove = apds9960_remove, > -- > 2.29.2 >
Re: [PATCH v3] tracepoint: Do not fail unregistering a probe due to memory allocation
On Wed, Nov 18, 2020 at 09:34:05AM -0500, Steven Rostedt wrote: > From: "Steven Rostedt (VMware)" > > The list of tracepoint callbacks is managed by an array that is protected > by RCU. To update this array, a new array is allocated, the updates are > copied over to the new array, and then the list of functions for the > tracepoint is switched over to the new array. After a completion of an RCU > grace period, the old array is freed. > > This process happens for both adding a callback as well as removing one. > But on removing a callback, if the new array fails to be allocated, the > callback is not removed, and may be used after it is freed by the clients > of the tracepoint. > > There's really no reason to fail if the allocation for a new array fails > when removing a function. Instead, the function can simply be replaced by a > stub function that could be cleaned up on the next modification of the > array. That is, instead of calling the function registered to the > tracepoint, it would call a stub function in its place. > > Link: https://lore.kernel.org/r/20201115055256.65625-1-mmull...@mmlx.us > Link: https://lore.kernel.org/r/20201116175107.02db3...@gandalf.local.home > Link: https://lore.kernel.org/r/20201117211836.54aca...@oasis.local.home > > Cc: Mathieu Desnoyers > Cc: Ingo Molnar > Cc: Alexei Starovoitov > Cc: Daniel Borkmann > Cc: Dmitry Vyukov > Cc: Martin KaFai Lau > Cc: Song Liu > Cc: Yonghong Song > Cc: Andrii Nakryiko > Cc: John Fastabend > Cc: KP Singh > Cc: netdev > Cc: bpf > Cc: Kees Cook > Cc: Florian Weimer > Fixes: 97e1c18e8d17b ("tracing: Kernel Tracepoints") > Reported-by: syzbot+83aa762ef23b6f0d1...@syzkaller.appspotmail.com > Reported-by: syzbot+d29e58bb557324e55...@syzkaller.appspotmail.com > Reported-by: Matt Mullins > Signed-off-by: Steven Rostedt (VMware) I'm a bit late answering your initial query, but yes indeed this fixes the bug I was hunting. I just watched it live through the reproducer for about a half-hour, while unpatched I get an instant "BUG: unable to handle page fault". Tested-by: Matt Mullins > --- > Changes since v2: >- Went back to using a stub function and not touching > the fast path. >- Removed adding __GFP_NOFAIL from the allocation of the removal. > > kernel/tracepoint.c | 80 - > 1 file changed, 64 insertions(+), 16 deletions(-) > > diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c > index 3f659f855074..3e261482296c 100644 > --- a/kernel/tracepoint.c > +++ b/kernel/tracepoint.c > @@ -53,6 +53,12 @@ struct tp_probes { > struct tracepoint_func probes[]; > }; > > +/* Called in removal of a func but failed to allocate a new tp_funcs */ > +static void tp_stub_func(void) > +{ > + return; > +} > + > static inline void *allocate_probes(int count) > { > struct tp_probes *p = kmalloc(struct_size(p, probes, count), > @@ -131,6 +137,7 @@ func_add(struct tracepoint_func **funcs, struct > tracepoint_func *tp_func, > { > struct tracepoint_func *old, *new; > int nr_probes = 0; > + int stub_funcs = 0; > int pos = -1; > > if (WARN_ON(!tp_func->func)) > @@ -147,14 +154,34 @@ func_add(struct tracepoint_func **funcs, struct > tracepoint_func *tp_func, > if (old[nr_probes].func == tp_func->func && > old[nr_probes].data == tp_func->data) > return ERR_PTR(-EEXIST); > + if (old[nr_probes].func == tp_stub_func) > + stub_funcs++; > } > } > - /* + 2 : one for new probe, one for NULL func */ > - new = allocate_probes(nr_probes + 2); > + /* + 2 : one for new probe, one for NULL func - stub functions */ > + new = allocate_probes(nr_probes + 2 - stub_funcs); > if (new == NULL) > return ERR_PTR(-ENOMEM); > if (old) { > - if (pos < 0) { > + if (stub_funcs) { > + /* Need to copy one at a time to remove stubs */ > + int probes = 0; > + > + pos = -1; > + for (nr_probes = 0; old[nr_probes].func; nr_probes++) { > + if (old[nr_probes].func == tp_stub_func) > + continue; > + if (pos < 0 && old[nr_probes].prio < prio) > + pos = probes++; > + new[probes++] = old[nr_probes]; > + } &g
Re: [PATCH] bpf: don't fail kmalloc while releasing raw_tp
On Tue, Nov 17, 2020 at 06:05:51PM -0500, Mathieu Desnoyers wrote: > - On Nov 16, 2020, at 5:10 PM, rostedt rost...@goodmis.org wrote: > > > On Mon, 16 Nov 2020 16:34:41 -0500 (EST) > > Mathieu Desnoyers wrote: > > [...] > > >> I think you'll want a WRITE_ONCE(old[i].func, tp_stub_func) here, matched > >> with a READ_ONCE() in __DO_TRACE. This introduces a new situation where the > >> func pointer can be updated and loaded concurrently. > > > > I thought about this a little, and then only thing we really should worry > > about is synchronizing with those that unregister. Because when we make > > this update, there are now two states. the __DO_TRACE either reads the > > original func or the stub. And either should be OK to call. > > > > Only the func gets updated and not the data. So what exactly are we worried > > about here? > > Indeed with a stub function, I don't see any need for READ_ONCE/WRITE_ONCE. I'm not sure if this is a practical issue, but without WRITE_ONCE, can't the write be torn? A racing __traceiter_ could potentially see a half-modified function pointer, which wouldn't work out too well. This was actually my gut instinct before I wrote the __GFP_NOFAIL instead -- currently that whole array's memory ordering is provided by RCU and I didn't dive deep enough to evaluate getting too clever with atomic modifications to it. > > However, if we want to compare the function pointer to some other value and > conditionally do (or skip) the call, I think you'll need the > READ_ONCE/WRITE_ONCE > to make sure the pointer is not re-fetched between comparison and call. > > Thanks, > > Mathieu > > -- > Mathieu Desnoyers > EfficiOS Inc. > http://www.efficios.com
[PATCH] bpf: don't fail kmalloc while releasing raw_tp
bpf_link_free is always called in process context, including from a workqueue and from __fput. Neither of these have the ability to propagate an -ENOMEM to the caller. Reported-by: syzbot+83aa762ef23b6f0d1...@syzkaller.appspotmail.com Reported-by: syzbot+d29e58bb557324e55...@syzkaller.appspotmail.com Signed-off-by: Matt Mullins --- I previously referenced a "pretty ugly" patch. This is not that one, because I don't think there's any way I can make the caller of ->release() actually handle errors like ENOMEM. It also looks like most of the other ways tracepoint_probe_unregister is called also don't check the error code (e.g. just a quick grep found blk_unregister_tracepoints). Should this just be upgraded to GFP_NOFAIL across the board instead of passing around a gfp_t? include/linux/trace_events.h | 6 -- include/linux/tracepoint.h | 7 +-- kernel/bpf/syscall.c | 2 +- kernel/trace/bpf_trace.c | 6 -- kernel/trace/trace_events.c | 6 -- kernel/tracepoint.c | 20 ++-- 6 files changed, 28 insertions(+), 19 deletions(-) diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index 5c6943354049..166ad7646a98 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -625,7 +625,8 @@ int perf_event_attach_bpf_prog(struct perf_event *event, struct bpf_prog *prog); void perf_event_detach_bpf_prog(struct perf_event *event); int perf_event_query_prog_array(struct perf_event *event, void __user *info); int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog); -int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog); +int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog, +gfp_t flags); struct bpf_raw_event_map *bpf_get_raw_tracepoint(const char *name); void bpf_put_raw_tracepoint(struct bpf_raw_event_map *btp); int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id, @@ -654,7 +655,8 @@ static inline int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_p { return -EOPNOTSUPP; } -static inline int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *p) +static inline int bpf_probe_unregister(struct bpf_raw_event_map *btp, + struct bpf_prog *p, gfp_t flags) { return -EOPNOTSUPP; } diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 598fec9f9dbf..7b02f92f3b8f 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -12,6 +12,7 @@ * Heavily inspired from the Linux Kernel Markers. */ +#include #include #include #include @@ -40,7 +41,8 @@ extern int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, int prio); extern int -tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data); +tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data, + gfp_t flags); extern void for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), void *priv); @@ -260,7 +262,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) unregister_trace_##name(void (*probe)(data_proto), void *data) \ { \ return tracepoint_probe_unregister(&__tracepoint_##name,\ - (void *)probe, data); \ + (void *)probe, data,\ + GFP_KERNEL);\ } \ static inline void \ check_trace_callback_type_##name(void (*cb)(data_proto))\ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index b999e7ff2583..f6876681c4ab 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2601,7 +2601,7 @@ static void bpf_raw_tp_link_release(struct bpf_link *link) struct bpf_raw_tp_link *raw_tp = container_of(link, struct bpf_raw_tp_link, link); - bpf_probe_unregister(raw_tp->btp, raw_tp->link.prog); + bpf_probe_unregister(raw_tp->btp, raw_tp->link.prog, GFP_KERNEL | __GFP_NOFAIL); bpf_put_raw_tracepoint(raw_tp->btp); } diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index a8d4f253ed77..a4ea58c7506d 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1955,9 +1955,11 @@ int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog) return __bpf_probe_register(btp, prog); } -int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog) +int bpf_probe_unregister(struc
Re: KASAN: vmalloc-out-of-bounds Read in bpf_trace_run3
On Wed, Nov 11, 2020 at 03:57:50PM +0100, Dmitry Vyukov wrote: > On Mon, Nov 2, 2020 at 12:54 PM syzbot > wrote: > > > > Hello, > > > > syzbot found the following issue on: > > > > HEAD commit:080b6f40 bpf: Don't rely on GCC __attribute__((optimize)) .. > > git tree: bpf > > console output: https://syzkaller.appspot.com/x/log.txt?x=1089d37c50 > > kernel config: https://syzkaller.appspot.com/x/.config?x=58a4ca757d776bfe > > dashboard link: https://syzkaller.appspot.com/bug?extid=d29e58bb557324e55e5e > > compiler: gcc (GCC) 10.1.0-syz 20200507 > > syz repro: https://syzkaller.appspot.com/x/repro.syz?x=10f4b03250 > > C reproducer: https://syzkaller.appspot.com/x/repro.c?x=1371a47c50 > > > > The issue was bisected to: > > > > commit 9df1c28bb75217b244257152ab7d788bb2a386d0 > > Author: Matt Mullins > > Date: Fri Apr 26 18:49:47 2019 + > > > > bpf: add writable context for raw tracepoints > > > We have a number of kernel memory corruptions related to bpf_trace_run now: > https://groups.google.com/g/syzkaller-bugs/search?q=kernel%2Ftrace%2Fbpf_trace.c > > Can raw tracepoints "legally" corrupt kernel memory (a-la /dev/kmem)? > Or they shouldn't? > > Looking at the description of Matt's commit, it seems that corruptions > should not be possible (bounded buffer, checked size, etc). Then it > means it's a real kernel bug? This bug doesn't seem to be related to the writability of the tracepoint; it bisected to that commit simply because it used BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE for the reproducer and it EINVAL's before that program type was introduced. The BPF program it loads is pretty much a no-op. The problem here is a kmalloc failure injection into tracepoint_probe_unregister, but the error is ignored -- so the bpf program is freed even though the tracepoint is never unregistered. I have a first pass at a patch to pipe through the error code, but it's pretty ugly. It's also called from the file_operations ->release(), for which errors are solidly ignored in __fput(), so I'm not sure what the best way to handle ENOMEM is... > > > > > bisection log: https://syzkaller.appspot.com/x/bisect.txt?x=12b6c4da50 > > final oops: https://syzkaller.appspot.com/x/report.txt?x=11b6c4da50 > > console output: https://syzkaller.appspot.com/x/log.txt?x=16b6c4da50 > > > > IMPORTANT: if you fix the issue, please add the following tag to the commit: > > Reported-by: syzbot+d29e58bb557324e55...@syzkaller.appspotmail.com > > Fixes: 9df1c28bb752 ("bpf: add writable context for raw tracepoints") > > > > == > > BUG: KASAN: vmalloc-out-of-bounds in __bpf_trace_run > > kernel/trace/bpf_trace.c:2045 [inline] > > BUG: KASAN: vmalloc-out-of-bounds in bpf_trace_run3+0x3e0/0x3f0 > > kernel/trace/bpf_trace.c:2083 > > Read of size 8 at addr c9e6c030 by task kworker/0:3/3754 > > > > CPU: 0 PID: 3754 Comm: kworker/0:3 Not tainted 5.9.0-syzkaller #0 > > Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS > > Google 01/01/2011 > > Workqueue: 0x0 (events) > > Call Trace: > > __dump_stack lib/dump_stack.c:77 [inline] > > dump_stack+0x107/0x163 lib/dump_stack.c:118 > > print_address_description.constprop.0.cold+0x5/0x4c8 mm/kasan/report.c:385 > > __kasan_report mm/kasan/report.c:545 [inline] > > kasan_report.cold+0x1f/0x37 mm/kasan/report.c:562 > > __bpf_trace_run kernel/trace/bpf_trace.c:2045 [inline] > > bpf_trace_run3+0x3e0/0x3f0 kernel/trace/bpf_trace.c:2083 > > __bpf_trace_sched_switch+0xdc/0x120 include/trace/events/sched.h:138 > > __traceiter_sched_switch+0x64/0xb0 include/trace/events/sched.h:138 > > trace_sched_switch include/trace/events/sched.h:138 [inline] > > __schedule+0xeb8/0x2130 kernel/sched/core.c:4520 > > schedule+0xcf/0x270 kernel/sched/core.c:4601 > > worker_thread+0x14c/0x1120 kernel/workqueue.c:2439 > > kthread+0x3af/0x4a0 kernel/kthread.c:292 > > ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:296 > > > > > > Memory state around the buggy address: > > c9e6bf00: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 > > c9e6bf80: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 > > >c9e6c000: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 > > ^ > > c9e6c080: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 > > c9e6c100: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
Re: [PATCH] hwmon: applesmc: avoid overlong udelay()
On my late 2013 Macbook Pro, I have a couple of scripts that set the fans to auto or full-speed: fan-hi: #!/bin/sh sudo sh -c 'echo 1 > /sys/devices/platform/applesmc.768/fan1_manual echo 1 > /sys/devices/platform/applesmc.768/fan2_manual cat /sys/devices/platform/applesmc.768/fan1_max > /sys/devices/platform/applesmc.768/fan1_output cat /sys/devices/platform/applesmc.768/fan2_max > /sys/devices/platform/applesmc.768/fan2_output' fan-auto: #!/bin/sh sudo sh -c 'echo 0 > /sys/devices/platform/applesmc.768/fan1_manual echo 0 > /sys/devices/platform/applesmc.768/fan2_manual' Running ./fan-hi and then ./fan-auto on Linux v5.6 works and doesn't cause any problems, but after updating to v5.9 I see this in dmesg: [Nov 6 17:24] applesmc: send_byte(0x01, 0x0300) fail: 0x40 [ +0.05] applesmc: FS! : write data fail [ +0.191777] applesmc: send_byte(0x30, 0x0300) fail: 0x40 [ +0.09] applesmc: F0Tg: write data fail [ +7.097416] applesmc: send_byte(0x00, 0x0300) fail: 0x40 [ +0.06] applesmc: FS! : write data fail and the fan controls don't work. Googling turned up this [1] which looks like the same problem. They said it began occurring between v5.7 and v5.8, so I looked and found this commit. After reverting commit fff2d0f701e6753591609739f8ab9be1c8e80ebb from v5.9, I no longer see the errors in dmesg and the fan controls work again. Any ideas what the problem is? Thanks, Matt [1] https://stackoverflow.com/questions/63505469/cant-write-data-to-applesmc-error-after-upgrade-to-arch-linux-kernel-5-8-1 signature.asc Description: PGP signature
Re: [PATCH] iio: light: apds9960: remove unneeded semicolon
On Tue, Oct 27, 2020 at 1:14 PM wrote: > > From: Tom Rix > > A semicolon is not needed after a switch statement. > Acked-by: Matt Ranostay > Signed-off-by: Tom Rix > --- > drivers/iio/light/apds9960.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c > index 9afb3fcc74e6..547e7f9d6920 100644 > --- a/drivers/iio/light/apds9960.c > +++ b/drivers/iio/light/apds9960.c > @@ -561,7 +561,7 @@ static int apds9960_write_raw(struct iio_dev *indio_dev, > } > default: > return -EINVAL; > - }; > + } > > return 0; > } > -- > 2.18.1 >
Re: [PATCH] iio: proximity: as3935 change of_property_read to device_property_read
On Fri, Oct 16, 2020 at 11:41 AM Vaishnav M A wrote: > > > This patch aims to replace the of_property_read_u32 for reading > the ams,tuning-capacitor-pf, ams,nflwdth properties with > device_property_read_u32. > > Thanks and Regards, > Vaishnav M A Could you explain a bit more in the commit message why this is needed? Also you pop comments that shouldn't be in the commit message below the "---" line :) > > Signed-off-by: Vaishnav M A > --- > drivers/iio/proximity/as3935.c | 5 ++--- > 1 file changed, 2 insertions(+), 3 deletions(-) > > diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c > index c339e7339ec8..7e47ddf89a56 100644 > --- a/drivers/iio/proximity/as3935.c > +++ b/drivers/iio/proximity/as3935.c > @@ -355,7 +355,6 @@ static int as3935_probe(struct spi_device *spi) > struct iio_dev *indio_dev; > struct iio_trigger *trig; > struct as3935_state *st; > - struct device_node *np = spi->dev.of_node; > int ret; > > /* Be sure lightning event interrupt is specified */ > @@ -374,7 +373,7 @@ static int as3935_probe(struct spi_device *spi) > spi_set_drvdata(spi, indio_dev); > mutex_init(&st->lock); > > - ret = of_property_read_u32(np, > + ret = device_property_read_u32(&spi->dev, > "ams,tuning-capacitor-pf", &st->tune_cap); > if (ret) { > st->tune_cap = 0; > @@ -390,7 +389,7 @@ static int as3935_probe(struct spi_device *spi) > return -EINVAL; > } > > - ret = of_property_read_u32(np, > + ret = device_property_read_u32(&spi->dev, > "ams,nflwdth", &st->nflwdth_reg); > if (!ret && st->nflwdth_reg > AS3935_NFLWDTH_MASK) { > dev_err(&spi->dev, > -- > 2.25.1 >
Re: [Intel-gfx] [PATCH 2/2] drm/i915/edp/jsl: Update vswing table for HBR and HBR2
On Mon, Sep 28, 2020 at 04:07:39PM -0700, Lucas De Marchi wrote: > On Mon, Sep 28, 2020 at 08:15:29PM +0300, Jani Nikula wrote: > > On Mon, 28 Sep 2020, "Surendrakumar Upadhyay, TejaskumarX" > > wrote: > > > This is a good example of a potential trap that having > > > IS_ELKHARTLAKE() cover both ELK and JSP creates. An unsuspecting coder > > > might change the if ladder to have IS_ELKHARTLAKE() first, and the > > > subsequent IS_JASPERLAKE() branch would never be taken. > > > > > > BR, > > > Jani. > > > > > > Tejas : In that case I will put attention note in comment about > > > platform checks such that ladder distrubance can be avoided. What you > > > suggest? > > > The solution is to make IS_ELKHARTLAKE() mean ELK and only ELK. > > Since we are talking about the TLA for JSL in the other patch, for > elkhartlake it is EHL, not ELK. ELK is something else, but I'm not sure > what: > > $ git grep -w ELK -- drivers/gpu/drm/ > drivers/gpu/drm/i915/gem/i915_gem_stolen.c: IS_GM45(i915) ? "CTG" > : "ELK", reg_val); > drivers/gpu/drm/i915/gem/i915_gem_stolen.c: * Whether ILK really reuses > the ELK register for this is unclear. > drivers/gpu/drm/i915/intel_pm.c: * Not 100% sure which way ELK should > go here as the > drivers/gpu/drm/i915/intel_pm.c: * assume ELK doesn't need this. Yeah, ELK = Eagle Lake, CTG = Cantiga. Both are old gen5 platforms IIRC. Matt > > Lucas De Marchi > > > > > BR, > > Jani. > > > > > > -- > > Jani Nikula, Intel Open Source Graphics Center -- Matt Roper Graphics Software Engineer VTT-OSGC Platform Enablement Intel Corporation (916) 356-2795
Re: [PATCH 1/2] drm/i915/jsl: Split EHL/JSL platform info and PCI ids
On Mon, Sep 28, 2020 at 08:14:02PM +0300, Jani Nikula wrote: > On Mon, 28 Sep 2020, "Surendrakumar Upadhyay, TejaskumarX" > wrote: > > > > From: Jani Nikula > > Sent: Monday, September 28, 2020 7:07 PM > > To: Surendrakumar Upadhyay, TejaskumarX > > ; Vivi, Rodrigo > > ; airl...@linux.ie ; > > dan...@ffwll.ch ; intel-...@lists.freedesktop.org > > ; dri-de...@lists.freedesktop.org > > ; linux-kernel@vger.kernel.org > > ; Ausmus, James ; > > Roper, Matthew D ; Souza, Jose > > ; ville.syrj...@linux.intel.com > > ; De Marchi, Lucas > > ; Pandey, Hariom > > Subject: Re: [PATCH 1/2] drm/i915/jsl: Split EHL/JSL platform info and PCI > > ids > > Please fix your email quoting when interacting on the public lists. > > > > > On Mon, 28 Sep 2020, Tejas Upadhyay > > wrote: > >> Split the basic platform definition, macros, and PCI IDs to > >> differentiate between EHL and JSL platforms. > >> > >> Signed-off-by: Tejas Upadhyay > >> > >> --- > >> drivers/gpu/drm/i915/i915_drv.h | 4 +++- > >> drivers/gpu/drm/i915/i915_pci.c | 9 + > >> drivers/gpu/drm/i915/intel_device_info.c | 1 + > >> drivers/gpu/drm/i915/intel_device_info.h | 1 + > >> include/drm/i915_pciids.h| 9 ++--- > >> 5 files changed, 20 insertions(+), 4 deletions(-) > >> > >> diff --git a/drivers/gpu/drm/i915/i915_drv.h > >> b/drivers/gpu/drm/i915/i915_drv.h > >> index 72a9449b674e..4f20acebb038 100644 > >> --- a/drivers/gpu/drm/i915/i915_drv.h > >> +++ b/drivers/gpu/drm/i915/i915_drv.h > >> @@ -1417,7 +1417,9 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, > >> #define IS_COMETLAKE(dev_priv) IS_PLATFORM(dev_priv, > >> INTEL_COMETLAKE) > >> #define IS_CANNONLAKE(dev_priv) IS_PLATFORM(dev_priv, > >> INTEL_CANNONLAKE) > >> #define IS_ICELAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ICELAKE) > >> -#define IS_ELKHARTLAKE(dev_priv) IS_PLATFORM(dev_priv, > >> INTEL_ELKHARTLAKE) > >> +#define IS_ELKHARTLAKE(dev_priv) (IS_PLATFORM(dev_priv, > >> INTEL_ELKHARTLAKE) || \ > >> + IS_PLATFORM(dev_priv, INTEL_JASPERLAKE)) > >> +#define IS_JASPERLAKE(dev_priv) IS_PLATFORM(dev_priv, > >> INTEL_JASPERLAKE) > > > > I think we've learned from history that we want the platform checks to > > be independent. I.e. if you need to split ELK and JSP, you need to make > > IS_ELKHARTLAKE() match *only* ELK, and you need to replace every current > > IS_ELKHARTLAKE() check with IS_ELKHARTLAKE() || IS_JASPERLAKE(). > > > > We've been here before, and we've thought before that we can get by with > > the minimal change. It's just postponing the inevitable and generates > > confusion. > > > > BR, > > Jani. > > > > Tejas : Replacing IS_ELKHARTLAKE() || IS_JASPERLAKE() everywhere will > > make lot of changes at each place. To avoid huge change and to > > differentiate between platforms we have taken this way. Do you think > > we still change it everywhere? Do you have example where it can harm > > this change? > > If you need to differentiate between the two platforms, IS_ELKHARTLAKE() > must mean only ELK and IS_JASPERLAKE() must mean only JSP. > > It's non-negotiable. We've made the mistake before, we're not doing it > again. > > There are 32 references to IS_ELKHARTLAKE(). It's slightly painful, but > the alternative is worse. Why are we adding IS_JASPERLAKE at all? EHL/JSL are documented as the same graphics IP, but are paired with different PCHs in the final SoCs, which is what causes the minor differences in programming. My understanding is that the voltage programming differences are ultimately due to that difference in PCH so we should just use HAS_PCH_MCC (EHL) and HAS_PCH_JSP (JSL) to distinguish which type of programming is needed rather than using a platform test. Matt > > > BR, > Jani. > > > > > >> #define IS_TIGERLAKE(dev_priv) IS_PLATFORM(dev_priv, > >> INTEL_TIGERLAKE) > >> #define IS_ROCKETLAKE(dev_priv) IS_PLATFORM(dev_priv, > >> INTEL_ROCKETLAKE) > >> #define IS_DG1(dev_priv)IS_PLATFORM(dev_priv, INTEL_DG1) > >> diff --git a/drivers/gpu/drm/i915/i915_pci.c > >> b/drivers/gpu/drm/i915/i915_pci.c > >> index 366ddfc8df6b..8690b69fcf33 100644 > >> --- a/drivers/gpu/drm/i915/i915_p
Re: [PATCH v3 02/23] alpha: use asm-generic/mmu_context.h for no-op implementations
On Tue, Sep 1, 2020 at 7:15 AM Nicholas Piggin wrote: > > Cc: Richard Henderson > Cc: Ivan Kokshaysky > Cc: Matt Turner > Cc: linux-al...@vger.kernel.org > Signed-off-by: Nicholas Piggin > --- > > Please ack or nack if you object to this being mered via > Arnd's tree. That would be great. Acked-by: Matt Turner
Re: [PATCH 5.4 047/215] iio:humidity:hdc100x Fix alignment and data leak issues
On Mon, Jul 20, 2020 at 9:50 AM Joe Perches wrote: > > On Mon, 2020-07-20 at 17:35 +0200, Greg Kroah-Hartman wrote: > > From: Jonathan Cameron > > > > commit ea5e7a7bb6205d24371373cd80325db1bc15eded upstream. > > > > One of a class of bugs pointed out by Lars in a recent review. > > iio_push_to_buffers_with_timestamp assumes the buffer used is aligned > > to the size of the timestamp (8 bytes). This is not guaranteed in > > this driver which uses an array of smaller elements on the stack. > > As Lars also noted this anti pattern can involve a leak of data to > > userspace and that indeed can happen here. We close both issues by > > moving to a suitable structure in the iio_priv() data. > > This data is allocated with kzalloc so no data can leak apart > > from previous readings. > [] > > +++ b/drivers/iio/humidity/hdc100x.c > > @@ -38,6 +38,11 @@ struct hdc100x_data { > > > > /* integration time of the sensor */ > > int adc_int_us[2]; > > + /* Ensure natural alignment of timestamp */ > > + struct { > > + __be16 channels[2]; > > + s64 ts __aligned(8); > > Why does an s64 need __aligned(8) ? This is due to on 32-bit x86 it is aligned to 4 bytes by default. - Matt > This seems needlessly redundant. > > Isn't this naturally aligned by the compiler? > > The struct isn't packed. >
Re: [PATCH] drm/i915/display: Ensure that ret is always initialized in icl_combo_phy_verify_state
On Wed, Jul 15, 2020 at 09:27:42PM -0700, Nathan Chancellor wrote: > Clang warns: > > drivers/gpu/drm/i915/display/intel_combo_phy.c:268:3: warning: variable > 'ret' is uninitialized when used here [-Wuninitialized] > ret &= check_phy_reg(dev_priv, phy, ICL_PORT_TX_DW8_LN0(phy), > ^~~ > drivers/gpu/drm/i915/display/intel_combo_phy.c:261:10: note: initialize > the variable 'ret' to silence this warning > bool ret; > ^ > = 0 > 1 warning generated. > > In practice, the bug this warning appears to be concerned with would not > actually matter because ret gets initialized to the return value of > cnl_verify_procmon_ref_values. However, that does appear to be a bug > since it means the first hunk of the patch this fixes won't actually do > anything (since the values of check_phy_reg won't factor into the final > ret value). Initialize ret to true then make all of the assignments a > bitwise AND with itself so that the function always does what it should > do. > > Fixes: 239bef676d8e ("drm/i915/display: Implement new combo phy > initialization step") > Link: https://github.com/ClangBuiltLinux/linux/issues/1094 > Signed-off-by: Nathan Chancellor Reviewed-by: Matt Roper > --- > drivers/gpu/drm/i915/display/intel_combo_phy.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c > b/drivers/gpu/drm/i915/display/intel_combo_phy.c > index eccaa79cb4a9..a4b8aa6d0a9e 100644 > --- a/drivers/gpu/drm/i915/display/intel_combo_phy.c > +++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c > @@ -258,7 +258,7 @@ static bool phy_is_master(struct drm_i915_private > *dev_priv, enum phy phy) > static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv, > enum phy phy) > { > - bool ret; > + bool ret = true; > u32 expected_val = 0; > > if (!icl_combo_phy_enabled(dev_priv, phy)) > @@ -276,7 +276,7 @@ static bool icl_combo_phy_verify_state(struct > drm_i915_private *dev_priv, >DCC_MODE_SELECT_CONTINUOSLY); > } > > - ret = cnl_verify_procmon_ref_values(dev_priv, phy); > + ret &= cnl_verify_procmon_ref_values(dev_priv, phy); > > if (phy_is_master(dev_priv, phy)) { > ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW8(phy), > > base-commit: ca0e494af5edb59002665bf12871e94b4163a257 > -- > 2.28.0.rc0 > -- Matt Roper Graphics Software Engineer VTT-OSGC Platform Enablement Intel Corporation (916) 356-2795
Re: [PATCH 0/5] RFC: connector: Add network namespace awareness
On Tue, 2020-07-14 at 15:03 +1000, Aleksa Sarai wrote: > On 2020-07-13, Eric W. Biederman wrote: > > Matt Bennett writes: > > > > > On Thu, 2020-07-02 at 21:10 +0200, Christian Brauner wrote: > > > > On Thu, Jul 02, 2020 at 08:17:38AM -0500, Eric W. Biederman wrote: > > > > > Matt Bennett writes: > > > > > > > > > > > Previously the connector functionality could only be used by > > > > > > processes running in the > > > > > > default network namespace. This meant that any process that uses > > > > > > the connector functionality > > > > > > could not operate correctly when run inside a container. This is a > > > > > > draft patch series that > > > > > > attempts to now allow this functionality outside of the default > > > > > > network namespace. > > > > > > > > > > > > I see this has been discussed previously [1], but am not sure how > > > > > > my changes relate to all > > > > > > of the topics discussed there and/or if there are any unintended > > > > > > side effects from my draft > > > > > > changes. > > > > > > > > > > Is there a piece of software that uses connector that you want to get > > > > > working in containers? > > > > > > We have an IPC system [1] where processes can register their socket > > > details (unix, tcp, tipc, ...) to a 'monitor' process. Processes can > > > then get notified when other processes they are interested in > > > start/stop their servers and use the registered details to connect to > > > them. Everything works unless a process crashes, in which case the > > > monitoring process never removes their details. Therefore the > > > monitoring process uses the connector functionality with > > > PROC_EVENT_EXIT to detect when a process crashes and removes the > > > details if it is a previously registered PID. > > > > > > This was working for us until we tried to run our system in a container. > > > > > > > > > > > > > I am curious what the motivation is because up until now there has > > > > > been > > > > > nothing very interesting using this functionality. So it hasn't been > > > > > worth anyone's time to make the necessary changes to the code. > > > > > > > > Imho, we should just state once and for all that the proc connector will > > > > not be namespaced. This is such a corner-case thing and has been > > > > non-namespaced for such a long time without consistent push for it to be > > > > namespaced combined with the fact that this needs quite some code to > > > > make it work correctly that I fear we end up buying more bugs than we're > > > > selling features. And realistically, you and I will end up maintaining > > > > this and I feel this is not worth the time(?). Maybe I'm being too > > > > pessimistic though. > > > > > > > > > > Fair enough. I can certainly look for another way to detect process > > > crashes. Interestingly I found a patch set [2] on the mailing list > > > that attempts to solve the problem I wish to solve, but it doesn't > > > look like the patches were ever developed further. From reading the > > > discussion thread on that patch set it appears that I should be doing > > > some form of polling on the /proc files. > > > > Recently Christian Brauner implemented pidfd complete with a poll > > operation that reports when a process terminates. > > > > If you are willing to change your userspace code switching to pidfd > > should be all that you need. > > While this does solve the problem of getting exit notifications in > general, you cannot get the exit code. But if they don't care about that > then we can solve that problem another time. :D > From first glance using pidfd will do exactly what we need. Not being able to get the exit code will not be an issue. In fact I think it will be an improvement over the connector as the listener will now only be waiting for the PIDs we actually care about - rather than getting woken up on every single process exit and having to check if it cares about the PID. Many thanks Eric and others, Matt
Re: [PATCH 0/5] RFC: connector: Add network namespace awareness
On Thu, 2020-07-02 at 21:10 +0200, Christian Brauner wrote: > On Thu, Jul 02, 2020 at 08:17:38AM -0500, Eric W. Biederman wrote: > > Matt Bennett writes: > > > > > Previously the connector functionality could only be used by processes > > > running in the > > > default network namespace. This meant that any process that uses the > > > connector functionality > > > could not operate correctly when run inside a container. This is a draft > > > patch series that > > > attempts to now allow this functionality outside of the default network > > > namespace. > > > > > > I see this has been discussed previously [1], but am not sure how my > > > changes relate to all > > > of the topics discussed there and/or if there are any unintended side > > > effects from my draft > > > changes. > > > > Is there a piece of software that uses connector that you want to get > > working in containers? We have an IPC system [1] where processes can register their socket details (unix, tcp, tipc, ...) to a 'monitor' process. Processes can then get notified when other processes they are interested in start/stop their servers and use the registered details to connect to them. Everything works unless a process crashes, in which case the monitoring process never removes their details. Therefore the monitoring process uses the connector functionality with PROC_EVENT_EXIT to detect when a process crashes and removes the details if it is a previously registered PID. This was working for us until we tried to run our system in a container. > > > > I am curious what the motivation is because up until now there has been > > nothing very interesting using this functionality. So it hasn't been > > worth anyone's time to make the necessary changes to the code. > > Imho, we should just state once and for all that the proc connector will > not be namespaced. This is such a corner-case thing and has been > non-namespaced for such a long time without consistent push for it to be > namespaced combined with the fact that this needs quite some code to > make it work correctly that I fear we end up buying more bugs than we're > selling features. And realistically, you and I will end up maintaining > this and I feel this is not worth the time(?). Maybe I'm being too > pessimistic though. > Fair enough. I can certainly look for another way to detect process crashes. Interestingly I found a patch set [2] on the mailing list that attempts to solve the problem I wish to solve, but it doesn't look like the patches were ever developed further. From reading the discussion thread on that patch set it appears that I should be doing some form of polling on the /proc files. Best regards, Matt [1] https://github.com/alliedtelesis/cmsg/blob/master/cmsg/src/service_listener/netlink.c#L61 [2] https://lkml.org/lkml/2018/10/29/638
Re: [PATCH 0/5] RFC: connector: Add network namespace awareness
On Thu, 2020-07-02 at 13:59 -0500, Eric W. Biederman wrote: > Matt Bennett writes: > > > Previously the connector functionality could only be used by processes > > running in the > > default network namespace. This meant that any process that uses the > > connector functionality > > could not operate correctly when run inside a container. This is a draft > > patch series that > > attempts to now allow this functionality outside of the default network > > namespace. > > > > I see this has been discussed previously [1], but am not sure how my > > changes relate to all > > of the topics discussed there and/or if there are any unintended side > > effects from my draft > > In a quick skim this patchset does not look like it approaches a correct > conversion to having code that works in multiple namespaces. > > I will take the changes to proc_id_connector for example. > You report the values in the callers current namespaces. > > Which means an unprivileged user can create a user namespace and get > connector to report whichever ids they want to users in another > namespace. AKA lie. > > So this appears to make connector completely unreliable. > > Eric > Hi Eric, Thank you for taking the time to review. I wrote these patches in an attempt to show that I was willing to do the work myself rather than simply asking for someone else to do it for me. The changes worked for my use cases when I tested them, but I expected that some of the changes would be incorrect and that I would need some guidance. I can spend some time to really dig in and fully understand the changes I am trying to make (I have limited kernel development experience) but based on the rest of the discussion threads it seems that there is likely no appetite to ever support namespaces with the connector. Best regards, Matt
Re: [PATCH v2] Replace HTTP links with HTTPS ones: Documentation/devicetree/bindings/iio
On Sat, Jul 4, 2020 at 12:34 PM Alexander A. Klimov wrote: > > Rationale: > Reduces attack surface on kernel devs opening the links for MITM > as HTTPS traffic is much harder to manipulate. > With regards to the drivers that I've authored the changes look good to me. Reviewed-by: Matt Ranostay > Deterministic algorithm: > For each file: > If not .svg: > For each line: > If doesn't contain `\bxmlns\b`: > For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: > If both the HTTP and HTTPS versions > return 200 OK and serve the same content: > Replace HTTP with HTTPS. > > Signed-off-by: Alexander A. Klimov > --- > Changes in v2: > Addressed > https://lore.kernel.org/linux-iio/20200704173459.78ceec60@archlinux/ > > Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml | 4 ++-- > Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt | 2 +- > Documentation/devicetree/bindings/iio/iio-bindings.txt| 2 +- > Documentation/devicetree/bindings/iio/light/apds9300.txt | 2 +- > Documentation/devicetree/bindings/iio/light/apds9960.txt | 2 +- > Documentation/devicetree/bindings/iio/light/opt3001.txt | 2 +- > Documentation/devicetree/bindings/iio/light/vl6180.txt| 2 +- > .../devicetree/bindings/iio/potentiometer/mcp41010.txt| 2 +- > .../devicetree/bindings/iio/potentiostat/lmp91000.txt | 4 ++-- > .../devicetree/bindings/iio/pressure/asc,dlhl60d.yaml | 2 +- > .../devicetree/bindings/iio/proximity/devantech-srf04.yaml| 4 ++-- > 11 files changed, 14 insertions(+), 14 deletions(-) > > diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml > b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml > index d124eba1ce54..fd4eaa3d0ab4 100644 > --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml > +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml > @@ -12,8 +12,8 @@ maintainers: > description: | >Analog Devices ADXL345/ADXL375 3-Axis Digital Accelerometers that supports >both I2C & SPI interfaces. > -http://www.analog.com/en/products/mems/accelerometers/adxl345.html > - > http://www.analog.com/en/products/sensors-mems/accelerometers/adxl375.html > +https://www.analog.com/en/products/mems/accelerometers/adxl345.html > + > https://www.analog.com/en/products/sensors-mems/accelerometers/adxl375.html > > properties: >compatible: > diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt > b/Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt > index 639c94ed83e9..17af395b99d9 100644 > --- a/Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt > +++ b/Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt > @@ -6,7 +6,7 @@ Is is programmable through an SPI interface. > > The internal DACs are loaded when the LOADDACS pin is pulled down. > > -http://www.ti.com/lit/ds/sbas106/sbas106.pdf > +https://www.ti.com/lit/ds/sbas106/sbas106.pdf > > Required Properties: > - compatible: Should be one of: > diff --git a/Documentation/devicetree/bindings/iio/iio-bindings.txt > b/Documentation/devicetree/bindings/iio/iio-bindings.txt > index af33267727f4..aa63cac7323e 100644 > --- a/Documentation/devicetree/bindings/iio/iio-bindings.txt > +++ b/Documentation/devicetree/bindings/iio/iio-bindings.txt > @@ -9,7 +9,7 @@ specifier is an array of one or more cells identifying the IIO > output on a device. The length of an IIO specifier is defined by the > value of a #io-channel-cells property in the IIO provider node. > > -[1] http://marc.info/?l=linux-iio&m=135902119507483&w=2 > +[1] https://marc.info/?l=linux-iio&m=135902119507483&w=2 > > ==IIO providers== > > diff --git a/Documentation/devicetree/bindings/iio/light/apds9300.txt > b/Documentation/devicetree/bindings/iio/light/apds9300.txt > index aa199e09a493..3aa6db3ee99d 100644 > --- a/Documentation/devicetree/bindings/iio/light/apds9300.txt > +++ b/Documentation/devicetree/bindings/iio/light/apds9300.txt > @@ -1,6 +1,6 @@ > * Avago APDS9300 ambient light sensor > > -http://www.avagotech.com/docs/AV02-1077EN > +https://www.avagotech.com/docs/AV02-1077EN > > Required properties: > > diff --git a/Documentation/devicetree/bindings/iio/light/apds9960.txt > b/Documentation/devicetree/bindings/iio/light/apds9960.txt > index 3af325ad194b..c53ddb81c4aa 100644 > --- a/Documentation/devicetree/bindings/iio/light/apds9960.txt > +++ b/Documentation/devicetree/bindings/iio/light/apds9960.txt > @@ -1,6 +1,6 @@ > * Avago APDS9960 gesture/RGB/ALS/proximity sensor > > -http://www.avagotech.com/docs/AV02-4191EN > +https://www
[PATCH 1/5] connector: Use task pid helpers
In preparation for supporting the connector outside of the default network namespace we switch to using these helpers now. As the connector is still only supported in the default namespace this change is a no-op. Signed-off-by: Matt Bennett --- drivers/connector/cn_proc.c | 48 ++--- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 646ad385e490..36a7823c56ec 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -83,11 +83,11 @@ void proc_fork_connector(struct task_struct *task) ev->what = PROC_EVENT_FORK; rcu_read_lock(); parent = rcu_dereference(task->real_parent); - ev->event_data.fork.parent_pid = parent->pid; - ev->event_data.fork.parent_tgid = parent->tgid; + ev->event_data.fork.parent_pid = task_pid_vnr(parent); + ev->event_data.fork.parent_tgid = task_tgid_vnr(parent); rcu_read_unlock(); - ev->event_data.fork.child_pid = task->pid; - ev->event_data.fork.child_tgid = task->tgid; + ev->event_data.fork.child_pid = task_pid_vnr(task); + ev->event_data.fork.child_tgid = task_tgid_vnr(task); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ @@ -110,8 +110,8 @@ void proc_exec_connector(struct task_struct *task) memset(&ev->event_data, 0, sizeof(ev->event_data)); ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_EXEC; - ev->event_data.exec.process_pid = task->pid; - ev->event_data.exec.process_tgid = task->tgid; + ev->event_data.exec.process_pid = task_pid_vnr(task); + ev->event_data.exec.process_tgid = task_tgid_vnr(task); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ @@ -134,8 +134,8 @@ void proc_id_connector(struct task_struct *task, int which_id) ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); ev->what = which_id; - ev->event_data.id.process_pid = task->pid; - ev->event_data.id.process_tgid = task->tgid; + ev->event_data.id.process_pid = task_pid_vnr(task); + ev->event_data.id.process_tgid = task_tgid_vnr(task); rcu_read_lock(); cred = __task_cred(task); if (which_id == PROC_EVENT_UID) { @@ -172,8 +172,8 @@ void proc_sid_connector(struct task_struct *task) memset(&ev->event_data, 0, sizeof(ev->event_data)); ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_SID; - ev->event_data.sid.process_pid = task->pid; - ev->event_data.sid.process_tgid = task->tgid; + ev->event_data.sid.process_pid = task_pid_vnr(task); + ev->event_data.sid.process_tgid = task_tgid_vnr(task); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ @@ -196,11 +196,11 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id) memset(&ev->event_data, 0, sizeof(ev->event_data)); ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_PTRACE; - ev->event_data.ptrace.process_pid = task->pid; - ev->event_data.ptrace.process_tgid = task->tgid; + ev->event_data.ptrace.process_pid = task_pid_vnr(task); + ev->event_data.ptrace.process_tgid = task_tgid_vnr(task); if (ptrace_id == PTRACE_ATTACH) { - ev->event_data.ptrace.tracer_pid = current->pid; - ev->event_data.ptrace.tracer_tgid = current->tgid; + ev->event_data.ptrace.tracer_pid = task_pid_vnr(current); + ev->event_data.ptrace.tracer_tgid = task_tgid_vnr(current); } else if (ptrace_id == PTRACE_DETACH) { ev->event_data.ptrace.tracer_pid = 0; ev->event_data.ptrace.tracer_tgid = 0; @@ -228,8 +228,8 @@ void proc_comm_connector(struct task_struct *task) memset(&ev->event_data, 0, sizeof(ev->event_data)); ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_COMM; - ev->event_data.comm.process_pid = task->pid; - ev->event_data.comm.process_tgid = task->tgid; + ev->event_data.comm.process_pid = task_pid_vnr(task); + ev->event_data.comm.process_tgid = task_tgid_vnr(task); get_task_comm(ev->event_data.comm.comm, task); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); @@ -254,14 +254,14 @@ void proc_coredump_connector(struct task_struct *task) memset(&ev->event_data, 0, sizeof(ev->event_data)); ev->timestamp_ns = ktime_get_ns(); ev
[PATCH 5/5] connector: Create connector per namespace
Move to storing the connector instance per network namespace. In doing so the ability to use the connector functionality outside the default namespace is now available. Signed-off-by: Matt Bennett --- drivers/connector/cn_proc.c | 49 ++ drivers/connector/connector.c | 171 -- drivers/hv/hv_fcopy.c | 1 + include/linux/connector.h | 14 ++- include/net/net_namespace.h | 4 + kernel/exit.c | 2 +- 6 files changed, 190 insertions(+), 51 deletions(-) diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 9202be177a30..661d921fd146 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,6 @@ static inline struct cn_msg *buffer_to_cn_msg(__u8 *buffer) return (struct cn_msg *)(buffer + 4); } -static atomic_t proc_event_num_listeners = ATOMIC_INIT(0); static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC }; /* local_event.count is used as the sequence number of the netlink message */ @@ -51,6 +51,9 @@ static DEFINE_PER_CPU(struct local_event, local_event) = { static inline void send_msg(struct cn_msg *msg) { + int ret = 0; + struct net *net = current->nsproxy->net_ns; + local_lock(&local_event.lock); msg->seq = __this_cpu_inc_return(local_event.count) - 1; @@ -62,7 +65,9 @@ static inline void send_msg(struct cn_msg *msg) * * If cn_netlink_send() fails, the data is not sent. */ - cn_netlink_send(&init_net, msg, 0, CN_IDX_PROC, GFP_NOWAIT); + ret = cn_netlink_send(net, msg, 0, CN_IDX_PROC, GFP_NOWAIT); + if (ret == -ESRCH && netlink_has_listeners(net->cdev.nls, CN_IDX_PROC) == 0) + atomic_set(&(net->cdev.proc_event_num_listeners), 0); local_unlock(&local_event.lock); } @@ -73,8 +78,9 @@ void proc_fork_connector(struct task_struct *task) struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); struct task_struct *parent; + struct net *net = current->nsproxy->net_ns; - if (atomic_read(&proc_event_num_listeners) < 1) + if (atomic_read(&(net->cdev.proc_event_num_listeners)) < 1) return; msg = buffer_to_cn_msg(buffer); @@ -102,8 +108,9 @@ void proc_exec_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + struct net *net = current->nsproxy->net_ns; - if (atomic_read(&proc_event_num_listeners) < 1) + if (atomic_read(&(net->cdev.proc_event_num_listeners)) < 1) return; msg = buffer_to_cn_msg(buffer); @@ -127,8 +134,9 @@ void proc_id_connector(struct task_struct *task, int which_id) struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); const struct cred *cred; + struct net *net = current->nsproxy->net_ns; - if (atomic_read(&proc_event_num_listeners) < 1) + if (atomic_read(&(net->cdev.proc_event_num_listeners)) < 1) return; msg = buffer_to_cn_msg(buffer); @@ -164,8 +172,9 @@ void proc_sid_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + struct net *net = current->nsproxy->net_ns; - if (atomic_read(&proc_event_num_listeners) < 1) + if (atomic_read(&(net->cdev.proc_event_num_listeners)) < 1) return; msg = buffer_to_cn_msg(buffer); @@ -188,8 +197,9 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + struct net *net = current->nsproxy->net_ns; - if (atomic_read(&proc_event_num_listeners) < 1) + if (atomic_read(&(net->cdev.proc_event_num_listeners)) < 1) return; msg = buffer_to_cn_msg(buffer); @@ -220,8 +230,9 @@ void proc_comm_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + struct net *net = current->nsproxy->net_ns; - if (atomic_read(&proc_event_num_listeners) < 1) + if (atomic_read(&(net->cdev.proc_event_num_listeners)) < 1) return; msg = buffer_to_cn_msg(buffer); @@ -246,8 +257,9 @@ void proc_coredump_connector(struct task_struct *task) struct proc_event *ev; struct task_struct *parent; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); + struct net *net = current->nsproxy->net_ns; - if (atomic_read
[PATCH 3/5] connector: Ensure callback entry is released
Currently the entry itself appears to be being leaked. Signed-off-by: Matt Bennett --- drivers/connector/cn_queue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index 49295052ba8b..a82ceeb37f26 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -132,8 +132,10 @@ void cn_queue_free_dev(struct cn_queue_dev *dev) struct cn_callback_entry *cbq, *n; spin_lock_bh(&dev->queue_lock); - list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) + list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) { list_del(&cbq->callback_entry); + cn_queue_release_callback(cbq); + } spin_unlock_bh(&dev->queue_lock); while (atomic_read(&dev->refcnt)) { -- 2.27.0
[PATCH 4/5] connector: Prepare for supporting multiple namespaces
Extend the existing function definitions / call sites to start passing the network namespace. For now we still only pass the default namespace. Signed-off-by: Matt Bennett --- Documentation/driver-api/connector.rst | 6 +++--- drivers/connector/cn_proc.c| 5 +++-- drivers/connector/cn_queue.c | 5 +++-- drivers/connector/connector.c | 21 - drivers/hv/hv_utils_transport.c| 6 -- drivers/md/dm-log-userspace-transfer.c | 6 -- drivers/video/fbdev/uvesafb.c | 8 +--- drivers/w1/w1_netlink.c| 19 +++ include/linux/connector.h | 24 samples/connector/cn_test.c| 6 -- 10 files changed, 65 insertions(+), 41 deletions(-) diff --git a/Documentation/driver-api/connector.rst b/Documentation/driver-api/connector.rst index c100c7482289..4fb1f73d76ad 100644 --- a/Documentation/driver-api/connector.rst +++ b/Documentation/driver-api/connector.rst @@ -25,9 +25,9 @@ handling, etc... The Connector driver allows any kernelspace agents to use netlink based networking for inter-process communication in a significantly easier way:: - int cn_add_callback(struct cb_id *id, char *name, void (*callback) (struct cn_msg *, struct netlink_skb_parms *)); - void cn_netlink_send_multi(struct cn_msg *msg, u16 len, u32 portid, u32 __group, int gfp_mask); - void cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group, int gfp_mask); + int cn_add_callback(struct cb_id *id, char *name, void (*callback) (struct net *, struct cn_msg *, struct netlink_skb_parms *)); + void cn_netlink_send_multi(struct net *net, struct cn_msg *msg, u16 len, u32 portid, u32 __group, int gfp_mask); + void cn_netlink_send(struct net *net, struct cn_msg *msg, u32 portid, u32 __group, int gfp_mask); struct cb_id { diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index d90aea555a21..9202be177a30 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -61,7 +62,7 @@ static inline void send_msg(struct cn_msg *msg) * * If cn_netlink_send() fails, the data is not sent. */ - cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_NOWAIT); + cn_netlink_send(&init_net, msg, 0, CN_IDX_PROC, GFP_NOWAIT); local_unlock(&local_event.lock); } @@ -343,7 +344,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) * cn_proc_mcast_ctl * @data: message sent from userspace via the connector */ -static void cn_proc_mcast_ctl(struct cn_msg *msg, +static void cn_proc_mcast_ctl(struct net *net, struct cn_msg *msg, struct netlink_skb_parms *nsp) { enum proc_cn_mcast_op *mc_op = NULL; diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index a82ceeb37f26..22fdd2b149af 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -16,11 +16,12 @@ #include #include #include +#include static struct cn_callback_entry * cn_queue_alloc_callback_entry(struct cn_queue_dev *dev, const char *name, struct cb_id *id, - void (*callback)(struct cn_msg *, + void (*callback)(struct net *, struct cn_msg *, struct netlink_skb_parms *)) { struct cn_callback_entry *cbq; @@ -58,7 +59,7 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2) int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name, struct cb_id *id, - void (*callback)(struct cn_msg *, + void (*callback)(struct net *, struct cn_msg *, struct netlink_skb_parms *)) { struct cn_callback_entry *cbq, *__cbq; diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 2d22d6bf52f2..82fcaa4d8be3 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -58,8 +58,8 @@ static int cn_already_initialized; * The message is sent to, the portid if given, the group if given, both if * both, or if both are zero then the group is looked up and sent there. */ -int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group, - gfp_t gfp_mask) +int cn_netlink_send_mult(struct net *net, struct cn_msg *msg, u16 len, +u32 portid, u32 __group, gfp_t gfp_mask) { struct cn_callback_entry *__cbq; unsigned int size; @@ -118,17 +118,18 @@ int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group, EXPORT_SYMBOL_GPL(cn_netlink_send_mult); /* same as cn_netlink_send_mult except msg->len is used for len */ -int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group, - gfp_t gfp
[PATCH 2/5] connector: Use 'current_user_ns' function
In preparation for supporting the connector outside of the default network namespace we switch to using this function now. As the connector is still only supported in the default namespace this change is a no-op. Signed-off-by: Matt Bennett --- drivers/connector/cn_proc.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 36a7823c56ec..d90aea555a21 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -139,11 +139,11 @@ void proc_id_connector(struct task_struct *task, int which_id) rcu_read_lock(); cred = __task_cred(task); if (which_id == PROC_EVENT_UID) { - ev->event_data.id.r.ruid = from_kuid_munged(&init_user_ns, cred->uid); - ev->event_data.id.e.euid = from_kuid_munged(&init_user_ns, cred->euid); + ev->event_data.id.r.ruid = from_kuid_munged(current_user_ns(), cred->uid); + ev->event_data.id.e.euid = from_kuid_munged(current_user_ns(), cred->euid); } else if (which_id == PROC_EVENT_GID) { - ev->event_data.id.r.rgid = from_kgid_munged(&init_user_ns, cred->gid); - ev->event_data.id.e.egid = from_kgid_munged(&init_user_ns, cred->egid); + ev->event_data.id.r.rgid = from_kgid_munged(current_user_ns(), cred->gid); + ev->event_data.id.e.egid = from_kgid_munged(current_user_ns(), cred->egid); } else { rcu_read_unlock(); return; @@ -362,7 +362,7 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg, return; /* Can only change if privileged. */ - if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) { + if (!__netlink_ns_capable(nsp, current_user_ns(), CAP_NET_ADMIN)) { err = EPERM; goto out; } -- 2.27.0
[PATCH 0/5] RFC: connector: Add network namespace awareness
Previously the connector functionality could only be used by processes running in the default network namespace. This meant that any process that uses the connector functionality could not operate correctly when run inside a container. This is a draft patch series that attempts to now allow this functionality outside of the default network namespace. I see this has been discussed previously [1], but am not sure how my changes relate to all of the topics discussed there and/or if there are any unintended side effects from my draft changes. Thanks. [1] https://marc.info/?l=linux-kernel&m=150806196728365&w=2 Matt Bennett (5): connector: Use task pid helpers connector: Use 'current_user_ns' function connector: Ensure callback entry is released connector: Prepare for supporting multiple namespaces connector: Create connector per namespace Documentation/driver-api/connector.rst | 6 +- drivers/connector/cn_proc.c| 110 +++--- drivers/connector/cn_queue.c | 9 +- drivers/connector/connector.c | 192 - drivers/hv/hv_fcopy.c | 1 + drivers/hv/hv_utils_transport.c| 6 +- drivers/md/dm-log-userspace-transfer.c | 6 +- drivers/video/fbdev/uvesafb.c | 8 +- drivers/w1/w1_netlink.c| 19 +-- include/linux/connector.h | 38 +++-- include/net/net_namespace.h| 4 + kernel/exit.c | 2 +- samples/connector/cn_test.c| 6 +- 13 files changed, 286 insertions(+), 121 deletions(-) -- 2.27.0
Re: [RFC][PATCH v5 00/51] objtool: Make recordmcount a subcommand
On Thu, Jun 18, 2020 at 01:37:46PM -0700, Matt Helsley wrote: > recordmcount has its own ELF wrapper code and could utilize > objtool's ELF code to more-portably handle architecture variations. > This series makes recordmcount a subcommand of objtool. It very > gradually converts recordmcount to become a subcommand of objtool and > then reuses parts of objtool's ELF code. > > recordmcount maps the file in and collects simple information it needs to > append a section to the object file. The only part of the original file it > modifies is the address of new section tables -- interestingly enough this > resembles RCU in that we don't really trim the old tables so > much as unlink them via a critical offset and then rely on > future tooling, in this case, to drop the unused bits. > > Much of the recordmcount ELF code is only reading and walking the data > structures to collect the mcount locations it records in a separate > area of memory. This means it's safe to mix access to the mapped > file with access to the objtool-style linked data > structures as we gradually convert it to using only the linked data > structures. Once the old ELF code is no longer in use we can drop it > and use objtool to take over the task of writing the results without > using the RCU-like trick any more. > > After that we greatly simplify the mcount subcommand by adding a > few flags to the ELF reading code in objtool. Overall the series > removes about 600 lines of recordmcount while adding little to > objtool's ELF code. > > Testing so far: > > I've been using scripts to test cross compilation and execution of > objtool, and mcount on objects built for x86, ppc64le, arm64, s390, and > sparc. > > > Applies on top of: > objtool/core > > Peter Zijlstra's "x86/entry: noinstr fixes" [2] Just thought I'd note for anyone reviewing/playing with this series: Peter's patches are now in objtool/core > Sami Tolvanen's patch enabling support for more than 64k > sections in recordmcount, already going upstream. [3] Sami's patch is now in Linus' master branch Cheers, -Matt
[tip: x86/urgent] x86/asm/64: Align start of __clear_user() loop to 16-bytes
The following commit has been merged into the x86/urgent branch of tip: Commit-ID: bb5570ad3b54e7930997aec76ab68256d5236d94 Gitweb: https://git.kernel.org/tip/bb5570ad3b54e7930997aec76ab68256d5236d94 Author:Matt Fleming AuthorDate:Thu, 18 Jun 2020 11:20:02 +01:00 Committer: Borislav Petkov CommitterDate: Fri, 19 Jun 2020 18:32:11 +02:00 x86/asm/64: Align start of __clear_user() loop to 16-bytes x86 CPUs can suffer severe performance drops if a tight loop, such as the ones in __clear_user(), straddles a 16-byte instruction fetch window, or worse, a 64-byte cacheline. This issues was discovered in the SUSE kernel with the following commit, 1153933703d9 ("x86/asm/64: Micro-optimize __clear_user() - Use immediate constants") which increased the code object size from 10 bytes to 15 bytes and caused the 8-byte copy loop in __clear_user() to be split across a 64-byte cacheline. Aligning the start of the loop to 16-bytes makes this fit neatly inside a single instruction fetch window again and restores the performance of __clear_user() which is used heavily when reading from /dev/zero. Here are some numbers from running libmicro's read_z* and pread_z* microbenchmarks which read from /dev/zero: Zen 1 (Naples) libmicro-file 5.7.0-rc6 5.7.0-rc6 5.7.0-rc6 revert-1153933703d9+ align16+ Time mean95-pread_z100k 9.9195 ( 0.00%) 5.9856 ( 39.66%) 5.9938 ( 39.58%) Time mean95-pread_z10k1.1378 ( 0.00%) 0.7450 ( 34.52%) 0.7467 ( 34.38%) Time mean95-pread_z1k 0.2623 ( 0.00%) 0.2251 ( 14.18%) 0.2252 ( 14.15%) Time mean95-pread_zw100k 9.9974 ( 0.00%) 6.0648 ( 39.34%) 6.0756 ( 39.23%) Time mean95-read_z100k9.8940 ( 0.00%) 5.9885 ( 39.47%) 5.9994 ( 39.36%) Time mean95-read_z10k 1.1394 ( 0.00%) 0.7483 ( 34.33%) 0.7482 ( 34.33%) Note that this doesn't affect Haswell or Broadwell microarchitectures which seem to avoid the alignment issue by executing the loop straight out of the Loop Stream Detector (verified using perf events). Fixes: 1153933703d9 ("x86/asm/64: Micro-optimize __clear_user() - Use immediate constants") Signed-off-by: Matt Fleming Signed-off-by: Borislav Petkov Cc: # v4.19+ Link: https://lkml.kernel.org/r/20200618102002.30034-1-m...@codeblueprint.co.uk --- arch/x86/lib/usercopy_64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index fff28c6..b0dfac3 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -24,6 +24,7 @@ unsigned long __clear_user(void __user *addr, unsigned long size) asm volatile( " testq %[size8],%[size8]\n" " jz 4f\n" + " .align 16\n" "0: movq $0,(%[dst])\n" " addq $8,%[dst]\n" " decl %%ecx ; jnz 0b\n"
[RFC][PATCH v5 12/51] objtool: mcount: Walk relocation lists
Rather than walk the section tables using the old recordmcount mapping of the ELF file, walk the section list provided by objtool's ELF code. This removes the last use of of the Elf_r_sym wrapper so we remove that too. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 10 +--- tools/objtool/recordmcount.h | 103 +-- 2 files changed, 28 insertions(+), 85 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 843027a46e1b..dafa6dd10d04 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -429,9 +429,9 @@ static const unsigned int missing_sym = (unsigned int)-1; #define RECORD_MCOUNT_64 #include "recordmcount.h" -static int arm_is_fake_mcount(Elf32_Rel const *rp) +static int arm_is_fake_mcount(struct reloc const *rp) { - switch (ELF32_R_TYPE(w(rp->r_info))) { + switch (rp->type) { case R_ARM_THM_CALL: case R_ARM_CALL: case R_ARM_PC24: @@ -462,11 +462,6 @@ union mips_r_info { } r_mips; }; -static uint64_t MIPS64_r_sym(Elf64_Rel const *rp) -{ - return w(((union mips_r_info){ .r_info = rp->r_info }).r_mips.r_sym); -} - static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type) { rp->r_info = ((union mips_r_info){ @@ -605,7 +600,6 @@ static int do_file(char const *const fname) } if (w2(ghdr->e_machine) == EM_MIPS) { reltype = R_MIPS_64; - Elf64_r_sym = MIPS64_r_sym; Elf64_r_info = MIPS64_r_info; is_fake_mcount64 = MIPS64_is_fake_mcount; } diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 3dae878f11a8..df8384f8e9e7 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -31,21 +31,14 @@ #undef get_shnum #undef set_shnum #undef get_shstrndx -#undef get_relp #undef do_func #undef Elf_Addr #undef Elf_Ehdr #undef Elf_Shdr #undef Elf_Rel #undef Elf_Rela -#undef Elf_Sym -#undef ELF_R_SYM -#undef Elf_r_sym #undef ELF_R_INFO #undef Elf_r_info -#undef ELF_ST_BIND -#undef ELF_ST_TYPE -#undef fn_ELF_R_SYM #undef fn_ELF_R_INFO #undef uint_t #undef _w @@ -62,7 +55,6 @@ # define get_shnum get_shnum64 # define set_shnum set_shnum64 # define get_shstrndx get_shstrndx64 -# define get_relp get_relp_64 # define do_func do64 # define get_mcountsym get_mcountsym_64 # define is_fake_mcountis_fake_mcount64 @@ -74,14 +66,8 @@ # define Elf_Shdr Elf64_Shdr # define Elf_Rel Elf64_Rel # define Elf_Rela Elf64_Rela -# define Elf_Sym Elf64_Sym -# define ELF_R_SYM ELF64_R_SYM -# define Elf_r_sym Elf64_r_sym # define ELF_R_INFOELF64_R_INFO # define Elf_r_infoElf64_r_info -# define ELF_ST_BIND ELF64_ST_BIND -# define ELF_ST_TYPE ELF64_ST_TYPE -# define fn_ELF_R_SYM fn_ELF64_R_SYM # define fn_ELF_R_INFO fn_ELF64_R_INFO # define uint_tuint64_t # define _ww8 @@ -97,7 +83,6 @@ # define get_shnum get_shnum32 # define set_shnum set_shnum32 # define get_shstrndx get_shstrndx32 -# define get_relp get_relp_32 # define do_func do32 # define get_mcountsym get_mcountsym_32 # define is_fake_mcountis_fake_mcount32 @@ -109,14 +94,8 @@ # define Elf_Shdr Elf32_Shdr # define Elf_Rel Elf32_Rel # define Elf_Rela Elf32_Rela -# define Elf_Sym Elf32_Sym -# define ELF_R_SYM ELF32_R_SYM -# define Elf_r_sym Elf32_r_sym # define ELF_R_INFOELF32_R_INFO # define Elf_r_infoElf32_r_info -# define ELF_ST_BIND ELF32_ST_BIND -# define ELF_ST_TYPE ELF32_ST_TYPE -# define fn_ELF_R_SYM fn_ELF32_R_SYM # define fn_ELF_R_INFO fn_ELF32_R_INFO # define uint_tuint32_t # define _ww @@ -125,17 +104,11 @@ #endif /* Functions and pointers that do_file() may override for specific e_machine. */ -static int fn_is_fake_mcount(Elf_Rel const *rp) +static int fn_is_fake_mcount(struct reloc const *reloc) { return 0; } -static int (*is_fake_mcount)(Elf_Rel const *rp) = fn_is_fake_mcount; - -static uint_t fn_ELF_R_SYM(Elf_Rel const *rp) -{ - return ELF_R_SYM(_w(rp->r_info)); -} -static uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM; +static int (*is_fake_mcount)(struct reloc const *reloc) = fn_is_fake_mcount; static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type) { @@ -166,10 +139,10 @@ static int mcount_adjust = 0; */ #define MIPS_FAKEMCOUNT_OFFSET 4 -static int
[RFC][PATCH v5 04/51] objtool: recordmcount: Start using objtool's elf wrapper
Use struct elf to grab the file descriptor. We will later move these calls into other functions as we expand the lifetime of the struct elf so that it can be passed to objtool elf.[ch] functions. This creates the libelf/objtool data structures and gives us two separate ways to walk the ELF file -- the libelf/objtool way and the old recordmcount wrapper way which avoids these extra data structures by using indices, offsets, and pointers into the mmapped ELF file. Subsequent patches will convert from the old recordmcount accessors to the libelf/objtool accessors. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 18 +- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 601e83840085..b2c606eb269b 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -33,6 +33,8 @@ #include "objtool.h" +#include "elf.h" + #ifndef EM_AARCH64 #define EM_AARCH64 183 #define R_AARCH64_NONE 0 @@ -57,6 +59,8 @@ static void *file_ptr;/* current file pointer location */ static void *file_append; /* added to the end of the file */ static size_t file_append_size; /* how much is added to end of file */ +static struct elf *lf; + /* Per-file resource cleanup when multiple files. */ static void file_append_cleanup(void) { @@ -73,6 +77,9 @@ static void mmap_cleanup(void) else free(file_map); file_map = NULL; + if (lf) + elf_close(lf); + lf = NULL; } /* ulseek, uwrite, ...: Check return value for errors. */ @@ -170,11 +177,12 @@ static void *mmap_file(char const *fname) file_updated = 0; sb.st_size = 0; - fd_map = open(fname, O_RDONLY); - if (fd_map < 0) { + lf = elf_open_read(fname, O_RDONLY); + if (!lf) { perror(fname); return NULL; } + fd_map = lf->fd; if (fstat(fd_map, &sb) < 0) { perror(fname); goto out; @@ -194,14 +202,14 @@ static void *mmap_file(char const *fname) } if (read(fd_map, file_map, sb.st_size) != sb.st_size) { perror(fname); - free(file_map); - file_map = NULL; + mmap_cleanup(); goto out; } } else mmap_failed = 0; out: - close(fd_map); + elf_close(lf); + lf = NULL; fd_map = -1; file_end = file_map + sb.st_size; -- 2.20.1
[RFC][PATCH v5 10/51] objtool: mcount: Walk objtool Elf structs in find_secsym_ndx
Rather than using indices into raw ELF32/64 tables mapped for the wrapper, use the objtool functions to find the suitable symbol in the given text section. This also removes all callers to find_symtab() and get_symindex() so we can remove them as well. Also take advantage of this commit to rename the function to something that reads more easily. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 2 + tools/objtool/recordmcount.h | 94 2 files changed, 22 insertions(+), 74 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index f20582ac99e2..843027a46e1b 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -422,6 +422,8 @@ static int is_mcounted_section_name(char const *const txtname) strcmp(".cpuidle.text", txtname) == 0; } +static const unsigned int missing_sym = (unsigned int)-1; + /* 32 bit and 64 bit are very similar */ #include "recordmcount.h" #define RECORD_MCOUNT_64 diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 30f8913aa841..b10f7fcd33c3 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -24,15 +24,13 @@ #undef mcount_adjust #undef sift_rel_mcount #undef nop_mcount -#undef find_secsym_ndx +#undef find_section_sym_index #undef has_rel_mcount #undef tot_relsize #undef get_mcountsym -#undef find_symtab #undef get_shnum #undef set_shnum #undef get_shstrndx -#undef get_symindex #undef get_sym_str_and_relp #undef do_func #undef Elf_Addr @@ -58,14 +56,12 @@ # define append_func append64 # define sift_rel_mcount sift64_rel_mcount # define nop_mcountnop_mcount_64 -# define find_secsym_ndx find64_secsym_ndx +# define find_section_sym_indexfind64_section_sym_index # define has_rel_mcounthas64_rel_mcount # define tot_relsize tot64_relsize -# define find_symtab find_symtab64 # define get_shnum get_shnum64 # define set_shnum set_shnum64 # define get_shstrndx get_shstrndx64 -# define get_symindex get_symindex64 # define get_sym_str_and_relp get_sym_str_and_relp_64 # define do_func do64 # define get_mcountsym get_mcountsym_64 @@ -95,14 +91,12 @@ # define append_func append32 # define sift_rel_mcount sift32_rel_mcount # define nop_mcountnop_mcount_32 -# define find_secsym_ndx find32_secsym_ndx +# define find_section_sym_indexfind32_section_sym_index # define has_rel_mcounthas32_rel_mcount # define tot_relsize tot32_relsize -# define find_symtab find_symtab32 # define get_shnum get_shnum32 # define set_shnum set_shnum32 # define get_shstrndx get_shstrndx32 -# define get_symindex get_symindex32 # define get_sym_str_and_relp get_sym_str_and_relp_32 # define do_func do32 # define get_mcountsym get_mcountsym_32 @@ -185,21 +179,6 @@ static int MIPS_is_fake_mcount(Elf_Rel const *rp) return is_fake; } -static unsigned int get_symindex(Elf_Sym const *sym, Elf32_Word const *symtab, -Elf32_Word const *symtab_shndx) -{ - unsigned long offset; - int index; - - if (sym->st_shndx != SHN_XINDEX) - return w2(sym->st_shndx); - - offset = (unsigned long)sym - (unsigned long)symtab; - index = offset / sizeof(*sym); - - return w(symtab_shndx[index]); -} - static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0) { if (shdr0 && !ehdr->e_shnum) @@ -225,28 +204,6 @@ static int get_shstrndx(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0) return w(shdr0->sh_link); } -static void find_symtab(Elf_Ehdr *const ehdr, Elf_Shdr const *shdr0, - Elf32_Word **symtab, - Elf32_Word **symtab_shndx) -{ - unsigned const nhdr = get_shnum(ehdr, shdr0); - Elf_Shdr const *relhdr; - unsigned k; - - *symtab = NULL; - *symtab_shndx = NULL; - - for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { - if (relhdr->sh_type == SHT_SYMTAB) - *symtab = (void *)ehdr + relhdr->sh_offset; - else if (relhdr->sh_type == SHT_SYMTAB_SHNDX) - *symtab_shndx = (void *)ehdr + relhdr->sh_offset; - - if (*symtab && *symtab_shndx) - break; - } -} - /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */ static int append_func(Elf_Ehdr *const ehdr, Elf_Shdr *const shstr, @@ -507,40 +464,37 @@ static int nop_mcount(const struct section * const rels, *Num:Value Size TypeBind Vis Ndx Name * 2: 0 SECTION LOCAL
[RFC][PATCH v5 26/51] objtool: mcount: Remove unused file mapping
The ELF data is now accessed completely through objtool's ELF code. We can remove the mapping of the original ELF file and propagate elf_open_read(), elf_close(), and malloc() up in place of mmap_file(), mmap_cleanup(), and umalloc() respectively. This also eliminates the last use of the umalloc() wrapper, reduces the number of global variables, and limits the use of globals to: The struct elf for the file we're working on. This saves passing it to nearly every function as a parameter. Variables set depending on the ELF file endian, wordsize, and arch so that the appropriate relocation structures, offset sizes, architecture quirks, and nop encodings will be used. One command-line option Note that we're still using the recordmcount wrapper to change variable sizes and structure definitions we use to build the mcount relocation data and call instruction offsets. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 99 +++- tools/objtool/recordmcount.h | 4 +- 2 files changed, 9 insertions(+), 94 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index f8699e52e7e5..a263062c9c64 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -41,104 +41,14 @@ #define R_AARCH64_ABS64257 #endif -#define R_ARM_PC24 1 #define R_ARM_THM_CALL 10 -#define R_ARM_CALL 28 -static int fd_map; /* File descriptor for file being modified. */ -static int mmap_failed; /* Boolean flag. */ static char gpfx; /* prefix for global symbol name (sometimes '_') */ static const char *altmcount; /* alternate mcount symbol name */ extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ -static void *file_map; /* pointer of the mapped file */ -static size_t file_map_size; /* original ELF file size */ static struct elf *lf; -static void mmap_cleanup(void) -{ - if (!mmap_failed) - munmap(file_map, file_map_size); - else - free(file_map); - file_map = NULL; - if (lf) - elf_close(lf); - lf = NULL; -} - -static void * umalloc(size_t size) -{ - void *const addr = malloc(size); - if (addr == 0) { - fprintf(stderr, "malloc failed: %zu bytes\n", size); - mmap_cleanup(); - return NULL; - } - return addr; -} - -/* - * Get the whole file as a programming convenience in order to avoid - * malloc+lseek+read+free of many pieces. If successful, then mmap - * avoids copying unused pieces; else just read the whole file. - * Open for both read and write; new info will be appended to the file. - * Use MAP_PRIVATE so that a few changes to the in-memory ElfXX_Ehdr - * do not propagate to the file until an explicit overwrite at the last. - * This preserves most aspects of consistency (all except .st_size) - * for simultaneous readers of the file while we are appending to it. - * However, multiple writers still are bad. We choose not to use - * locking because it is expensive and the use case of kernel build - * makes multiple writers unlikely. - */ -static void *mmap_file(char const *fname) -{ - struct stat sb; - - /* Avoid problems if early cleanup() */ - fd_map = -1; - mmap_failed = 1; - file_map = NULL; - file_map_size = 0; - - lf = elf_open_read(fname, O_RDWR); - if (!lf) { - perror(fname); - return NULL; - } - fd_map = lf->fd; - if (fstat(fd_map, &sb) < 0) { - perror(fname); - goto out; - } - if (!S_ISREG(sb.st_mode)) { - fprintf(stderr, "not a regular file: %s\n", fname); - goto out; - } - file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, - fd_map, 0); - if (file_map == MAP_FAILED) { - mmap_failed = 1; - file_map = umalloc(sb.st_size); - if (!file_map) { - perror(fname); - goto out; - } - if (read(fd_map, file_map, sb.st_size) != sb.st_size) { - perror(fname); - mmap_cleanup(); - goto out; - } - } else - mmap_failed = 0; - file_map_size = sb.st_size; -out: - fd_map = -1; - - return file_map; -} - - static unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; static unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; static unsigned char *ideal_nop; @@ -527,8 +437,11 @@ static int do_file(char const *const fname) unsigned int reltype = 0; int rc = -1; - if (!mmap_file(fname)) + lf = elf_open_read(fn
[RFC][PATCH v5 29/51] objtool: mcount: Pre-allocate new ELF sections
Rather than allocating the ELF sections after collecting the mcount locations and building the relocation entries, create the empty sections beforehand. This has the benefit of removing the memcpy() and just using the resulting libelf buffers directly. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.h | 122 +++ 1 file changed, 53 insertions(+), 69 deletions(-) diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index e2c8b9d4725d..ce88f0c2f79b 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -17,7 +17,6 @@ * This conversion to macros was done by: * Copyright 2010 Steven Rostedt , Red Hat Inc. */ -#undef append_func #undef sift_rel_mcount #undef do_func #undef Elf_Shdr @@ -31,7 +30,6 @@ #undef _size #ifdef RECORD_MCOUNT_64 -# define append_func append64 # define sift_rel_mcount sift64_rel_mcount # define do_func do64 # define Elf_Rel Elf64_Rel @@ -43,7 +41,6 @@ # define _ww8 # define _size 8 #else -# define append_func append32 # define sift_rel_mcount sift32_rel_mcount # define do_func do32 # define Elf_Rel Elf32_Rel @@ -62,57 +59,6 @@ static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type) } static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; -/* Append the new __mcount_loc and its relocations. */ -static int append_func(uint_t const *const mloc0, - uint_t const *const mlocp, - Elf_Rel const *const mrel0, - Elf_Rel const *const mrelp, - unsigned int const loc_size, - unsigned int const rel_entsize, - unsigned int const symsec_sh_link) -{ - /* Begin constructing output file */ - struct section *mcount_loc_sec, *reloc_sec; - char const *mc_name = (sizeof(Elf_Rela) == rel_entsize) - ? ".rela__mcount_loc" - : ".rel__mcount_loc"; - - /* add section: __mcount_loc */ - mcount_loc_sec = elf_create_section(lf, - mc_name + (sizeof(Elf_Rela) == rel_entsize) + strlen(".rel"), - loc_size, mlocp - mloc0); - if (!mcount_loc_sec) - return -1; - // created mcount_loc_sec->sh.sh_size = (void *)mlocp - (void *)mloc0; - mcount_loc_sec->sh.sh_link = 0; - mcount_loc_sec->sh.sh_info = 0; - mcount_loc_sec->sh.sh_addralign = loc_size; - // created mcount_loc_sec->sh.sh_entsize = loc_size; - - // assert mcount_loc_sec->data->d_size == (void *)mlocp - (void *)mloc0 - memcpy(mcount_loc_sec->data->d_buf, mloc0, - mcount_loc_sec->data->d_size); - elf_flagdata(mcount_loc_sec->data, ELF_C_SET, ELF_F_DIRTY); - - /* add section .rel[a]__mcount_loc */ - reloc_sec = elf_create_section(lf, mc_name, rel_entsize, - mrelp - mrel0); - if (!reloc_sec) - return -1; - reloc_sec->sh.sh_type = (sizeof(Elf_Rela) == rel_entsize) ? - SHT_RELA : SHT_REL; - reloc_sec->sh.sh_flags = 0; /* clear SHF_ALLOC */ - reloc_sec->sh.sh_link = find_section_by_name(lf, ".symtab")->idx; - reloc_sec->sh.sh_info = mcount_loc_sec->idx; - reloc_sec->sh.sh_addralign = loc_size; - - // assert reloc_sec->data->d_size == (void *)mrelp - (void *)mrel0 - memcpy(reloc_sec->data->d_buf, mrel0, reloc_sec->data->d_size); - elf_flagdata(reloc_sec->data, ELF_C_SET, ELF_F_DIRTY); - - return elf_write(lf); -} - /* * Look at the relocations in order to find the calls to mcount. * Accumulate the section offsets that are found, and their relocation info, @@ -167,12 +113,12 @@ static int do_func(unsigned const reltype) uint_t * mloc0; uint_t * mlocp; - unsigned int rel_entsize = 0; - unsigned symsec_sh_link = 0; - - struct section *sec; + struct section *sec, *mlocs, *mrels; + char const *mc_name; - int result = 0; + unsigned int rel_entsize = 0; + int result = -1; + bool is_rela; if (find_section_by_name(lf, "__mcount_loc") != NULL) return 0; @@ -180,6 +126,7 @@ static int do_func(unsigned const reltype) totrelsz = tot_relsize(&rel_entsize); if (totrelsz == 0) return 0; + mrel0 = malloc(totrelsz); mrelp = mrel0; if (!mrel0) @@ -193,6 +140,31 @@ static int do_func(unsigned const reltype) return -1; } + is_rela = (sizeof(Elf_Rela) == rel_entsize); + mc_name = is_rela +
[RFC][PATCH v5 16/51] objtool: mcount: Move is_fake_mcount()
Promote the now-bit-independent is_fake_mcount() out of the old recordmcount ELF wrapper. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 48 +++--- tools/objtool/recordmcount.h | 50 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index d5f7c06afd57..24b019b82795 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -438,6 +438,48 @@ static struct symbol *get_mcountsym(struct reloc *reloc) return NULL; } +/* + * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st + * _mcount symbol is needed for dynamic function tracer, with it, to disable + * tracing(ftrace_make_nop), the instruction in the position is replaced with + * the "b label" instruction, to enable tracing(ftrace_make_call), replace the + * instruction back. So, here, we set the 2nd one as fake and filter it. + * + * c: 3c03lui v1,0x0 <-->b label + * c: R_MIPS_HI16 _mcount + * c: R_MIPS_NONE *ABS* + * c: R_MIPS_NONE *ABS* + * 10: 6463daddiu v1,v1,0 + * 10: R_MIPS_LO16 _mcount + * 10: R_MIPS_NONE *ABS* + * 10: R_MIPS_NONE *ABS* + * 14: 03e0082dmoveat,ra + * 18: 0060f809jalrv1 + * label: + */ +#define MIPS_FAKEMCOUNT_OFFSET 4 + +static int MIPS_is_fake_mcount(struct reloc const *reloc) +{ + static unsigned long old_r_offset = ~0UL; + unsigned long current_r_offset = reloc->offset; + int is_fake; + + is_fake = (old_r_offset != ~0UL) && + (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET); + old_r_offset = current_r_offset; + + return is_fake; +} + +/* Functions and pointers that do_file() may override for specific e_machine. */ +static int fn_is_fake_mcount(struct reloc const *reloc) +{ + return 0; +} + +static int (*is_fake_mcount)(struct reloc const *reloc) = fn_is_fake_mcount; + static const unsigned int missing_sym = (unsigned int)-1; /* 32 bit and 64 bit are very similar */ @@ -557,7 +599,7 @@ static int do_file(char const *const fname) altmcount = "__gnu_mcount_nc"; make_nop = make_nop_arm; rel_type_nop = R_ARM_NONE; - is_fake_mcount32 = arm_is_fake_mcount; + is_fake_mcount = arm_is_fake_mcount; gpfx = 0; break; case EM_AARCH64: @@ -597,7 +639,7 @@ static int do_file(char const *const fname) } if (w2(ehdr->e_machine) == EM_MIPS) { reltype = R_MIPS_32; - is_fake_mcount32 = MIPS32_is_fake_mcount; + is_fake_mcount = MIPS_is_fake_mcount; } if (do32(ehdr, reltype) < 0) goto out; @@ -617,7 +659,7 @@ static int do_file(char const *const fname) if (w2(ghdr->e_machine) == EM_MIPS) { reltype = R_MIPS_64; Elf64_r_info = MIPS64_r_info; - is_fake_mcount64 = MIPS64_is_fake_mcount; + is_fake_mcount = MIPS_is_fake_mcount; } if (do64(ghdr, reltype) < 0) goto out; diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index dde2ec054e51..941f96e4f74b 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -18,9 +18,6 @@ * Copyright 2010 Steven Rostedt , Red Hat Inc. */ #undef append_func -#undef is_fake_mcount -#undef fn_is_fake_mcount -#undef MIPS_is_fake_mcount #undef mcount_adjust #undef sift_rel_mcount #undef nop_mcount @@ -54,9 +51,6 @@ # define set_shnum set_shnum64 # define get_shstrndx get_shstrndx64 # define do_func do64 -# define is_fake_mcountis_fake_mcount64 -# define fn_is_fake_mcount fn_is_fake_mcount64 -# define MIPS_is_fake_mcount MIPS64_is_fake_mcount # define mcount_adjust mcount_adjust_64 # define Elf_Ehdr Elf64_Ehdr # define Elf_Shdr Elf64_Shdr @@ -80,9 +74,6 @@ # define set_shnum set_shnum32 # define get_shstrndx get_shstrndx32 # define do_func do32 -# define is_fake_mcountis_fake_mcount32 -# define fn_is_fake_mcount fn_is_fake_mcount32 -# define MIPS_is_fake_mcount MIPS32_is_fake_mcount # define mcount_adjust mcount_adjust_32 # define Elf_Ehdr Elf32_Ehdr # define Elf_Shdr Elf32_Shdr @@ -97,13 +88,6 @@ # define _size 4 #endif -/* Functions and pointers that do_file() may override for specific e_machine. */ -static int fn_is_fake_mcount(struct reloc const *reloc) -{ -
[RFC][PATCH v5 27/51] objtool: mcount: Reduce usage of _size wrapper
Use a new loc_size parameter to append_func() rather than use the wrapper's _size macro directly. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.h | 11 ++- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index fcc4f1a74d60..a74a80b3356e 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -72,6 +72,7 @@ static int append_func(uint_t const *const mloc0, uint_t const *const mlocp, Elf_Rel const *const mrel0, Elf_Rel const *const mrelp, + unsigned int const loc_size, unsigned int const rel_entsize, unsigned int const symsec_sh_link) { @@ -84,14 +85,14 @@ static int append_func(uint_t const *const mloc0, /* add section: __mcount_loc */ mcount_loc_sec = elf_create_section(lf, mc_name + (sizeof(Elf_Rela) == rel_entsize) + strlen(".rel"), - _size, mlocp - mloc0); + loc_size, mlocp - mloc0); if (!mcount_loc_sec) return -1; // created mcount_loc_sec->sh.sh_size = (void *)mlocp - (void *)mloc0; mcount_loc_sec->sh.sh_link = 0; mcount_loc_sec->sh.sh_info = 0; - mcount_loc_sec->sh.sh_addralign = _size; - // created mcount_loc_sec->sh.sh_entsize = _size; + mcount_loc_sec->sh.sh_addralign = loc_size; + // created mcount_loc_sec->sh.sh_entsize = loc_size; // assert mcount_loc_sec->data->d_size == (void *)mlocp - (void *)mloc0 memcpy(mcount_loc_sec->data->d_buf, mloc0, @@ -108,7 +109,7 @@ static int append_func(uint_t const *const mloc0, reloc_sec->sh.sh_flags = 0; /* clear SHF_ALLOC */ reloc_sec->sh.sh_link = find_section_by_name(lf, ".symtab")->idx; reloc_sec->sh.sh_info = mcount_loc_sec->idx; - reloc_sec->sh.sh_addralign = _size; + reloc_sec->sh.sh_addralign = loc_size; // assert reloc_sec->data->d_size == (void *)mrelp - (void *)mrel0 memcpy(reloc_sec->data->d_buf, mrel0, reloc_sec->data->d_size); @@ -227,7 +228,7 @@ static int do_func(unsigned const reltype) } if (!result && mloc0 != mlocp) result = append_func(mloc0, mlocp, mrel0, mrelp, -rel_entsize, symsec_sh_link); +_size, rel_entsize, symsec_sh_link); out: free(mrel0); free(mloc0); -- 2.20.1
[RFC][PATCH v5 03/51] objtool: Make recordmcount into mcount subcmd
Rather than a standalone executable merge recordmcount as a sub command of objtool. This is a small step towards cleaning up recordmcount and eventually sharing ELF code with objtool. For the initial step all that's required is a bit of Makefile changes and invoking the former main() function from recordmcount.c because the subcommand code uses similar function arguments as main when dispatching. objtool ignores some object files that tracing does not, specifically those with OBJECT_FILES_NON_STANDARD Makefile variables. For this reason we keep the recordmcount_dep separate from the objtool_dep. When using objtool mcount we can also, like the other objtool invocations, just depend on the binary rather than the source the binary is built from. Subsequent patches will gradually convert recordmcount to use more and more of libelf/objtool's ELF accessor code. This will both clean up recordmcount to be more easily readable and remove recordmcount's crude accessor wrapping code. Signed-off-by: Matt Helsley --- Documentation/dontdiff | 2 +- Documentation/trace/ftrace.rst | 6 ++-- Makefile| 15 -- arch/arm64/include/asm/ftrace.h | 2 +- arch/x86/include/asm/ftrace.h | 2 +- kernel/trace/Kconfig| 9 +- scripts/Makefile.build | 19 +++-- scripts/sorttable.h | 2 +- tools/objtool/Build | 4 +-- tools/objtool/Makefile | 20 ++--- tools/objtool/builtin-mcount.c | 50 + tools/objtool/builtin.h | 1 + tools/objtool/objtool.c | 1 + tools/objtool/objtool.h | 1 + tools/objtool/recordmcount.c| 36 +++- tools/objtool/weak.c| 5 16 files changed, 104 insertions(+), 71 deletions(-) create mode 100644 tools/objtool/builtin-mcount.c diff --git a/Documentation/dontdiff b/Documentation/dontdiff index ef9519c32c55..82cc4e3bb713 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -211,7 +211,7 @@ r420_reg_safe.h r600_reg_safe.h randomize_layout_hash.h randomize_layout_seed.h -recordmcount +objtool relocs rlim_names.h rn50_reg_safe.h diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index 24ec4ec2d98d..eefb966e5832 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -2684,8 +2684,8 @@ every kernel function, produced by the -pg switch in gcc), starts of pointing to a simple return. (Enabling FTRACE will include the -pg switch in the compiling of the kernel.) -At compile time every C file object is run through the -recordmcount program (located in the tools/objtool directory). This +At compile time every C file object is run through objtool's +mcount subcommand (located in the tools/objtool directory). This program will parse the ELF headers in the C object to find all the locations in the .text section that call mcount. Starting with gcc version 4.6, the -mfentry has been added for x86, which @@ -2699,7 +2699,7 @@ can be traced. A section called "__mcount_loc" is created that holds references to all the mcount/fentry call sites in the .text section. -The recordmcount program re-links this section back into the +Running "objtool mcount" re-links this section back into the original object. The final linking stage of the kernel will add all these references into a single table. diff --git a/Makefile b/Makefile index e20c30f82c58..3842d7258b43 100644 --- a/Makefile +++ b/Makefile @@ -841,6 +841,7 @@ ifdef CONFIG_FTRACE_MCOUNT_RECORD ifeq ($(call cc-option-yn,-mrecord-mcount),y) CC_FLAGS_FTRACE+= -mrecord-mcount export CC_USING_RECORD_MCOUNT := 1 +undefine CONFIG_OBJTOOL_SUBCMD_MCOUNT endif ifdef CONFIG_HAVE_NOP_MCOUNT ifeq ($(call cc-option-yn, -mnop-mcount),y) @@ -848,7 +849,7 @@ ifdef CONFIG_FTRACE_MCOUNT_RECORD CC_FLAGS_USING += -DCC_USING_NOP_MCOUNT endif endif -endif +endif # CONFIG_FTRACE_MCOUNT_RECORD ifdef CONFIG_HAVE_FENTRY ifeq ($(call cc-option-yn, -mfentry),y) CC_FLAGS_FTRACE+= -mfentry @@ -858,14 +859,7 @@ endif export CC_FLAGS_FTRACE KBUILD_CFLAGS += $(CC_FLAGS_FTRACE) $(CC_FLAGS_USING) KBUILD_AFLAGS += $(CC_FLAGS_USING) -ifdef CONFIG_DYNAMIC_FTRACE - ifdef CONFIG_HAVE_C_RECORDMCOUNT - BUILD_C_RECORDMCOUNT := y - export BUILD_C_RECORDMCOUNT - objtool_target := tools/objtool FORCE - endif -endif -endif +endif # CONFIG_FUNCTION_TRACER # We trigger additional mismatches with less inlining ifdef CONFIG_DEBUG_SECTION_MISMATCH @@ -1196,6 +1190,9 @@ ifneq ($(has_libelf),1) ifdef CONFIG_UNWINDER_ORC @echo "error: Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 @false + else ifdef CONFIG_OBJTOOL_SUBCMD_MCOUNT +
[RFC][PATCH v5 02/51] objtool: Prepare to merge recordmcount
Move recordmcount into the objtool directory. We keep this step separate so changes which turn recordmcount into a subcommand of objtool don't get obscured. Signed-off-by: Matt Helsley --- Documentation/trace/ftrace-design.rst | 4 ++-- Documentation/trace/ftrace.rst | 2 +- Makefile | 11 +++ scripts/.gitignore | 1 - scripts/Makefile | 1 - scripts/Makefile.build | 11 ++- tools/objtool/.gitignore | 1 + tools/objtool/Build| 2 ++ tools/objtool/Makefile | 13 - {scripts => tools/objtool}/recordmcount.c | 0 {scripts => tools/objtool}/recordmcount.h | 0 {scripts => tools/objtool}/recordmcount.pl | 0 12 files changed, 31 insertions(+), 15 deletions(-) rename {scripts => tools/objtool}/recordmcount.c (100%) rename {scripts => tools/objtool}/recordmcount.h (100%) rename {scripts => tools/objtool}/recordmcount.pl (100%) diff --git a/Documentation/trace/ftrace-design.rst b/Documentation/trace/ftrace-design.rst index 6893399157f0..f793a76ff65a 100644 --- a/Documentation/trace/ftrace-design.rst +++ b/Documentation/trace/ftrace-design.rst @@ -253,7 +253,7 @@ You need very few things to get the syscalls tracing in an arch. HAVE_FTRACE_MCOUNT_RECORD - -See scripts/recordmcount.pl for more info. Just fill in the arch-specific +See tools/objtool/recordmcount.pl for more info. Just fill in the arch-specific details for how to locate the addresses of mcount call sites via objdump. This option doesn't make much sense without also implementing dynamic ftrace. @@ -371,7 +371,7 @@ linux/ftrace.h for the functions:: ftrace_make_call() The rec->ip value is the address of the mcount call site that was collected -by the scripts/recordmcount.pl during build time. +by the tools/objtool/recordmcount.pl during build time. The last function is used to do runtime patching of the active tracer. This will be modifying the assembly code at the location of the ftrace_call symbol diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index 430a16283103..24ec4ec2d98d 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -2685,7 +2685,7 @@ starts of pointing to a simple return. (Enabling FTRACE will include the -pg switch in the compiling of the kernel.) At compile time every C file object is run through the -recordmcount program (located in the scripts directory). This +recordmcount program (located in the tools/objtool directory). This program will parse the ELF headers in the C object to find all the locations in the .text section that call mcount. Starting with gcc version 4.6, the -mfentry has been added for x86, which diff --git a/Makefile b/Makefile index cf731709ebe7..e20c30f82c58 100644 --- a/Makefile +++ b/Makefile @@ -862,6 +862,7 @@ ifdef CONFIG_DYNAMIC_FTRACE ifdef CONFIG_HAVE_C_RECORDMCOUNT BUILD_C_RECORDMCOUNT := y export BUILD_C_RECORDMCOUNT + objtool_target := tools/objtool FORCE endif endif endif @@ -1191,13 +1192,15 @@ uapi-asm-generic: PHONY += prepare-objtool prepare-objtool: $(objtool_target) -ifeq ($(SKIP_STACK_VALIDATION),1) -ifdef CONFIG_UNWINDER_ORC +ifneq ($(has_libelf),1) + ifdef CONFIG_UNWINDER_ORC @echo "error: Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 @false -else + else +ifeq ($(SKIP_STACK_VALIDATION),1) @echo "warning: Cannot use CONFIG_STACK_VALIDATION=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 -endif +endif + endif endif # Generate some files diff --git a/scripts/.gitignore b/scripts/.gitignore index 0d1c8e217cd7..dafda6d2c306 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -2,7 +2,6 @@ bin2c kallsyms unifdef -recordmcount sorttable asn1_compiler extract-cert diff --git a/scripts/Makefile b/scripts/Makefile index 95ecf970c74c..d8d81de4f1cb 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -5,7 +5,6 @@ always-$(CONFIG_BUILD_BIN2C) += bin2c always-$(CONFIG_KALLSYMS) += kallsyms -always-$(BUILD_C_RECORDMCOUNT) += recordmcount always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable always-$(CONFIG_ASN1) += asn1_compiler always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 2e8810b7e5ed..f3f58d71951c 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -188,18 +188,19 @@ endif # files, including recordmcount. sub_cmd_record_mcount =
[RFC][PATCH v5 07/51] objtool: mcount: Move nhdr into find_symtab()
Since it's no longer needed in the rest of do_func() we can move it to where it's needed rather than pass it as a parameter. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index b46e855d32bf..4bd61c9d1fd5 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -229,9 +229,10 @@ static int get_shstrndx(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0) } static void find_symtab(Elf_Ehdr *const ehdr, Elf_Shdr const *shdr0, - unsigned const nhdr, Elf32_Word **symtab, + Elf32_Word **symtab, Elf32_Word **symtab_shndx) { + unsigned const nhdr = get_shnum(ehdr, shdr0); Elf_Shdr const *relhdr; unsigned k; @@ -593,7 +594,6 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname, { Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) + (void *)ehdr); - unsigned const nhdr = get_shnum(ehdr, shdr0); Elf_Shdr *const shstr = &shdr0[get_shstrndx(ehdr, shdr0)]; char const *const shstrtab = (char const *)(_w(shstr->sh_offset) + (void *)ehdr); @@ -638,7 +638,7 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname, return -1; } - find_symtab(ehdr, shdr0, nhdr, &symtab, &symtab_shndx); + find_symtab(ehdr, shdr0, &symtab, &symtab_shndx); list_for_each_entry(sec, &lf->sections, list) { char const *txtname; -- 2.20.1
[RFC][PATCH v5 28/51] objtool: mcount: Move mcount_adjust out of wrapper
The mcount_adjust variable defines how many bytes to move back from the relocation address in order to be able to get to the start of the function call instruction(s) needed to turn it into a no-op. The values are very small and signed so we don't need to worry about changing the size of the variable's type inside the wrapper -- we can just use a regular int. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 11 --- tools/objtool/recordmcount.h | 5 - 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index a263062c9c64..bb53927612fb 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -387,6 +387,11 @@ static unsigned tot_relsize(unsigned int *rel_entsize) return totrelsz; } +/* zero or a small negative offset added to get the start of the call + * instruction + */ +static int mcount_adjust = 0; + /* 32 bit and 64 bit are very similar */ #include "recordmcount.h" #define RECORD_MCOUNT_64 @@ -497,7 +502,7 @@ static int do_file(char const *const fname) rel_type_nop = R_386_NONE; make_nop = make_nop_x86; ideal_nop = ideal_nop5_x86_32; - mcount_adjust_32 = -1; + mcount_adjust = -1; gpfx = 0; break; case EM_ARM: @@ -526,7 +531,7 @@ static int do_file(char const *const fname) ideal_nop = ideal_nop5_x86_64; reltype = R_X86_64_64; rel_type_nop = R_X86_64_NONE; - mcount_adjust_64 = -1; + mcount_adjust = -1; gpfx = 0; break; } /* end switch */ @@ -558,7 +563,7 @@ static int do_file(char const *const fname) } if (lf->ehdr.e_machine == EM_S390) { reltype = R_390_64; - mcount_adjust_64 = -14; + mcount_adjust = -14; } if (lf->ehdr.e_machine == EM_MIPS) { reltype = R_MIPS_64; diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index a74a80b3356e..e2c8b9d4725d 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -18,7 +18,6 @@ * Copyright 2010 Steven Rostedt , Red Hat Inc. */ #undef append_func -#undef mcount_adjust #undef sift_rel_mcount #undef do_func #undef Elf_Shdr @@ -35,7 +34,6 @@ # define append_func append64 # define sift_rel_mcount sift64_rel_mcount # define do_func do64 -# define mcount_adjust mcount_adjust_64 # define Elf_Rel Elf64_Rel # define Elf_Rela Elf64_Rela # define ELF_R_INFOELF64_R_INFO @@ -48,7 +46,6 @@ # define append_func append32 # define sift_rel_mcount sift32_rel_mcount # define do_func do32 -# define mcount_adjust mcount_adjust_32 # define Elf_Rel Elf32_Rel # define Elf_Rela Elf32_Rela # define ELF_R_INFOELF32_R_INFO @@ -65,8 +62,6 @@ static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type) } static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; -static int mcount_adjust = 0; - /* Append the new __mcount_loc and its relocations. */ static int append_func(uint_t const *const mloc0, uint_t const *const mlocp, -- 2.20.1
[RFC][PATCH v5 19/51] objtool: mcount: Restrict using ehdr in append_func()
Use the ehdr parameter to append_func() to write the ELF file's header but use the objtool ELF header data as the basis for making changes. The makes it clearer when we can switch from using the old recordmcount wrapper to write the ELF file because ehdr will only be passed on to uwrite() calls and those will get replaced later. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.h | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index eed592954f37..19bff5a7c8ce 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -93,7 +93,7 @@ static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_E static int mcount_adjust = 0; -static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0) +static unsigned int get_shnum(GElf_Ehdr const *ehdr, Elf_Shdr const *shdr0) { if (shdr0 && !ehdr->e_shnum) return w(shdr0->sh_size); @@ -133,11 +133,11 @@ static int append_func(Elf_Ehdr *const ehdr, char const *mc_name = (sizeof(Elf_Rela) == rel_entsize) ? ".rela__mcount_loc" : ".rel__mcount_loc"; - uint_t const old_shoff = _w(ehdr->e_shoff); + uint_t const old_shoff = lf->ehdr.e_shoff; uint_t const old_shstr_sh_size = _w(shstr->sh_size); uint_t const old_shstr_sh_offset = _w(shstr->sh_offset); Elf_Shdr *const shdr0 = (Elf_Shdr *)(old_shoff + (void *)ehdr); - unsigned int const old_shnum = get_shnum(ehdr, shdr0); + unsigned int const old_shnum = get_shnum(&lf->ehdr, shdr0); unsigned int const new_shnum = 2 + old_shnum; /* {.rel,}__mcount_loc */ uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size); uint_t new_e_shoff; @@ -149,8 +149,6 @@ static int append_func(Elf_Ehdr *const ehdr, t += (_align & -t); /* word-byte align */ new_e_shoff = t; - set_shnum(ehdr, shdr0, new_shnum); - /* body for new shstrtab */ if (ulseek(sb.st_size, SEEK_SET) < 0) return -1; @@ -205,6 +203,7 @@ static int append_func(Elf_Ehdr *const ehdr, return -1; ehdr->e_shoff = _w(new_e_shoff); + set_shnum(ehdr, shdr0, new_shnum); if (ulseek(0, SEEK_SET) < 0) return -1; if (uwrite(ehdr, sizeof(*ehdr)) < 0) -- 2.20.1
[RFC][PATCH v5 37/51] objtool: mcount: Simplify mcount name matching
Setting altmcount only when processing ARM ELF files is not necessary -- we can make the code easier to read by always checking for the string. Signed-off-by: Matt Helsley --- tools/objtool/mcount.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index ff52697613b1..7e621769c488 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -44,7 +44,6 @@ #define R_ARM_THM_CALL 10 static char gpfx; /* prefix for global symbol name (sometimes '_') */ -static const char *altmcount; /* alternate mcount symbol name */ extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ static struct elf *lf; @@ -173,7 +172,7 @@ static struct symbol *get_mcount_sym(struct reloc *reloc) if (symname[0] == '.') ++symname; /* ppc64 hack */ if (strcmp(mcount, symname) == 0 || - (altmcount && strcmp(altmcount, symname) == 0) || + (strcmp("__gnu_mcount_nc", symname) == 0) || (strcmp(fentry, symname) == 0)) return sym; return NULL; @@ -567,7 +566,6 @@ static int do_file(char const *const fname) break; case EM_ARM: reltype = R_ARM_ABS32; - altmcount = "__gnu_mcount_nc"; make_nop = make_nop_arm; rel_type_nop = R_ARM_NONE; is_fake_mcount = arm_is_fake_mcount; -- 2.20.1
[RFC][PATCH v5 30/51] objtool: mcount: Generic location and relocation table types
Rather than building the exact ELF section data we need and avoiding libelf's conversion step, use more GElf types and then libelf's elfxx_xlatetof() functions to convert the mcount locations (GElf_Addr) and associated relocations. This converts sift_rel_mcount() so that it doesn't use the recordmcount wrapper. The next patch will move it out of the wrapper. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 44 +++-- tools/objtool/recordmcount.h | 122 ++- 2 files changed, 60 insertions(+), 106 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index bb53927612fb..34976f3294ac 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -210,7 +210,7 @@ static int is_mcounted_section_name(char const *const txtname) strcmp(".cpuidle.text", txtname) == 0; } -static struct symbol *get_mcountsym(struct reloc *reloc) +static struct symbol *get_mcount_sym(struct reloc *reloc) { struct symbol *sym = reloc->sym; char const *symname = sym->name; @@ -322,16 +322,16 @@ static int nop_mcount(struct section * const rels, { struct reloc *reloc; struct section *txts = find_section_by_index(lf, rels->sh.sh_info); - struct symbol *mcountsym = NULL; + struct symbol *mcount_sym = NULL; int once = 0; list_for_each_entry(reloc, &rels->reloc_list, list) { int ret = -1; - if (!mcountsym) - mcountsym = get_mcountsym(reloc); + if (!mcount_sym) + mcount_sym = get_mcount_sym(reloc); - if (mcountsym == reloc->sym && !is_fake_mcount(reloc)) { + if (mcount_sym == reloc->sym && !is_fake_mcount(reloc)) { if (make_nop) { ret = make_nop(txts, reloc->offset); if (ret < 0) @@ -392,6 +392,9 @@ static unsigned tot_relsize(unsigned int *rel_entsize) */ static int mcount_adjust = 0; +/* Size of an entry in __mcount_loc; 4 or 8 */ +static size_t loc_size; + /* 32 bit and 64 bit are very similar */ #include "recordmcount.h" #define RECORD_MCOUNT_64 @@ -409,34 +412,6 @@ static int arm_is_fake_mcount(struct reloc const *rp) return 1; } -/* 64-bit EM_MIPS has weird ELF64_Rela.r_info. - * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf - * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40] - * to imply the order of the members; the spec does not say so. - * typedef unsigned char Elf64_Byte; - * fails on MIPS64 because their already has it! - */ - -typedef uint8_t myElf64_Byte; /* Type for a 8-bit quantity. */ - -union mips_r_info { - Elf64_Xword r_info; - struct { - Elf64_Word r_sym; /* Symbol index. */ - myElf64_Byte r_ssym;/* Special symbol. */ - myElf64_Byte r_type3; /* Third relocation. */ - myElf64_Byte r_type2; /* Second relocation. */ - myElf64_Byte r_type;/* First relocation. */ - } r_mips; -}; - -static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type) -{ - rp->r_info = ((union mips_r_info){ - .r_mips = { .r_sym = w(sym), .r_type = type } - }).r_info; -} - static int do_file(char const *const fname) { unsigned int reltype = 0; @@ -552,6 +527,7 @@ static int do_file(char const *const fname) reltype = R_MIPS_32; is_fake_mcount = MIPS_is_fake_mcount; } + loc_size = 4; rc = do32(reltype); break; case ELFCLASS64: { @@ -567,9 +543,9 @@ static int do_file(char const *const fname) } if (lf->ehdr.e_machine == EM_MIPS) { reltype = R_MIPS_64; - Elf64_r_info = MIPS64_r_info; is_fake_mcount = MIPS_is_fake_mcount; } + loc_size = 8; rc = do64(reltype); break; } diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index ce88f0c2f79b..1d11dfc40d09 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -19,86 +19,63 @@ */ #undef sift_rel_mcount #undef do_func -#undef Elf_Shdr -#undef Elf_Rel #undef Elf_Rela -#undef ELF_R_INFO -#undef Elf_r_info -#undef fn_ELF_R_INFO -#undef uint_t -#undef _w -#undef _size #ifdef RECORD_MCOUNT_64 # define sift_rel_mcount sift64_rel_mcount # define do_func do64 -# define Elf_Rel Elf64_Rel # define Elf_Rela Elf64_Rela -# define ELF_R_INFOELF64_R_INFO -# defi
[RFC][PATCH v5 50/51] objtool: mcount: Remove useless lookup
Since the relocation section's sh_info points back to the text section it applies to and we already have that we can just pass it in and greatly simplify find_section_sym_index(). Signed-off-by: Matt Helsley --- tools/objtool/mcount.c | 39 +++ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 084bbc02de0c..a74625aed09b 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -198,35 +198,27 @@ static const unsigned int missing_sym = (unsigned int)-1; *Num:Value Size TypeBind Vis Ndx Name * 2: 0 SECTION LOCAL DEFAULT1 */ -static int find_section_sym_index(unsigned const txtndx, - char const *const txtname, - unsigned long *const recvalp, - unsigned int *sym_index) +static int find_section_sym_index(const struct section * const txts, + unsigned long *const recvalp, + unsigned int *sym_index) { struct symbol *sym; - struct section *txts = find_section_by_index(lf, txtndx); - - if (!txts) { - fprintf(stderr, "Cannot find section %u: %s.\n", - txtndx, txtname); - return missing_sym; - } list_for_each_entry(sym, &txts->symbol_list, list) { /* avoid symbols with weak binding */ - if ((sym->bind == STB_LOCAL) || (sym->bind == STB_GLOBAL)) { - /* function symbols on ARM have quirks, avoid them */ - if (lf->ehdr.e_machine == EM_ARM - && sym->type == STT_FUNC) - continue; - - *recvalp = sym->sym.st_value; - *sym_index = sym->idx; - return 0; - } + if ((sym->bind != STB_LOCAL) && (sym->bind != STB_GLOBAL)) + continue; + + /* function symbols on ARM have quirks, avoid them */ + if (lf->ehdr.e_machine == EM_ARM && sym->type == STT_FUNC) + continue; + + *recvalp = sym->sym.st_value; + *sym_index = sym->idx; + return 0; } fprintf(stderr, "Cannot find symbol for section %u: %s.\n", - txtndx, txtname); + txts->idx, txts->name); return missing_sym; } @@ -414,8 +406,7 @@ static int do_mcount(unsigned const reltype) unsigned long recval = 0; unsigned int recsym; - if (find_section_sym_index(sec->sh.sh_info, - txts->name, &recval, &recsym)) + if (find_section_sym_index(txts, &recval, &recsym)) goto out; sift_rel_mcount(&r_offset, sec, mrels, mlocs, -- 2.20.1
[RFC][PATCH v5 13/51] objtool: mcount: Return symbol from mcountsym
Before we can move this function out of the wrapper and into wordsize-independent code we need to return the relocation symbol information in a size-independent fashion. Previously we compared the raw info bits but that requires passing around an unsigned long. Instead we just use a pointer to the objtool struct symbol which callers can use as-needed. Reported-by: Kamalesh Babulal Signed-off-by: Matt Helsley Co-developed-by: Kamalesh Babulal Co-developed-by: Peter Zijlstra -- Thanks to Kamalesh Babulal for reporting this problem and suggesting a fix. Thanks to Peter Zijlstra for recommending an enhancement to the fix. --- tools/objtool/recordmcount.h | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index df8384f8e9e7..6ac120aa45af 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -271,7 +271,7 @@ static int append_func(Elf_Ehdr *const ehdr, return elf_write(lf); } -static unsigned get_mcountsym(struct reloc *reloc) +static struct symbol *get_mcountsym(struct reloc *reloc) { struct symbol *sym = reloc->sym; char const *symname = sym->name; @@ -283,8 +283,8 @@ static unsigned get_mcountsym(struct reloc *reloc) if (strcmp(mcount, symname) == 0 || (altmcount && strcmp(altmcount, symname) == 0) || (strcmp(fentry, symname) == 0)) - return GELF_R_INFO(reloc->sym->idx, reloc->type); - return 0; + return sym; + return NULL; } /* @@ -303,14 +303,14 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, uint_t *const mloc0 = mlocp; Elf_Rel *mrelp = *mrelpp; unsigned int rel_entsize = rels->sh.sh_entsize; - unsigned mcountsym = 0; + struct symbol *mcountsym = NULL; struct reloc *reloc; list_for_each_entry(reloc, &rels->reloc_list, list) { if (!mcountsym) mcountsym = get_mcountsym(reloc); - if (mcountsym == GELF_R_INFO(reloc->sym->idx, reloc->type) && !is_fake_mcount(reloc)) { + if (mcountsym == reloc->sym && !is_fake_mcount(reloc)) { uint_t const addend = _w(reloc->offset - recval + mcount_adjust); mrelp->r_offset = _w(offbase @@ -342,7 +342,7 @@ static int nop_mcount(struct section * const rels, + (void *)ehdr); struct reloc *reloc; Elf_Shdr const *const shdr = &shdr0[rels->sh.sh_info]; - unsigned mcountsym = 0; + struct symbol *mcountsym = NULL; int once = 0; list_for_each_entry(reloc, &rels->reloc_list, list) { @@ -351,7 +351,7 @@ static int nop_mcount(struct section * const rels, if (!mcountsym) mcountsym = get_mcountsym(reloc); - if (mcountsym == GELF_R_INFO(reloc->sym->idx, reloc->type) && !is_fake_mcount(reloc)) { + if (mcountsym == reloc->sym && !is_fake_mcount(reloc)) { if (make_nop) { ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + reloc->offset); if (ret < 0) -- 2.20.1
[RFC][PATCH v5 49/51] objtool: mcount: Remove relocation size check
Rather than use the size of the relocations check the section header type directly to see if the mcount relocations should be rel or rela relocations. Signed-off-by: Matt Helsley --- tools/objtool/elf.c| 4 ++-- tools/objtool/elf.h| 2 +- tools/objtool/mcount.c | 15 +-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 733e10d4a574..4948df31bba0 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -642,8 +642,8 @@ static int read_relocs(struct elf *elf) sec->base->reloc = sec; sec->mcountable = relocs_mcountable(sec); - if (sec->mcountable && !elf->mcount_rel_entsize) - elf->mcount_rel_entsize = sec->sh.sh_entsize; + if (sec->mcountable) + elf->mcount_r_addends = (sec->sh.sh_type == SHT_RELA); nr_reloc = 0; for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 8ece1ca79cca..f298e327af01 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -87,8 +87,8 @@ struct elf { Elf *elf; GElf_Ehdr ehdr; int fd; - size_t mcount_rel_entsize; bool changed; + bool mcount_r_addends; char *name; struct list_head sections; DECLARE_HASHTABLE(symbol_hash, ELF_HASH_BITS); diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 9527924af56b..084bbc02de0c 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -368,22 +368,17 @@ static void fill_mcount_locs(GElf_Sxword r_offset, GElf_Addr **rbuf, } /* Overall supervision for Elf32 ET_REL file. */ -static int do_mcount(unsigned const reltype, size_t rela_size) +static int do_mcount(unsigned const reltype) { - GElf_Sxword r_offset = 0; - struct section *sec, *mlocs, *mrels; const char * const mc_name = "__mcount_loc"; - - const unsigned int rel_entsize = lf->mcount_rel_entsize; + GElf_Sxword r_offset = 0; int result = -1; - bool is_rela; + const bool is_rela = lf->mcount_r_addends; if (find_section_by_name(lf, "__mcount_loc") != NULL) return 0; - is_rela = (rela_size == rel_entsize); - /* add section: __mcount_loc */ mlocs = elf_create_section(lf, mc_name, sizeof(GElf_Addr), 0); if (!mlocs) @@ -562,7 +557,7 @@ static int do_file(char const *const fname) is_fake_mcount = MIPS_is_fake_mcount; } loc_size = 4; - rc = do_mcount(reltype, sizeof(Elf32_Rela)); + rc = do_mcount(reltype); break; case ELFCLASS64: { if (lf->ehdr.e_ehsize != sizeof(Elf64_Ehdr) @@ -580,7 +575,7 @@ static int do_file(char const *const fname) is_fake_mcount = MIPS_is_fake_mcount; } loc_size = 8; - rc = do_mcount(reltype, sizeof(Elf64_Rela)); + rc = do_mcount(reltype); break; } } /* end switch */ -- 2.20.1
[RFC][PATCH v5 45/51] objtool: mcount: Move mcount section test to objtool ELF
In preparation for removing this first pass by mcount move the test for whether a section is mcountable into objtool's ELF read code, much like we did with the symbol name. A subsequent patch will eliminate the tot_relsize() function and thereby reduce the number of passes through the ELF data. Signed-off-by: Matt Helsley --- tools/objtool/elf.c| 16 tools/objtool/elf.h| 2 +- tools/objtool/mcount.c | 36 +++- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 666cbc01c332..dffdc3264a25 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -308,6 +308,20 @@ struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, uns return find_reloc_by_dest_range(elf, sec, offset, 1); } +/* Names of the sections that could contain calls to mcount. */ +static int is_mcounted_section_name(char const *const txtname) +{ + return strncmp(".text", txtname, 5) == 0 || + strcmp(".init.text", txtname) == 0 || + strcmp(".ref.text", txtname) == 0 || + strcmp(".sched.text",txtname) == 0 || + strcmp(".spinlock.text", txtname) == 0 || + strcmp(".irqentry.text", txtname) == 0 || + strcmp(".softirqentry.text", txtname) == 0 || + strcmp(".kprobes.text", txtname) == 0 || + strcmp(".cpuidle.text", txtname) == 0; +} + static int read_sections(struct elf *elf) { Elf_Scn *s = NULL; @@ -370,6 +384,8 @@ static int read_sections(struct elf *elf) } sec->len = sec->sh.sh_size; + sec->mcounted = is_mcounted_section_name(sec->name); + list_add_tail(&sec->list, &elf->sections); elf_hash_add(elf->section_hash, &sec->hash, sec->idx); elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index f0b02824f9d3..db207e93a1e6 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -39,7 +39,7 @@ struct section { char *name; int idx; unsigned int len; - bool changed, text, rodata, noinstr; + bool changed, text, rodata, noinstr, mcounted; }; enum symbol_class { diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 7d7843f7cd44..a75d918a9fa5 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -144,20 +144,6 @@ static int make_nop_arm64(struct section *txts, size_t const offset) return elf_write_insn(lf, txts, offset, 4, ideal_nop); } -/* Names of the sections that could contain calls to mcount. */ -static int is_mcounted_section_name(char const *const txtname) -{ - return strncmp(".text", txtname, 5) == 0 || - strcmp(".init.text", txtname) == 0 || - strcmp(".ref.text", txtname) == 0 || - strcmp(".sched.text",txtname) == 0 || - strcmp(".spinlock.text", txtname) == 0 || - strcmp(".irqentry.text", txtname) == 0 || - strcmp(".softirqentry.text", txtname) == 0 || - strcmp(".kprobes.text", txtname) == 0 || - strcmp(".cpuidle.text", txtname) == 0; -} - /* * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st * _mcount symbol is needed for dynamic function tracer, with it, to disable @@ -288,7 +274,7 @@ static int nop_mcount(struct section * const rels, return 0; } -static char const *has_rel_mcount(const struct section * const rels) +static struct section const *has_rel_mcount(const struct section * const rels) { const struct section *txts; if (rels->sh.sh_type != SHT_REL && rels->sh.sh_type != SHT_RELA) @@ -297,17 +283,17 @@ static char const *has_rel_mcount(const struct section * const rels) if ((txts->sh.sh_type != SHT_PROGBITS) || !(txts->sh.sh_flags & SHF_EXECINSTR)) return NULL; - return txts->name; + return txts; } static void tot_relsize(unsigned int *rel_entsize) { const struct section *sec; - char const *txtname; + const struct section *txts; list_for_each_entry(sec, &lf->sections, list) { - txtname = has_rel_mcount(sec); - if (!(txtname && is_mcounted_section_name(txtname))) + txts = has_rel_mcount(sec); + if (!(txts && txts->mcounted)) continue; *rel_entsize = sec->sh.sh_entsize; } @@ -441,25 +427,25 @@ static int do_
[RFC][PATCH v5 14/51] objtool: mcount: Move get_mcountsym
Now that it's been stripped of using the old recordmcount ELF wrapper get_mcountsym() is ready to be promoted out of the double-included wrapper header. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 16 tools/objtool/recordmcount.h | 19 --- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index dafa6dd10d04..d5f7c06afd57 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -422,6 +422,22 @@ static int is_mcounted_section_name(char const *const txtname) strcmp(".cpuidle.text", txtname) == 0; } +static struct symbol *get_mcountsym(struct reloc *reloc) +{ + struct symbol *sym = reloc->sym; + char const *symname = sym->name; + char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; + char const *fentry = "__fentry__"; + + if (symname[0] == '.') + ++symname; /* ppc64 hack */ + if (strcmp(mcount, symname) == 0 || + (altmcount && strcmp(altmcount, symname) == 0) || + (strcmp(fentry, symname) == 0)) + return sym; + return NULL; +} + static const unsigned int missing_sym = (unsigned int)-1; /* 32 bit and 64 bit are very similar */ diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 6ac120aa45af..210899819261 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -27,7 +27,6 @@ #undef find_section_sym_index #undef has_rel_mcount #undef tot_relsize -#undef get_mcountsym #undef get_shnum #undef set_shnum #undef get_shstrndx @@ -56,7 +55,6 @@ # define set_shnum set_shnum64 # define get_shstrndx get_shstrndx64 # define do_func do64 -# define get_mcountsym get_mcountsym_64 # define is_fake_mcountis_fake_mcount64 # define fn_is_fake_mcount fn_is_fake_mcount64 # define MIPS_is_fake_mcount MIPS64_is_fake_mcount @@ -84,7 +82,6 @@ # define set_shnum set_shnum32 # define get_shstrndx get_shstrndx32 # define do_func do32 -# define get_mcountsym get_mcountsym_32 # define is_fake_mcountis_fake_mcount32 # define fn_is_fake_mcount fn_is_fake_mcount32 # define MIPS_is_fake_mcount MIPS32_is_fake_mcount @@ -271,22 +268,6 @@ static int append_func(Elf_Ehdr *const ehdr, return elf_write(lf); } -static struct symbol *get_mcountsym(struct reloc *reloc) -{ - struct symbol *sym = reloc->sym; - char const *symname = sym->name; - char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; - char const *fentry = "__fentry__"; - - if (symname[0] == '.') - ++symname; /* ppc64 hack */ - if (strcmp(mcount, symname) == 0 || - (altmcount && strcmp(altmcount, symname) == 0) || - (strcmp(fentry, symname) == 0)) - return sym; - return NULL; -} - /* * Look at the relocations in order to find the calls to mcount. * Accumulate the section offsets that are found, and their relocation info, -- 2.20.1
[RFC][PATCH v5 09/51] objtool: mcount: Use libelf for section header names
Rather than passing in the string table contents as a parameter, pass in the section index of the string table and rely on libelf string table accessor functions to look up section names. Note that modifying the string table with libelf will come later so append_func() is unchanged. Signed-off-by: Matt Helsley --- tools/objtool/elf.c | 3 +- tools/objtool/elf.h | 1 + tools/objtool/recordmcount.c | 2 +- tools/objtool/recordmcount.h | 89 ++-- 4 files changed, 37 insertions(+), 58 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 6812cf74be9a..17e39b3a1719 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -185,8 +185,7 @@ struct section *find_section_by_name(const struct elf *elf, const char *name) return NULL; } -static struct section *find_section_by_index(struct elf *elf, -unsigned int idx) +struct section *find_section_by_index(const struct elf *elf, unsigned int idx) { struct section *sec; diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 6cc80a075166..60eb44661658 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -131,6 +131,7 @@ int elf_write(struct elf *elf); void elf_close(struct elf *elf); struct section *find_section_by_name(const struct elf *elf, const char *name); +struct section *find_section_by_index(const struct elf *elf, unsigned int idx); struct symbol *find_func_by_offset(struct section *sec, unsigned long offset); struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); struct symbol *find_symbol_by_name(const struct elf *elf, const char *name); diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 9941683b3f60..f20582ac99e2 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -177,7 +177,7 @@ static void *mmap_file(char const *fname) file_updated = 0; sb.st_size = 0; - lf = elf_open_read(fname, O_RDONLY); + lf = elf_open_read(fname, O_RDWR); if (!lf) { perror(fname); return NULL; diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 53abfd49a537..30f8913aa841 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -25,7 +25,6 @@ #undef sift_rel_mcount #undef nop_mcount #undef find_secsym_ndx -#undef __has_rel_mcount #undef has_rel_mcount #undef tot_relsize #undef get_mcountsym @@ -60,7 +59,6 @@ # define sift_rel_mcount sift64_rel_mcount # define nop_mcountnop_mcount_64 # define find_secsym_ndx find64_secsym_ndx -# define __has_rel_mcount __has64_rel_mcount # define has_rel_mcounthas64_rel_mcount # define tot_relsize tot64_relsize # define find_symtab find_symtab64 @@ -98,7 +96,6 @@ # define sift_rel_mcount sift32_rel_mcount # define nop_mcountnop_mcount_32 # define find_secsym_ndx find32_secsym_ndx -# define __has_rel_mcount __has32_rel_mcount # define has_rel_mcounthas32_rel_mcount # define tot_relsize tot32_relsize # define find_symtab find_symtab32 @@ -276,6 +273,7 @@ static int append_func(Elf_Ehdr *const ehdr, shstr->sh_size = _w(t); shstr->sh_offset = _w(sb.st_size); + t += sb.st_size; t += (_align & -t); /* word-byte align */ new_e_shoff = t; @@ -340,7 +338,7 @@ static int append_func(Elf_Ehdr *const ehdr, return -1; if (uwrite(ehdr, sizeof(*ehdr)) < 0) return -1; - return 0; + return elf_write(lf); } static unsigned get_mcountsym(Elf_Sym const *const sym0, @@ -365,7 +363,7 @@ static unsigned get_mcountsym(Elf_Sym const *const sym0, return mcountsym; } -static void get_sym_str_and_relp(GElf_Shdr const *const relhdr, +static void get_sym_str_and_relp(const struct section * const rels, Elf_Ehdr const *const ehdr, Elf_Sym const **sym0, char const **str0, @@ -373,10 +371,10 @@ static void get_sym_str_and_relp(GElf_Shdr const *const relhdr, { Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) + (void *)ehdr); - unsigned const symsec_sh_link = relhdr->sh_link; + unsigned const symsec_sh_link = rels->sh.sh_link; Elf_Shdr const *const symsec = &shdr0[symsec_sh_link]; Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; - Elf_Rel const *const rel0 = (Elf_Rel const *)(relhdr->sh_offset + Elf_Rel const *const rel0 = (Elf_Rel const *)(rels->sh.sh_offset + (void *)ehdr); *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset) @@ -396,7 +394,7 @@ static void get_sym_str_and_relp(GElf_Shdr const *const relhdr, st
[RFC][PATCH v5 38/51] objtool: mcount: mcount symbol name simplification
Remove gpfx -- the recognized prefix for the mcount symbol -- and just recognize any of the prefixes. This allows us to further substitute the various strings directly into the code rather than using variables. Signed-off-by: Matt Helsley --- tools/objtool/mcount.c | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 7e621769c488..4d6596a031bf 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -43,7 +43,6 @@ #define R_ARM_THM_CALL 10 -static char gpfx; /* prefix for global symbol name (sometimes '_') */ extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ static struct elf *lf; @@ -166,14 +165,16 @@ static struct symbol *get_mcount_sym(struct reloc *reloc) { struct symbol *sym = reloc->sym; char const *symname = sym->name; - char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; - char const *fentry = "__fentry__"; if (symname[0] == '.') - ++symname; /* ppc64 hack */ - if (strcmp(mcount, symname) == 0 || + symname++; /* ppc64 hack */ + + if (symname[0] == '_') + symname++; + + if (strcmp("mcount", symname) == 0 || (strcmp("__gnu_mcount_nc", symname) == 0) || - (strcmp(fentry, symname) == 0)) + (strcmp("_fentry__", symname) == 0)) return sym; return NULL; } @@ -550,7 +551,6 @@ static int do_file(char const *const fname) goto out; } - gpfx = '_'; switch (lf->ehdr.e_machine) { default: fprintf(stderr, "unrecognized e_machine %u %s\n", @@ -562,14 +562,12 @@ static int do_file(char const *const fname) make_nop = make_nop_x86; ideal_nop = ideal_nop5_x86_32; mcount_adjust = -1; - gpfx = 0; break; case EM_ARM: reltype = R_ARM_ABS32; make_nop = make_nop_arm; rel_type_nop = R_ARM_NONE; is_fake_mcount = arm_is_fake_mcount; - gpfx = 0; break; case EM_AARCH64: reltype = R_AARCH64_ABS64; @@ -582,7 +580,7 @@ static int do_file(char const *const fname) case EM_PPC:reltype = R_PPC_ADDR32; break; case EM_PPC64: reltype = R_PPC64_ADDR64; break; case EM_S390: /* reltype: e_class*/ break; - case EM_SH: reltype = R_SH_DIR32; gpfx = 0; break; + case EM_SH: reltype = R_SH_DIR32; break; case EM_SPARCV9: reltype = R_SPARC_64; break; case EM_X86_64: make_nop = make_nop_x86; @@ -590,7 +588,6 @@ static int do_file(char const *const fname) reltype = R_X86_64_64; rel_type_nop = R_X86_64_NONE; mcount_adjust = -1; - gpfx = 0; break; } /* end switch */ -- 2.20.1
[RFC][PATCH v5 51/51] objtool: mcount: Remove stale description
The comments at the top no longer reflect how we process the ELF contents. More helpful comments are inline with the code so we don't need the top comments either. Signed-off-by: Matt Helsley --- tools/objtool/mcount.c | 13 - 1 file changed, 13 deletions(-) diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index a74625aed09b..fa99bd2e9195 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -8,19 +8,6 @@ * Copyright 2010 Steven Rostedt , Red Hat Inc. */ -/* - * Strategy: alter the .o file in-place. - * - * Append a new STRTAB that has the new section names, followed by a new array - * ElfXX_Shdr[] that has the new section headers, followed by the section - * contents for __mcount_loc and its relocations. The old shstrtab strings, - * and the old ElfXX_Shdr[] array, remain as "garbage" (commonly, a couple - * kilobytes.) Subsequent processing by /bin/ld (or the kernel module loader) - * will ignore the garbage regions, because they are not designated by the - * new .e_shoff nor the new ElfXX_Shdr[]. [In order to remove the garbage, - * then use "ld -r" to create a new file that omits the garbage.] - */ - #include #include #include -- 2.20.1
[RFC][PATCH v5 35/51] objtool: mcount: Remove endian wrappers
Now that they're no longer used we can remove these endian wrappers. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 63 1 file changed, 63 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 7f4d18e83e24..ff52697613b1 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -149,53 +149,6 @@ static int make_nop_arm64(struct section *txts, size_t const offset) return 0; } -/* w8rev, w8nat, ...: Handle endianness. */ - -static uint64_t w8rev(uint64_t const x) -{ - return ((0xff & (x >> (0 * 8))) << (7 * 8)) - | ((0xff & (x >> (1 * 8))) << (6 * 8)) - | ((0xff & (x >> (2 * 8))) << (5 * 8)) - | ((0xff & (x >> (3 * 8))) << (4 * 8)) - | ((0xff & (x >> (4 * 8))) << (3 * 8)) - | ((0xff & (x >> (5 * 8))) << (2 * 8)) - | ((0xff & (x >> (6 * 8))) << (1 * 8)) - | ((0xff & (x >> (7 * 8))) << (0 * 8)); -} - -static uint32_t w4rev(uint32_t const x) -{ - return ((0xff & (x >> (0 * 8))) << (3 * 8)) - | ((0xff & (x >> (1 * 8))) << (2 * 8)) - | ((0xff & (x >> (2 * 8))) << (1 * 8)) - | ((0xff & (x >> (3 * 8))) << (0 * 8)); -} - -static uint32_t w2rev(uint16_t const x) -{ - return ((0xff & (x >> (0 * 8))) << (1 * 8)) - | ((0xff & (x >> (1 * 8))) << (0 * 8)); -} - -static uint64_t w8nat(uint64_t const x) -{ - return x; -} - -static uint32_t w4nat(uint32_t const x) -{ - return x; -} - -static uint32_t w2nat(uint16_t const x) -{ - return x; -} - -static uint64_t (*w8)(uint64_t); -static uint32_t (*w)(uint32_t); -static uint32_t (*w2)(uint16_t); - /* Names of the sections that could contain calls to mcount. */ static int is_mcounted_section_name(char const *const txtname) { @@ -571,22 +524,12 @@ static int do_file(char const *const fname) goto out; } - w = w4nat; - w2 = w2nat; - w8 = w8nat; switch (lf->ehdr.e_ident[EI_DATA]) { - static unsigned int const endian = 1; default: fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", lf->ehdr.e_ident[EI_DATA], fname); goto out; case ELFDATA2LSB: - if (*(unsigned char const *)&endian != 1) { - /* objtool is big endian, file.o is little endian. */ - w = w4rev; - w2 = w2rev; - w8 = w8rev; - } ideal_nop4_arm = ideal_nop4_arm_le; bl_mcount_arm = bl_mcount_arm_le; push_arm = push_arm_le; @@ -594,12 +537,6 @@ static int do_file(char const *const fname) push_bl_mcount_thumb = push_bl_mcount_thumb_le; break; case ELFDATA2MSB: - if (*(unsigned char const *)&endian != 0) { - /* objtool is little endian, file.o is big endian. */ - w = w4rev; - w2 = w2rev; - w8 = w8rev; - } ideal_nop4_arm = ideal_nop4_arm_be; bl_mcount_arm = bl_mcount_arm_be; push_arm = push_arm_be; -- 2.20.1
[RFC][PATCH v5 46/51] objtool: mcount: Flag mcount relocation sections
Move the check for relocations sections that apply to mcountable text sections into objtool's ELF code. Signed-off-by: Matt Helsley --- tools/objtool/elf.c| 13 + tools/objtool/elf.h| 2 +- tools/objtool/mcount.c | 36 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index dffdc3264a25..3708f85fe36d 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -385,6 +385,7 @@ static int read_sections(struct elf *elf) sec->len = sec->sh.sh_size; sec->mcounted = is_mcounted_section_name(sec->name); + sec->relocs_mcountable = false; list_add_tail(&sec->list, &elf->sections); elf_hash_add(elf->section_hash, &sec->hash, sec->idx); @@ -609,6 +610,17 @@ static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsi return 0; } +static bool relocs_mcountable(const struct section * const rels) +{ + const struct section *txts; + + txts = rels->base; + if ((txts->sh.sh_type != SHT_PROGBITS) || + !(txts->sh.sh_flags & SHF_EXECINSTR)) + return false; + return true; +} + static int read_relocs(struct elf *elf) { struct section *sec; @@ -630,6 +642,7 @@ static int read_relocs(struct elf *elf) } sec->base->reloc = sec; + sec->relocs_mcountable = relocs_mcountable(sec); nr_reloc = 0; for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index db207e93a1e6..92d3e68abf59 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -39,7 +39,7 @@ struct section { char *name; int idx; unsigned int len; - bool changed, text, rodata, noinstr, mcounted; + bool changed, text, rodata, noinstr, mcounted, relocs_mcountable; }; enum symbol_class { diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index a75d918a9fa5..9cd52beed871 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -274,28 +274,13 @@ static int nop_mcount(struct section * const rels, return 0; } -static struct section const *has_rel_mcount(const struct section * const rels) -{ - const struct section *txts; - if (rels->sh.sh_type != SHT_REL && rels->sh.sh_type != SHT_RELA) - return NULL; - txts = find_section_by_index(lf, rels->sh.sh_info); - if ((txts->sh.sh_type != SHT_PROGBITS) || - !(txts->sh.sh_flags & SHF_EXECINSTR)) - return NULL; - return txts; -} - static void tot_relsize(unsigned int *rel_entsize) { const struct section *sec; - const struct section *txts; list_for_each_entry(sec, &lf->sections, list) { - txts = has_rel_mcount(sec); - if (!(txts && txts->mcounted)) - continue; - *rel_entsize = sec->sh.sh_entsize; + if (sec->relocs_mcountable) + *rel_entsize = sec->sh.sh_entsize; } } @@ -429,8 +414,19 @@ static int do_mcount(unsigned const reltype, size_t rela_size) list_for_each_entry(sec, &lf->sections, list) { struct section const *txts; - txts = has_rel_mcount(sec); - if (txts && txts->mcounted) { + /* Find relocation sections.. */ + if (sec->sh.sh_type != SHT_REL && + sec->sh.sh_type != SHT_RELA) + continue; + /* Which may relocate mcount calls.. */ + if (!sec->relocs_mcountable) + continue; + txts = sec->base; + if (!txts) + continue; + + if (txts->mcounted) { + /* In mcountable text sections */ unsigned long recval = 0; unsigned int recsym; @@ -440,7 +436,7 @@ static int do_mcount(unsigned const reltype, size_t rela_size) sift_rel_mcount(&r_offset, sec, mrels, mlocs, recsym, recval, reltype, is_rela); - } else if (txts && (warn_on_notrace_sect || make_nop)) { + } else if (warn_on_notrace_sect || make_nop) { /* * This section is ignored by ftrace, but still * has mcount calls. Convert them to nops now. -- 2.20.1
[RFC][PATCH v5 43/51] objtool: check: Use class to recognize kcov calls
Suggested-by: Peter Zijlstra Signed-off-by: Matt Helsley --- tools/objtool/check.c | 3 +-- tools/objtool/elf.c | 7 +++ tools/objtool/elf.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 78375908acda..d08714b878c5 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -771,8 +771,7 @@ static int add_call_destinations(struct objtool_file *file) * so they need a little help, NOP out any KCOV calls from noinstr * text. */ - if (insn->sec->noinstr && - !strncmp(insn->call_dest->name, "__sanitizer_cov_", 16)) { + if (insn->sec->noinstr && insn->call_dest->class == SYM_KCOV) { if (reloc) { reloc->type = R_NONE; elf_write_reloc(file->elf, reloc); diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index d55d8fef11b4..666cbc01c332 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -402,6 +402,11 @@ static bool is_mcount_sym(const char *name) return false; } +static bool is_kcov_symbol(const char *name) +{ + return !strncmp(name, "__sanitize_cov_", 16); +} + static int read_symbols(struct elf *elf) { struct section *symtab, *symtab_shndx, *sec; @@ -473,6 +478,8 @@ static int read_symbols(struct elf *elf) if (is_mcount_sym(sym->name)) sym->class = SYM_MCOUNT; + else if (is_kcov_symbol(sym->name)) + sym->class = SYM_KCOV; sym->offset = sym->sym.st_value; sym->len = sym->sym.st_size; diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 13935edaff54..f0b02824f9d3 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -45,6 +45,7 @@ struct section { enum symbol_class { SYM_REGULAR = 0, SYM_MCOUNT = 1, + SYM_KCOV = 2, }; struct symbol { -- 2.20.1
[RFC][PATCH v5 33/51] objtool: mcount: Remove wrapper for ELF relocation type
Remove the last uses of the Elf_Rela wrapper by passing the size of the relocations we're dealing with as a parameter. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 4 ++-- tools/objtool/recordmcount.h | 7 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index b9f15fc1f40e..6db035252b6c 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -575,7 +575,7 @@ static int do_file(char const *const fname) is_fake_mcount = MIPS_is_fake_mcount; } loc_size = 4; - rc = do32(reltype); + rc = do32(reltype, sizeof(Elf32_Rela)); break; case ELFCLASS64: { if (lf->ehdr.e_ehsize != sizeof(Elf64_Ehdr) @@ -593,7 +593,7 @@ static int do_file(char const *const fname) is_fake_mcount = MIPS_is_fake_mcount; } loc_size = 8; - rc = do64(reltype); + rc = do64(reltype, sizeof(Elf64_Rela)); break; } } /* end switch */ diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 2dd303d51b78..07fc93917736 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -18,18 +18,15 @@ * Copyright 2010 Steven Rostedt , Red Hat Inc. */ #undef do_func -#undef Elf_Rela #ifdef RECORD_MCOUNT_64 # define do_func do64 -# define Elf_Rela Elf64_Rela #else # define do_func do32 -# define Elf_Rela Elf32_Rela #endif /* Overall supervision for Elf32 ET_REL file. */ -static int do_func(unsigned const reltype) +static int do_func(unsigned const reltype, size_t rela_size) { /* Upper bound on space: assume all relevant relocs are for mcount. */ unsigned totrelsz; @@ -68,7 +65,7 @@ static int do_func(unsigned const reltype) return -1; } - is_rela = (sizeof(Elf_Rela) == rel_entsize); + is_rela = (rela_size == rel_entsize); /* add section: __mcount_loc */ mlocs = elf_create_section(lf, mc_name, sizeof(*mloc0), 0); -- 2.20.1
[RFC][PATCH v5 42/51] objtool: mcount: Move mcount symbol name testing
Move the test for mcount symbols into the ELF code itself and set a class on indicator on the symbol. This simplifies mcount a little and tests the symbols names near where they're first touched so should be cache-hot and may also help us reduce the number of passes through the ELF contents needed for individual subcommands. Finally, if we manage to combine subcommands into a single exec of objtool the number of passes through the ELF data could be even further reduced. Suggested-by: Peter Zijlstra Signed-off-by: Matt Helsley --- tools/objtool/elf.c| 18 ++ tools/objtool/elf.h| 6 ++ tools/objtool/mcount.c | 31 +++ 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 8dcdea8020a5..d55d8fef11b4 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -387,6 +387,21 @@ static int read_sections(struct elf *elf) return 0; } +static bool is_mcount_sym(const char *name) +{ + if (name[0] == '.') + name++; /* ppc64 hack */ + + if (name[0] == '_') + name++; + + if (strcmp("mcount", name) == 0 || + (strcmp("__gnu_mcount_nc", name) == 0) || + (strcmp("_fentry__", name) == 0)) + return true; + return false; +} + static int read_symbols(struct elf *elf) { struct section *symtab, *symtab_shndx, *sec; @@ -456,6 +471,9 @@ static int read_symbols(struct elf *elf) } else sym->sec = find_section_by_index(elf, 0); + if (is_mcount_sym(sym->name)) + sym->class = SYM_MCOUNT; + sym->offset = sym->sym.st_value; sym->len = sym->sym.st_size; diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 09fa0d085341..13935edaff54 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -42,6 +42,11 @@ struct section { bool changed, text, rodata, noinstr; }; +enum symbol_class { + SYM_REGULAR = 0, + SYM_MCOUNT = 1, +}; + struct symbol { struct list_head list; struct rb_node node; @@ -55,6 +60,7 @@ struct symbol { unsigned long offset; unsigned int len; struct symbol *pfunc, *cfunc, *alias; + enum symbol_class class; bool uaccess_safe; }; diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 029e6e72c972..7fbde6ce6eb8 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -152,24 +152,6 @@ static int is_mcounted_section_name(char const *const txtname) strcmp(".cpuidle.text", txtname) == 0; } -static struct symbol *get_mcount_sym(struct reloc *reloc) -{ - struct symbol *sym = reloc->sym; - char const *symname = sym->name; - - if (symname[0] == '.') - symname++; /* ppc64 hack */ - - if (symname[0] == '_') - symname++; - - if (strcmp("mcount", symname) == 0 || - (strcmp("__gnu_mcount_nc", symname) == 0) || - (strcmp("_fentry__", symname) == 0)) - return sym; - return NULL; -} - /* * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st * _mcount symbol is needed for dynamic function tracer, with it, to disable @@ -266,16 +248,13 @@ static int nop_mcount(struct section * const rels, { struct reloc *reloc; struct section *txts = find_section_by_index(lf, rels->sh.sh_info); - struct symbol *mcount_sym = NULL; int once = 0; list_for_each_entry(reloc, &rels->reloc_list, list) { int ret = -1; - if (!mcount_sym) - mcount_sym = get_mcount_sym(reloc); - - if (mcount_sym == reloc->sym && !is_fake_mcount(reloc)) { + if (reloc->sym->class == SYM_MCOUNT && + !is_fake_mcount(reloc)) { if (make_nop) { ret = make_nop(txts, reloc->offset); if (ret < 0) @@ -355,16 +334,12 @@ static void sift_rel_mcount(GElf_Addr **mlocpp, { GElf_Rel *mrelp = *mrelpp; GElf_Rela *mrelap = *mrelpp; - struct symbol *mcount_sym = NULL; struct reloc *reloc; list_for_each_entry(reloc, &rels->reloc_list, list) { unsigned long addend; - if (!mcount_sym) - mcount_sym = get_mcount_sym(reloc); - - if (mcount_sym != reloc->sym || is_fake_mcount(reloc)) + if (reloc->sym->class == SYM_MCOUNT || is_fake_mcount(reloc)) continue; addend = reloc->offset - recval + mcount_adjust; -- 2.20.1
[RFC][PATCH v5 34/51] objtool: mcount: Remove wrapper double-include trick
We no longer need to double-include the recordmcount.h wrapper All of the types and functions that rely on them have been converted to using objtool's ELF code. This moves the remaining function to recordmcount.c and changes the function name to something slightly more descriptive while dropping the wrapped naming. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 113 -- tools/objtool/recordmcount.h | 132 --- 2 files changed, 107 insertions(+), 138 deletions(-) delete mode 100644 tools/objtool/recordmcount.h diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 6db035252b6c..7f4d18e83e24 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -442,10 +442,111 @@ static void sift_rel_mcount(GElf_Addr **mlocpp, *mrelpp = is_rela ? (void *)mrelap : (void *)mrelp; } -/* 32 bit and 64 bit are very similar */ -#include "recordmcount.h" -#define RECORD_MCOUNT_64 -#include "recordmcount.h" +/* Overall supervision for Elf32 ET_REL file. */ +static int do_mcount(unsigned const reltype, size_t rela_size) +{ + /* Upper bound on space: assume all relevant relocs are for mcount. */ + unsigned totrelsz; + + void *mrel0; + void *mrelp; + + GElf_Addr *mloc0; + GElf_Addr *mlocp; + GElf_Sxword r_offset = 0; + + struct section *sec, *mlocs, *mrels; + const char * const mc_name = "__mcount_loc"; + + unsigned int rel_entsize = 0; + int result = -1; + bool is_rela; + + if (find_section_by_name(lf, "__mcount_loc") != NULL) + return 0; + + totrelsz = tot_relsize(&rel_entsize); + if (totrelsz == 0) + return 0; + + mrel0 = malloc(totrelsz); + mrelp = mrel0; + if (!mrel0) + return -1; + + /* 2*sizeof(address) <= sizeof(Elf_Rel) */ + mloc0 = malloc(totrelsz>>1); + mlocp = mloc0; + if (!mloc0) { + free(mrel0); + return -1; + } + + is_rela = (rela_size == rel_entsize); + + /* add section: __mcount_loc */ + mlocs = elf_create_section(lf, mc_name, sizeof(*mloc0), 0); + if (!mlocs) + goto out; + mlocs->sh.sh_link = 0; + mlocs->sh.sh_info = 0; + mlocs->sh.sh_addralign = 8; + mlocs->data->d_buf = mloc0; + mlocs->data->d_type = ELF_T_ADDR; /* elf_xlatetof() conversion */ + + /* add section .rel[a]__mcount_loc */ + mrels = elf_create_reloc_section(lf, mlocs, +is_rela ? SHT_RELA : SHT_REL); + if (!mrels) + goto out; + mrels->sh.sh_flags = 0; /* clear SHF_INFO_LINK */ + mrels->data->d_buf = mrel0; + + list_for_each_entry(sec, &lf->sections, list) { + char const *txtname; + + txtname = has_rel_mcount(sec); + if (txtname && is_mcounted_section_name(txtname)) { + unsigned long recval = 0; + unsigned int recsym; + + if (find_section_sym_index(sec->sh.sh_info, + txtname, &recval, &recsym)) + goto out; + + sift_rel_mcount(&mlocp, &r_offset, &mrelp, sec, + recsym, recval, reltype, is_rela); + } else if (txtname && (warn_on_notrace_sect || make_nop)) { + /* +* This section is ignored by ftrace, but still +* has mcount calls. Convert them to nops now. +*/ + if (nop_mcount(sec, txtname) < 0) + goto out; + } + } + + if (mloc0 != mlocp) { + /* Update the section size and Elf_Data size */ + mlocs->sh.sh_size = (void *)mlocp - (void *)mloc0; + mlocs->len = mlocs->sh.sh_size; + mlocs->data->d_size = mlocs->len; + elf_flagdata(mlocs->data, ELF_C_SET, ELF_F_DIRTY); + + mrels->sh.sh_size = mrelp - mrel0; + mrels->len = mrels->sh.sh_size; + mrels->data->d_size = mrels->len; + elf_flagdata(mrels->data, ELF_C_SET, ELF_F_DIRTY); + + /* overwrite the ELF file */ + result = elf_write(lf); + } else + result = 0; +out: + free(mrel0); + free(mloc0); + return result; +} static int arm_is_fake_mcount(struct reloc const *rp) { @@ -575,7 +676,7 @@ static int do_file(char const *const fname) is_fake_mcount = MIPS_is_fake_mcount; }
[RFC][PATCH v5 40/51] objtool: mcount: const-ify ARM instruction patterns
Let the compiler know we won't be modifying the instruction patterns we use to determine how to turn ARM instruction(s) into nops, and the nop instruction(s) we'll put in their place. Also, while we're at it, convert to unsigned char because the next patch will need that as well. Signed-off-by: Matt Helsley --- tools/objtool/mcount.c | 42 +- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 5c59df0df97b..629eb7222ef3 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -47,10 +47,10 @@ extern int warn_on_notrace_sect; /* warn when section has mcount not being recor static struct elf *lf; -static const unsigned char ip_relative_call_x86[5] = { 0xe8, 0x00, 0x00, 0x00, 0x00 }; -static const unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; -static const unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; -static const unsigned char *ideal_nop; +static const char ip_relative_call_x86[5] = { 0xe8, 0x00, 0x00, 0x00, 0x00 }; +static const char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; +static const char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; +static const char *ideal_nop; static char rel_type_nop; @@ -58,7 +58,7 @@ static int (*make_nop)(struct section *, size_t const offset); static int make_nop_x86(struct section *txts, size_t const offset) { - unsigned char *op = txts->data->d_buf + offset - 1; + char *op = txts->data->d_buf + offset - 1; if (offset < 1) return -1; @@ -71,25 +71,25 @@ static int make_nop_x86(struct section *txts, size_t const offset) return 0; } -static unsigned char ideal_nop4_arm_le[4] = { 0x00, 0x00, 0xa0, 0xe1 }; /* mov r0, r0 */ -static unsigned char ideal_nop4_arm_be[4] = { 0xe1, 0xa0, 0x00, 0x00 }; /* mov r0, r0 */ -static unsigned char *ideal_nop4_arm; +static const char ideal_nop4_arm_le[4] = { 0x00, 0x00, 0xa0, 0xe1 }; /* mov r0, r0 */ +static const char ideal_nop4_arm_be[4] = { 0xe1, 0xa0, 0x00, 0x00 }; /* mov r0, r0 */ +static const char *ideal_nop4_arm; -static unsigned char bl_mcount_arm_le[4] = { 0xfe, 0xff, 0xff, 0xeb }; /* bl */ -static unsigned char bl_mcount_arm_be[4] = { 0xeb, 0xff, 0xff, 0xfe }; /* bl */ -static unsigned char *bl_mcount_arm; +static const char bl_mcount_arm_le[4] = { 0xfe, 0xff, 0xff, 0xeb }; /* bl */ +static const char bl_mcount_arm_be[4] = { 0xeb, 0xff, 0xff, 0xfe }; /* bl */ +static const char *bl_mcount_arm; -static unsigned char push_arm_le[4] = { 0x04, 0xe0, 0x2d, 0xe5 }; /* push {lr} */ -static unsigned char push_arm_be[4] = { 0xe5, 0x2d, 0xe0, 0x04 }; /* push {lr} */ -static unsigned char *push_arm; +static const char push_arm_le[4] = { 0x04, 0xe0, 0x2d, 0xe5 }; /* push {lr} */ +static const char push_arm_be[4] = { 0xe5, 0x2d, 0xe0, 0x04 }; /* push {lr} */ +static const char *push_arm; -static unsigned char ideal_nop2_thumb_le[2] = { 0x00, 0xbf }; /* nop */ -static unsigned char ideal_nop2_thumb_be[2] = { 0xbf, 0x00 }; /* nop */ -static unsigned char *ideal_nop2_thumb; +static const char ideal_nop2_thumb_le[2] = { 0x00, 0xbf }; /* nop */ +static const char ideal_nop2_thumb_be[2] = { 0xbf, 0x00 }; /* nop */ +static const char *ideal_nop2_thumb; -static unsigned char push_bl_mcount_thumb_le[6] = { 0x00, 0xb5, 0xff, 0xf7, 0xfe, 0xff }; /* push {lr}, bl */ -static unsigned char push_bl_mcount_thumb_be[6] = { 0xb5, 0x00, 0xf7, 0xff, 0xff, 0xfe }; /* push {lr}, bl */ -static unsigned char *push_bl_mcount_thumb; +static const char push_bl_mcount_thumb_le[6] = { 0x00, 0xb5, 0xff, 0xf7, 0xfe, 0xff }; /* push {lr}, bl */ +static const char push_bl_mcount_thumb_be[6] = { 0xb5, 0x00, 0xf7, 0xff, 0xff, 0xfe }; /* push {lr}, bl */ +static const char *push_bl_mcount_thumb; static int make_nop_arm(struct section *txts, size_t const offset) { @@ -124,7 +124,7 @@ static int make_nop_arm(struct section *txts, size_t const offset) return 0; } -static unsigned char ideal_nop4_arm64[4] = {0x1f, 0x20, 0x03, 0xd5}; +static const char ideal_nop4_arm64[4] = {0x1f, 0x20, 0x03, 0xd5}; static int make_nop_arm64(struct section *txts, size_t const offset) { uint32_t *ptr; -- 2.20.1
[RFC][PATCH v5 31/51] objtool: mcount: Use objtool relocation section
Now that we add an initially-empty relocation section and share the libelf data buffer from the beginning, we can safely use objtools elf_create_reloc_section() function to simplify the code further -- use the anticipated base section name, avoid the need to set sh_info, etc. The only remaining difference between this and the old recordmcount code is we didn't set SHF_INFO_LINK so we clear the sh_flags as before. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.h | 18 +- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 1d11dfc40d09..fc6346a7eaf5 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -92,7 +92,7 @@ static int do_func(unsigned const reltype) GElf_Sxword r_offset = 0; struct section *sec, *mlocs, *mrels; - const char *mc_name; + const char * const mc_name = "__mcount_loc"; unsigned int rel_entsize = 0; int result = -1; @@ -119,12 +119,9 @@ static int do_func(unsigned const reltype) } is_rela = (sizeof(Elf_Rela) == rel_entsize); - mc_name = is_rela - ? ".rela__mcount_loc" - : ".rel__mcount_loc"; /* add section: __mcount_loc */ - mlocs = elf_create_section(lf, mc_name + (is_rela ? 1 : 0) + strlen(".rel"), sizeof(*mloc0), 0); + mlocs = elf_create_section(lf, mc_name, sizeof(*mloc0), 0); if (!mlocs) goto out; mlocs->sh.sh_link = 0; @@ -134,17 +131,12 @@ static int do_func(unsigned const reltype) mlocs->data->d_type = ELF_T_ADDR; /* elf_xlatetof() conversion */ /* add section .rel[a]__mcount_loc */ - mrels = elf_create_section(lf, mc_name, rel_entsize, 0); + mrels = elf_create_reloc_section(lf, mlocs, +is_rela ? SHT_RELA : SHT_REL); if (!mrels) goto out; - /* Like elf_create_rela_section() without the name bits */ - mrels->sh.sh_type = is_rela ? SHT_RELA : SHT_REL; - mrels->sh.sh_flags = 0; /* clear SHF_ALLOC */ - mrels->sh.sh_link = find_section_by_name(lf, ".symtab")->idx; - mrels->sh.sh_info = mlocs->idx; - mrels->sh.sh_addralign = 8; + mrels->sh.sh_flags = 0; /* clear SHF_INFO_LINK */ mrels->data->d_buf = mrel0; - mrels->data->d_type = is_rela ? ELF_T_RELA : ELF_T_REL; /* elf_xlatetof() conversion */ list_for_each_entry(sec, &lf->sections, list) { char const *txtname; -- 2.20.1
[RFC][PATCH v5 48/51] objtool: mcount: Eliminate first pass
Determine the size of the mcount relocations in objtool's ELF reading code. This reduces the number of passes we make through the list of sections (which can become large due to things like -ffunction-sections). Signed-off-by: Matt Helsley --- tools/objtool/elf.c| 2 ++ tools/objtool/elf.h| 1 + tools/objtool/mcount.c | 16 +--- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 12bd889a62ba..733e10d4a574 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -642,6 +642,8 @@ static int read_relocs(struct elf *elf) sec->base->reloc = sec; sec->mcountable = relocs_mcountable(sec); + if (sec->mcountable && !elf->mcount_rel_entsize) + elf->mcount_rel_entsize = sec->sh.sh_entsize; nr_reloc = 0; for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index fb10f470d1a4..8ece1ca79cca 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -87,6 +87,7 @@ struct elf { Elf *elf; GElf_Ehdr ehdr; int fd; + size_t mcount_rel_entsize; bool changed; char *name; struct list_head sections; diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 80daf0e17eab..9527924af56b 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -274,19 +274,6 @@ static int nop_mcount(struct section * const rels, return 0; } -static void tot_relsize(unsigned int *rel_entsize) -{ - const struct section *sec; - - list_for_each_entry(sec, &lf->sections, list) { - if (sec->sh.sh_type != SHT_REL && - sec->sh.sh_type != SHT_RELA) - continue; - if (sec->mcountable) - *rel_entsize = sec->sh.sh_entsize; - } -} - /* zero or a small negative offset added to get the start of the call * instruction */ @@ -388,14 +375,13 @@ static int do_mcount(unsigned const reltype, size_t rela_size) struct section *sec, *mlocs, *mrels; const char * const mc_name = "__mcount_loc"; - unsigned int rel_entsize = 0; + const unsigned int rel_entsize = lf->mcount_rel_entsize; int result = -1; bool is_rela; if (find_section_by_name(lf, "__mcount_loc") != NULL) return 0; - tot_relsize(&rel_entsize); is_rela = (rela_size == rel_entsize); /* add section: __mcount_loc */ -- 2.20.1
[RFC][PATCH v5 25/51] objtool: mcount: Use ELF header from objtool
The ELF header is the very first structure in an ELF file. Rather than cast it from the file mapping we use the ELF header extracted via objtool's ELF code. This is the last usage of the open-coded mapping of the ELF file which we will remove in a later step. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 37 +--- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index aa35173de3d9..f8699e52e7e5 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -525,21 +525,19 @@ static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type) static int do_file(char const *const fname) { unsigned int reltype = 0; - Elf32_Ehdr *ehdr; int rc = -1; - ehdr = mmap_file(fname); - if (!ehdr) + if (!mmap_file(fname)) goto out; w = w4nat; w2 = w2nat; w8 = w8nat; - switch (ehdr->e_ident[EI_DATA]) { + switch (lf->ehdr.e_ident[EI_DATA]) { static unsigned int const endian = 1; default: fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", - ehdr->e_ident[EI_DATA], fname); + lf->ehdr.e_ident[EI_DATA], fname); goto out; case ELFDATA2LSB: if (*(unsigned char const *)&endian != 1) { @@ -568,18 +566,18 @@ static int do_file(char const *const fname) push_bl_mcount_thumb = push_bl_mcount_thumb_be; break; } /* end switch */ - if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 || - w2(ehdr->e_type) != ET_REL || - ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + if (memcmp(ELFMAG, lf->ehdr.e_ident, SELFMAG) != 0 || + lf->ehdr.e_type != ET_REL || + lf->ehdr.e_ident[EI_VERSION] != EV_CURRENT) { fprintf(stderr, "unrecognized ET_REL file %s\n", fname); goto out; } gpfx = '_'; - switch (w2(ehdr->e_machine)) { + switch (lf->ehdr.e_machine) { default: fprintf(stderr, "unrecognized e_machine %u %s\n", - w2(ehdr->e_machine), fname); + lf->ehdr.e_machine, fname); goto out; case EM_386: reltype = R_386_32; @@ -620,37 +618,36 @@ static int do_file(char const *const fname) break; } /* end switch */ - switch (ehdr->e_ident[EI_CLASS]) { + switch (lf->ehdr.e_ident[EI_CLASS]) { default: fprintf(stderr, "unrecognized ELF class %d %s\n", - ehdr->e_ident[EI_CLASS], fname); + lf->ehdr.e_ident[EI_CLASS], fname); goto out; case ELFCLASS32: - if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr) - || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { + if (lf->ehdr.e_ehsize != sizeof(Elf32_Ehdr) + || lf->ehdr.e_shentsize != sizeof(Elf32_Shdr)) { fprintf(stderr, "unrecognized ET_REL file: %s\n", fname); goto out; } - if (w2(ehdr->e_machine) == EM_MIPS) { + if (lf->ehdr.e_machine == EM_MIPS) { reltype = R_MIPS_32; is_fake_mcount = MIPS_is_fake_mcount; } rc = do32(reltype); break; case ELFCLASS64: { - Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; - if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr) - || w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { + if (lf->ehdr.e_ehsize != sizeof(Elf64_Ehdr) + || lf->ehdr.e_shentsize != sizeof(Elf64_Shdr)) { fprintf(stderr, "unrecognized ET_REL file: %s\n", fname); goto out; } - if (w2(ghdr->e_machine) == EM_S390) { + if (lf->ehdr.e_machine == EM_S390) { reltype = R_390_64; mcount_adjust_64 = -14; } - if (w2(ghdr->e_machine) == EM_MIPS) { + if (lf->ehdr.e_machine == EM_MIPS) { reltype = R_MIPS_64; Elf64_r_info = MIPS64_r_info; is_fake_mcount = MIPS_is_fake_mcount; -- 2.20.1
[RFC][PATCH v5 41/51] objtool: mcount: Convert nop writes to elf_write_insn()
objtool's elf_write_insn() does extra checking when writing to an instruction so use that rather than a plain memcpy(). Signed-off-by: Matt Helsley --- tools/objtool/mcount.c | 10 -- 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 629eb7222ef3..029e6e72c972 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -66,9 +66,7 @@ static int make_nop_x86(struct section *txts, size_t const offset) if (memcmp(op, ip_relative_call_x86, 5) != 0) return -1; - /* convert to nop */ - memcpy(op, ideal_nop, 5); - return 0; + return elf_write_insn(lf, txts, offset, 5, ideal_nop); } static const char ideal_nop4_arm_le[4] = { 0x00, 0x00, 0xa0, 0xe1 }; /* mov r0, r0 */ @@ -117,7 +115,8 @@ static int make_nop_arm(struct section *txts, size_t const offset) /* Convert to nop */ do { - memcpy(map + off, ideal_nop, nop_size); + if (elf_write_insn(lf, txts, off, nop_size, ideal_nop)) + return -1; off += nop_size; } while (--cnt > 0); @@ -136,8 +135,7 @@ static int make_nop_arm64(struct section *txts, size_t const offset) return -1; /* Convert to nop */ - memcpy(map + offset, ideal_nop, 4); - return 0; + return elf_write_insn(lf, txts, offset, 4, ideal_nop); } /* Names of the sections that could contain calls to mcount. */ -- 2.20.1
[RFC][PATCH v5 47/51] objtool: mcount: Merge section mcount flags
One flag is only for relocation sections and the other only for text (not relocation) sections so we can share the same flag and test the section type when we need to. Signed-off-by: Matt Helsley --- tools/objtool/elf.c| 5 ++--- tools/objtool/elf.h| 2 +- tools/objtool/mcount.c | 9 ++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 3708f85fe36d..12bd889a62ba 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -384,8 +384,7 @@ static int read_sections(struct elf *elf) } sec->len = sec->sh.sh_size; - sec->mcounted = is_mcounted_section_name(sec->name); - sec->relocs_mcountable = false; + sec->mcountable = is_mcounted_section_name(sec->name); list_add_tail(&sec->list, &elf->sections); elf_hash_add(elf->section_hash, &sec->hash, sec->idx); @@ -642,7 +641,7 @@ static int read_relocs(struct elf *elf) } sec->base->reloc = sec; - sec->relocs_mcountable = relocs_mcountable(sec); + sec->mcountable = relocs_mcountable(sec); nr_reloc = 0; for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 92d3e68abf59..fb10f470d1a4 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -39,7 +39,7 @@ struct section { char *name; int idx; unsigned int len; - bool changed, text, rodata, noinstr, mcounted, relocs_mcountable; + bool changed, text, rodata, noinstr, mcountable; }; enum symbol_class { diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 9cd52beed871..80daf0e17eab 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -279,7 +279,10 @@ static void tot_relsize(unsigned int *rel_entsize) const struct section *sec; list_for_each_entry(sec, &lf->sections, list) { - if (sec->relocs_mcountable) + if (sec->sh.sh_type != SHT_REL && + sec->sh.sh_type != SHT_RELA) + continue; + if (sec->mcountable) *rel_entsize = sec->sh.sh_entsize; } } @@ -419,13 +422,13 @@ static int do_mcount(unsigned const reltype, size_t rela_size) sec->sh.sh_type != SHT_RELA) continue; /* Which may relocate mcount calls.. */ - if (!sec->relocs_mcountable) + if (!sec->mcountable) continue; txts = sec->base; if (!txts) continue; - if (txts->mcounted) { + if (txts->mcountable) { /* In mcountable text sections */ unsigned long recval = 0; unsigned int recsym; -- 2.20.1
[RFC][PATCH v5 32/51] objtool: mcount: Move sift_rel_mcount out of wrapper file
Now that this function no longer uses any of the old recordmcount wrapper code we can move it out of the wrapper too. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 47 + tools/objtool/recordmcount.h | 50 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 34976f3294ac..b9f15fc1f40e 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -395,6 +395,53 @@ static int mcount_adjust = 0; /* Size of an entry in __mcount_loc; 4 or 8 */ static size_t loc_size; +/* + * Look at the relocations in order to find the calls to mcount. + * Accumulate the section offsets that are found, and their relocation info, + * onto the end of the existing arrays. + */ +static void sift_rel_mcount(GElf_Addr **mlocpp, + GElf_Sxword *r_offsetp, + void **const mrelpp, + const struct section * const rels, + unsigned const recsym_index, + unsigned long const recval, + unsigned const reltype, + bool is_rela) +{ + GElf_Rel *mrelp = *mrelpp; + GElf_Rela *mrelap = *mrelpp; + struct symbol *mcount_sym = NULL; + struct reloc *reloc; + + list_for_each_entry(reloc, &rels->reloc_list, list) { + unsigned long addend; + + if (!mcount_sym) + mcount_sym = get_mcount_sym(reloc); + + if (mcount_sym != reloc->sym || is_fake_mcount(reloc)) + continue; + + addend = reloc->offset - recval + mcount_adjust; + if (is_rela) { + mrelap->r_offset = *r_offsetp; + mrelap->r_info = GELF_R_INFO(recsym_index, reltype); + mrelap->r_addend = addend; + mrelap++; + **mlocpp = 0; + } else { + mrelp->r_offset = *r_offsetp; + mrelp->r_info = GELF_R_INFO(recsym_index, reltype); + mrelp++; + **mlocpp = addend; + } + (*mlocpp)++; + *r_offsetp += loc_size; + } + *mrelpp = is_rela ? (void *)mrelap : (void *)mrelp; +} + /* 32 bit and 64 bit are very similar */ #include "recordmcount.h" #define RECORD_MCOUNT_64 diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index fc6346a7eaf5..2dd303d51b78 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -17,67 +17,17 @@ * This conversion to macros was done by: * Copyright 2010 Steven Rostedt , Red Hat Inc. */ -#undef sift_rel_mcount #undef do_func #undef Elf_Rela #ifdef RECORD_MCOUNT_64 -# define sift_rel_mcount sift64_rel_mcount # define do_func do64 # define Elf_Rela Elf64_Rela #else -# define sift_rel_mcount sift32_rel_mcount # define do_func do32 # define Elf_Rela Elf32_Rela #endif -/* - * Look at the relocations in order to find the calls to mcount. - * Accumulate the section offsets that are found, and their relocation info, - * onto the end of the existing arrays. - */ -static void sift_rel_mcount(GElf_Addr **mlocpp, - GElf_Sxword *r_offsetp, - void **const mrelpp, - const struct section * const rels, - unsigned const recsym_index, - unsigned long const recval, - unsigned const reltype, - bool is_rela) -{ - GElf_Rel *mrelp = *mrelpp; - GElf_Rela *mrelap = *mrelpp; - struct symbol *mcount_sym = NULL; - struct reloc *reloc; - - list_for_each_entry(reloc, &rels->reloc_list, list) { - unsigned long addend; - - if (!mcount_sym) - mcount_sym = get_mcount_sym(reloc); - - if (mcount_sym != reloc->sym || is_fake_mcount(reloc)) - continue; - - addend = reloc->offset - recval + mcount_adjust; - if (is_rela) { - mrelap->r_offset = *r_offsetp; - mrelap->r_info = GELF_R_INFO(recsym_index, reltype); - mrelap->r_addend = addend; - mrelap++; - **mlocpp = 0; - } else { - mrelp->r_offset = *r_offsetp; - mrelp->r_info = GELF_R_INFO(recsym_index, reltype); - mrelp++; - **mlocpp = addend; - } -
[RFC][PATCH v5 44/51] objtool: mcount: Keep lists locations and relocations
To reduce the need for an initial pass through the sections we need to keep lists of mcount call locations and suitable relocations. A subsequent patch will eliminate the need for the first pass entirely. Introduce a new list for the locations and reuse objtool's relocation lists respectively. Signed-off-by: Matt Helsley --- tools/objtool/mcount.c | 133 +++-- 1 file changed, 75 insertions(+), 58 deletions(-) diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 7fbde6ce6eb8..7d7843f7cd44 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -43,9 +43,15 @@ #define R_ARM_THM_CALL 10 +struct mcount_loc { + struct list_head list; + GElf_Addr loc; +}; + extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ static struct elf *lf; +static struct list_head mcount_locs; static const char ip_relative_call_x86[5] = { 0xe8, 0x00, 0x00, 0x00, 0x00 }; static const char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; @@ -294,20 +300,17 @@ static char const *has_rel_mcount(const struct section * const rels) return txts->name; } -static unsigned tot_relsize(unsigned int *rel_entsize) +static void tot_relsize(unsigned int *rel_entsize) { const struct section *sec; - unsigned totrelsz = 0; char const *txtname; list_for_each_entry(sec, &lf->sections, list) { txtname = has_rel_mcount(sec); if (!(txtname && is_mcounted_section_name(txtname))) continue; - totrelsz += sec->sh.sh_size; *rel_entsize = sec->sh.sh_entsize; } - return totrelsz; } /* zero or a small negative offset added to get the start of the call @@ -323,55 +326,89 @@ static size_t loc_size; * Accumulate the section offsets that are found, and their relocation info, * onto the end of the existing arrays. */ -static void sift_rel_mcount(GElf_Addr **mlocpp, - GElf_Sxword *r_offsetp, - void **const mrelpp, +static void sift_rel_mcount(GElf_Sxword *r_offsetp, const struct section * const rels, + struct section *mc_relocs, + struct section *mc_locs, unsigned const recsym_index, unsigned long const recval, unsigned const reltype, bool is_rela) { - GElf_Rel *mrelp = *mrelpp; - GElf_Rela *mrelap = *mrelpp; struct reloc *reloc; list_for_each_entry(reloc, &rels->reloc_list, list) { unsigned long addend; + struct mcount_loc *mc_loc; + struct reloc *mc_reloc; + + if (reloc->sym->class != SYM_MCOUNT || is_fake_mcount(reloc)) + continue; - if (reloc->sym->class == SYM_MCOUNT || is_fake_mcount(reloc)) + mc_loc = malloc(sizeof(*mc_loc)); + if (!mc_loc) { + perror("malloc"); continue; + } + mc_reloc = malloc(sizeof(*mc_reloc)); + if (!mc_reloc) { + perror("malloc"); + free(mc_loc); + continue; + } + memset(mc_reloc, 0, sizeof(*mc_reloc)); + memset(mc_loc, 0, sizeof(*mc_loc)); + mc_reloc->sec = mc_relocs; addend = reloc->offset - recval + mcount_adjust; if (is_rela) { - mrelap->r_offset = *r_offsetp; - mrelap->r_info = GELF_R_INFO(recsym_index, reltype); - mrelap->r_addend = addend; - mrelap++; - **mlocpp = 0; + mc_reloc->rela.r_offset = *r_offsetp; + mc_reloc->rela.r_info = GELF_R_INFO(recsym_index, reltype); + mc_reloc->rela.r_addend = addend; + mc_loc->loc = 0; } else { - mrelp->r_offset = *r_offsetp; - mrelp->r_info = GELF_R_INFO(recsym_index, reltype); - mrelp++; - **mlocpp = addend; + mc_reloc->rel.r_offset = *r_offsetp; + mc_reloc->rel.r_info = GELF_R_INFO(recsym_index, reltype); + mc_loc->loc = addend; } - (*mlocpp)++; + mc_reloc->offset = *r_offsetp; + mc_reloc->type = reltype; + mc_reloc->sec = mc_locs; + elf_add_reloc(lf, mc_reloc); + +
[RFC][PATCH v5 36/51] objtool: mcount: Rename to mcount.c
Now that we've converted recordmcount to a subcommand of objtool rename the .c file in order to follow the convention of the other objtool subcmds. Signed-off-by: Matt Helsley --- tools/objtool/Build| 2 +- tools/objtool/{recordmcount.c => mcount.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tools/objtool/{recordmcount.c => mcount.c} (100%) diff --git a/tools/objtool/Build b/tools/objtool/Build index f4f0515d4f91..7815a094c991 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -7,7 +7,7 @@ objtool-$(SUBCMD_CHECK) += special.o objtool-$(SUBCMD_ORC) += check.o objtool-$(SUBCMD_ORC) += orc_gen.o objtool-$(SUBCMD_ORC) += orc_dump.o -objtool-$(SUBCMD_MCOUNT) += recordmcount.o +objtool-$(SUBCMD_MCOUNT) += mcount.o objtool-y += builtin-check.o objtool-y += builtin-orc.o diff --git a/tools/objtool/recordmcount.c b/tools/objtool/mcount.c similarity index 100% rename from tools/objtool/recordmcount.c rename to tools/objtool/mcount.c -- 2.20.1
[RFC][PATCH v5 39/51] objtool: mcount: Verify x86 instruction with memcmp()
Instead of hard-coding what amounts to a memcmp() use memcmp to determine if the instruction we wish to replace matches what we expect. This makes the x86 code more like that of, for instance, ARM. Signed-off-by: Matt Helsley --- tools/objtool/mcount.c | 19 ++- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c index 4d6596a031bf..5c59df0df97b 100644 --- a/tools/objtool/mcount.c +++ b/tools/objtool/mcount.c @@ -47,9 +47,10 @@ extern int warn_on_notrace_sect; /* warn when section has mcount not being recor static struct elf *lf; -static unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; -static unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; -static unsigned char *ideal_nop; +static const unsigned char ip_relative_call_x86[5] = { 0xe8, 0x00, 0x00, 0x00, 0x00 }; +static const unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; +static const unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; +static const unsigned char *ideal_nop; static char rel_type_nop; @@ -57,20 +58,12 @@ static int (*make_nop)(struct section *, size_t const offset); static int make_nop_x86(struct section *txts, size_t const offset) { - uint32_t *ptr; - unsigned char *op; - void *map = txts->data->d_buf; + unsigned char *op = txts->data->d_buf + offset - 1; if (offset < 1) return -1; - /* Confirm we have 0xe8 0x0 0x0 0x0 0x0 */ - ptr = map + offset; - if (*ptr != 0) - return -1; - - op = map + offset - 1; - if (*op != 0xe8) + if (memcmp(op, ip_relative_call_x86, 5) != 0) return -1; /* convert to nop */ -- 2.20.1
[RFC][PATCH v5 08/51] objtool: mcount: Remove unused fname parameter
The name of the object file being processed is unused in the wrapper's leaf functions so we no longer need to pass it as a parameter. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 4 ++-- tools/objtool/recordmcount.h | 19 --- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index f585bf7f45f5..9941683b3f60 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -586,7 +586,7 @@ static int do_file(char const *const fname) reltype = R_MIPS_32; is_fake_mcount32 = MIPS32_is_fake_mcount; } - if (do32(ehdr, fname, reltype) < 0) + if (do32(ehdr, reltype) < 0) goto out; break; case ELFCLASS64: { @@ -607,7 +607,7 @@ static int do_file(char const *const fname) Elf64_r_info = MIPS64_r_info; is_fake_mcount64 = MIPS64_is_fake_mcount; } - if (do64(ghdr, fname, reltype) < 0) + if (do64(ghdr, reltype) < 0) goto out; break; } diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 4bd61c9d1fd5..53abfd49a537 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -548,8 +548,7 @@ static int find_secsym_ndx(unsigned const txtndx, /* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */ static char const * __has_rel_mcount(GElf_Shdr const *const relhdr, /* reltype */ Elf_Shdr const *const shdr0, -char const *const shstrtab, -char const *const fname) +char const *const shstrtab) { /* .sh_info depends on .sh_type == SHT_REL[,A] */ Elf_Shdr const *const txthdr = &shdr0[relhdr->sh_info]; @@ -563,25 +562,23 @@ static char const * __has_rel_mcount(GElf_Shdr const *const relhdr, /* reltype * static char const *has_rel_mcount(GElf_Shdr const *const relhdr, Elf_Shdr const *const shdr0, - char const *const shstrtab, - char const *const fname) + char const *const shstrtab) { if (relhdr->sh_type != SHT_REL && relhdr->sh_type != SHT_RELA) return NULL; - return __has_rel_mcount(relhdr, shdr0, shstrtab, fname); + return __has_rel_mcount(relhdr, shdr0, shstrtab); } static unsigned tot_relsize(Elf_Shdr const *const shdr0, - const char *const shstrtab, - const char *const fname) + const char *const shstrtab) { struct section *sec; unsigned totrelsz = 0; char const *txtname; list_for_each_entry(sec, &lf->sections, list) { - txtname = has_rel_mcount(&sec->sh, shdr0, shstrtab, fname); + txtname = has_rel_mcount(&sec->sh, shdr0, shstrtab); if (txtname && is_mcounted_section_name(txtname)) totrelsz += sec->sh.sh_size; } @@ -589,7 +586,7 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0, } /* Overall supervision for Elf32 ET_REL file. */ -static int do_func(Elf_Ehdr *const ehdr, char const *const fname, +static int do_func(Elf_Ehdr *const ehdr, unsigned const reltype) { Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) @@ -622,7 +619,7 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname, if (find_section_by_name(lf, "__mcount_loc") != NULL) return 0; - totrelsz = tot_relsize(shdr0, shstrtab, fname); + totrelsz = tot_relsize(shdr0, shstrtab); if (totrelsz == 0) return 0; mrel0 = umalloc(totrelsz); @@ -645,7 +642,7 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname, relhdr = &sec->sh; txtname = has_rel_mcount(relhdr, shdr0, - shstrtab, fname); + shstrtab); if (txtname && is_mcounted_section_name(txtname)) { unsigned int recsym; uint_t recval = 0; -- 2.20.1
[RFC][PATCH v5 20/51] objtool: mcount: Use objtool ELF to write
Rather than modify the pseudo-mapping of the ELF file directly, which is the recordmcount way of operating, use the objtool section list and generic ELF functions to modify the ELF file. This eliminates a bunch of code -- the ulseek() and uwrite() functions -- because it's used to patch the ELF data. Instead we rely on objtool's ELF code to handle updating the ELF file. This means a bunch of the odd bits in append_func() also go away since they did things like update the ELF header, add to the section table, and append the new section names to the string table -- all handled by objtool's ELF code. Since we no longer use the get/set_shnum() functions to determine the next section to allocate and set how many new sections there are we can also eliminate those two functions. One unusual part, with respect to objtool is the way we handle writing nops. Objtool is not designed to modify the an ELF text section directly (or at least I could not find and example to base this work on). So we break layering to access the "data" of the text section via the section's "data buffer". This is still cleaner -- we can now pass in the section struct and offset as separate parameters. Note that this patch does not move the associated parts out of the wrapper file. We postpone that cleanup for later so that it's easier to see the changes to the functions rather than obscuring them with the move. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 161 - tools/objtool/recordmcount.h | 167 --- 2 files changed, 53 insertions(+), 275 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 2225479157e5..c015091a8a8c 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -52,24 +52,9 @@ static struct stat sb; /* Remember .st_size, etc. */ static const char *altmcount; /* alternate mcount symbol name */ extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ static void *file_map; /* pointer of the mapped file */ -static void *file_end; /* pointer to the end of the mapped file */ -static int file_updated; /* flag to state file was changed */ -static void *file_ptr; /* current file pointer location */ - -static void *file_append; /* added to the end of the file */ -static size_t file_append_size; /* how much is added to end of file */ static struct elf *lf; -/* Per-file resource cleanup when multiple files. */ -static void file_append_cleanup(void) -{ - free(file_append); - file_append = NULL; - file_append_size = 0; - file_updated = 0; -} - static void mmap_cleanup(void) { if (!mmap_failed) @@ -82,72 +67,11 @@ static void mmap_cleanup(void) lf = NULL; } -/* ulseek, uwrite, ...: Check return value for errors. */ - -static off_t ulseek(off_t const offset, int const whence) -{ - switch (whence) { - case SEEK_SET: - file_ptr = file_map + offset; - break; - case SEEK_CUR: - file_ptr += offset; - break; - case SEEK_END: - file_ptr = file_map + (sb.st_size - offset); - break; - } - if (file_ptr < file_map) { - fprintf(stderr, "lseek: seek before file\n"); - return -1; - } - return file_ptr - file_map; -} - -static ssize_t uwrite(void const *const buf, size_t const count) -{ - size_t cnt = count; - off_t idx = 0; - - file_updated = 1; - - if (file_ptr + count >= file_end) { - off_t aoffset = (file_ptr + count) - file_end; - - if (aoffset > file_append_size) { - file_append = realloc(file_append, aoffset); - file_append_size = aoffset; - } - if (!file_append) { - perror("write"); - file_append_cleanup(); - mmap_cleanup(); - return -1; - } - if (file_ptr < file_end) { - cnt = file_end - file_ptr; - } else { - cnt = 0; - idx = aoffset - count; - } - } - - if (cnt) - memcpy(file_ptr, buf, cnt); - - if (cnt < count) - memcpy(file_append + idx, buf + cnt, count - cnt); - - file_ptr += count; - return count; -} - static void * umalloc(size_t size) { void *const addr = malloc(size); if (addr == 0) { fprintf(stderr, "malloc failed: %zu bytes\n", size); - file_append_cleanup(); mmap_cleanup(); return NULL; } @@ -173,8 +97,6 @@ static void *mmap_file(char const *fname) fd_map = -1; m
[RFC][PATCH v5 22/51] objtool: mcount: Move has_rel_mcount() and tot_relsize()
The has_rel_mcount() and tot_relsize() helpers are no longer dependent on the ELF wrapper so we can move them. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 26 ++ tools/objtool/recordmcount.h | 33 - 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index fae0b15d0632..918e47217379 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -446,6 +446,32 @@ static int nop_mcount(struct section * const rels, return 0; } +static char const *has_rel_mcount(const struct section * const rels) +{ + const struct section *txts; + if (rels->sh.sh_type != SHT_REL && rels->sh.sh_type != SHT_RELA) + return NULL; + txts = find_section_by_index(lf, rels->sh.sh_info); + if ((txts->sh.sh_type != SHT_PROGBITS) || + !(txts->sh.sh_flags & SHF_EXECINSTR)) + return NULL; + return txts->name; +} + +static unsigned tot_relsize(void) +{ + const struct section *sec; + unsigned totrelsz = 0; + char const *txtname; + + list_for_each_entry(sec, &lf->sections, list) { + txtname = has_rel_mcount(sec); + if (txtname && is_mcounted_section_name(txtname)) + totrelsz += sec->sh.sh_size; + } + return totrelsz; +} + /* 32 bit and 64 bit are very similar */ #include "recordmcount.h" #define RECORD_MCOUNT_64 diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 25028c61da2b..2733f7fde51d 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -20,8 +20,6 @@ #undef append_func #undef mcount_adjust #undef sift_rel_mcount -#undef has_rel_mcount -#undef tot_relsize #undef do_func #undef Elf_Shdr #undef Elf_Rel @@ -36,8 +34,6 @@ #ifdef RECORD_MCOUNT_64 # define append_func append64 # define sift_rel_mcount sift64_rel_mcount -# define has_rel_mcounthas64_rel_mcount -# define tot_relsize tot64_relsize # define do_func do64 # define mcount_adjust mcount_adjust_64 # define Elf_Rel Elf64_Rel @@ -51,8 +47,6 @@ #else # define append_func append32 # define sift_rel_mcount sift32_rel_mcount -# define has_rel_mcounthas32_rel_mcount -# define tot_relsize tot32_relsize # define do_func do32 # define mcount_adjust mcount_adjust_32 # define Elf_Rel Elf32_Rel @@ -165,33 +159,6 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, return mlocp; } -static char const *has_rel_mcount(const struct section * const rels) -{ - const struct section *txts; - if (rels->sh.sh_type != SHT_REL && rels->sh.sh_type != SHT_RELA) - return NULL; - txts = find_section_by_index(lf, rels->sh.sh_info); - if ((txts->sh.sh_type != SHT_PROGBITS) || - !(txts->sh.sh_flags & SHF_EXECINSTR)) - return NULL; - return txts->name; -} - - -static unsigned tot_relsize(void) -{ - const struct section *sec; - unsigned totrelsz = 0; - char const *txtname; - - list_for_each_entry(sec, &lf->sections, list) { - txtname = has_rel_mcount(sec); - if (txtname && is_mcounted_section_name(txtname)) - totrelsz += sec->sh.sh_size; - } - return totrelsz; -} - /* Overall supervision for Elf32 ET_REL file. */ static int do_func(unsigned const reltype) { -- 2.20.1
[RFC][PATCH v5 21/51] objtool: mcount: Move nop_mcount()
The nop_mcount() function overwrites mcount calls that should be ignored with no-ops. This operation varies by architecture and wordsize so we retain the function pointers used to implement the fundamental operation while nop_mcount() itself is responsible for walking the relocations, determining if they should be turned into no-ops, then calling the arch-specific code. Since none of these use the recordmcount ELF wrappers anymore we can move it out of the wrapper. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 47 + tools/objtool/recordmcount.h | 50 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index c015091a8a8c..fae0b15d0632 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -399,6 +399,53 @@ static int find_section_sym_index(unsigned const txtndx, return missing_sym; } +/* + * Read the relocation table again, but this time its called on sections + * that are not going to be traced. The mcount calls here will be converted + * into nops. + */ +static int nop_mcount(struct section * const rels, + const char *const txtname) +{ + struct reloc *reloc; + struct section *txts = find_section_by_index(lf, rels->sh.sh_info); + struct symbol *mcountsym = NULL; + int once = 0; + + list_for_each_entry(reloc, &rels->reloc_list, list) { + int ret = -1; + + if (!mcountsym) + mcountsym = get_mcountsym(reloc); + + if (mcountsym == reloc->sym && !is_fake_mcount(reloc)) { + if (make_nop) { + ret = make_nop(txts, reloc->offset); + if (ret < 0) + return -1; + } + if (warn_on_notrace_sect && !once) { + printf("Section %s has mcount callers being ignored\n", + txtname); + once = 1; + /* just warn? */ + if (!make_nop) + return 0; + } + } + + /* +* If we successfully removed the mcount, mark the relocation +* as a nop (don't do anything with it). +*/ + if (!ret) { + reloc->type = rel_type_nop; + rels->changed = true; + } + } + return 0; +} + /* 32 bit and 64 bit are very similar */ #include "recordmcount.h" #define RECORD_MCOUNT_64 diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 1f14c64ed484..25028c61da2b 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -20,7 +20,6 @@ #undef append_func #undef mcount_adjust #undef sift_rel_mcount -#undef nop_mcount #undef has_rel_mcount #undef tot_relsize #undef do_func @@ -37,7 +36,6 @@ #ifdef RECORD_MCOUNT_64 # define append_func append64 # define sift_rel_mcount sift64_rel_mcount -# define nop_mcountnop_mcount_64 # define has_rel_mcounthas64_rel_mcount # define tot_relsize tot64_relsize # define do_func do64 @@ -53,7 +51,6 @@ #else # define append_func append32 # define sift_rel_mcount sift32_rel_mcount -# define nop_mcountnop_mcount_32 # define has_rel_mcounthas32_rel_mcount # define tot_relsize tot32_relsize # define do_func do32 @@ -168,53 +165,6 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, return mlocp; } -/* - * Read the relocation table again, but this time its called on sections - * that are not going to be traced. The mcount calls here will be converted - * into nops. - */ -static int nop_mcount(struct section * const rels, - const char *const txtname) -{ - struct reloc *reloc; - struct section *txts = find_section_by_index(lf, rels->sh.sh_info); - struct symbol *mcountsym = NULL; - int once = 0; - - list_for_each_entry(reloc, &rels->reloc_list, list) { - int ret = -1; - - if (!mcountsym) - mcountsym = get_mcountsym(reloc); - - if (mcountsym == reloc->sym && !is_fake_mcount(reloc)) { - if (make_nop) { - ret = make_nop(txts, reloc->offset); - if (ret < 0) - return -1; - } - if (warn_on_notrace_sect &
[RFC][PATCH v5 15/51] objtool: mcount: Replace MIPS offset types
Replace MIPS is_fake_mcount code using Elf_Addr with unsigned long for the offsets. This is consistent with the way that objtool more generally treats offsets and removes the last use of the Elf_Addr wrapper. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.h | 9 +++-- 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 210899819261..dde2ec054e51 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -31,7 +31,6 @@ #undef set_shnum #undef get_shstrndx #undef do_func -#undef Elf_Addr #undef Elf_Ehdr #undef Elf_Shdr #undef Elf_Rel @@ -59,7 +58,6 @@ # define fn_is_fake_mcount fn_is_fake_mcount64 # define MIPS_is_fake_mcount MIPS64_is_fake_mcount # define mcount_adjust mcount_adjust_64 -# define Elf_Addr Elf64_Addr # define Elf_Ehdr Elf64_Ehdr # define Elf_Shdr Elf64_Shdr # define Elf_Rel Elf64_Rel @@ -86,7 +84,6 @@ # define fn_is_fake_mcount fn_is_fake_mcount32 # define MIPS_is_fake_mcount MIPS32_is_fake_mcount # define mcount_adjust mcount_adjust_32 -# define Elf_Addr Elf32_Addr # define Elf_Ehdr Elf32_Ehdr # define Elf_Shdr Elf32_Shdr # define Elf_Rel Elf32_Rel @@ -138,11 +135,11 @@ static int mcount_adjust = 0; static int MIPS_is_fake_mcount(struct reloc const *reloc) { - static Elf_Addr old_r_offset = ~(Elf_Addr)0; - Elf_Addr current_r_offset = reloc->offset; + static unsigned long old_r_offset = ~0UL; + unsigned long current_r_offset = reloc->offset; int is_fake; - is_fake = (old_r_offset != ~(Elf_Addr)0) && + is_fake = (old_r_offset != ~0UL) && (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET); old_r_offset = current_r_offset; -- 2.20.1
[RFC][PATCH v5 23/51] objtool: mcount: Move relocation entry size detection
Move where we detect the size of relocation entries we wish to use into the first loop over the sections. This will allow us to allocate the mcount location and relocation sections before the next loop that collects them. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 8 +--- tools/objtool/recordmcount.h | 5 ++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 918e47217379..29f299e5bb52 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -458,7 +458,7 @@ static char const *has_rel_mcount(const struct section * const rels) return txts->name; } -static unsigned tot_relsize(void) +static unsigned tot_relsize(unsigned int *rel_entsize) { const struct section *sec; unsigned totrelsz = 0; @@ -466,8 +466,10 @@ static unsigned tot_relsize(void) list_for_each_entry(sec, &lf->sections, list) { txtname = has_rel_mcount(sec); - if (txtname && is_mcounted_section_name(txtname)) - totrelsz += sec->sh.sh_size; + if (!(txtname && is_mcounted_section_name(txtname))) + continue; + totrelsz += sec->sh.sh_size; + *rel_entsize = sec->sh.sh_entsize; } return totrelsz; } diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 2733f7fde51d..5ca488f3471c 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -171,7 +171,7 @@ static int do_func(unsigned const reltype) uint_t * mloc0; uint_t * mlocp; - unsigned rel_entsize = 0; + unsigned int rel_entsize = 0; unsigned symsec_sh_link = 0; struct section *sec; @@ -181,7 +181,7 @@ static int do_func(unsigned const reltype) if (find_section_by_name(lf, "__mcount_loc") != NULL) return 0; - totrelsz = tot_relsize(); + totrelsz = tot_relsize(&rel_entsize); if (totrelsz == 0) return 0; mrel0 = umalloc(totrelsz); @@ -211,7 +211,6 @@ static int do_func(unsigned const reltype) if (result) goto out; - rel_entsize = sec->sh.sh_entsize; mlocp = sift_rel_mcount(mlocp, (void *)mlocp - (void *)mloc0, &mrelp, sec, recsym, (uint_t)recval, reltype); -- 2.20.1
[RFC][PATCH v5 24/51] objtool: mcount: Only keep ELF file size
Since we're no longer writing to the ELF file mapping and we're not appending to it we don't need to keep more information from the stat structure. At the same time we can give the smaller global variable a better name. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 29f299e5bb52..aa35173de3d9 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -48,17 +48,17 @@ static int fd_map; /* File descriptor for file being modified. */ static int mmap_failed; /* Boolean flag. */ static char gpfx; /* prefix for global symbol name (sometimes '_') */ -static struct stat sb; /* Remember .st_size, etc. */ static const char *altmcount; /* alternate mcount symbol name */ extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ static void *file_map; /* pointer of the mapped file */ +static size_t file_map_size; /* original ELF file size */ static struct elf *lf; static void mmap_cleanup(void) { if (!mmap_failed) - munmap(file_map, sb.st_size); + munmap(file_map, file_map_size); else free(file_map); file_map = NULL; @@ -93,11 +93,13 @@ static void * umalloc(size_t size) */ static void *mmap_file(char const *fname) { + struct stat sb; + /* Avoid problems if early cleanup() */ fd_map = -1; mmap_failed = 1; file_map = NULL; - sb.st_size = 0; + file_map_size = 0; lf = elf_open_read(fname, O_RDWR); if (!lf) { @@ -129,6 +131,7 @@ static void *mmap_file(char const *fname) } } else mmap_failed = 0; + file_map_size = sb.st_size; out: fd_map = -1; -- 2.20.1
[RFC][PATCH v5 17/51] objtool: mcount: Stop using ehdr in find_section_sym_index
We can use the objtool GElf_Ehdr structure to access ehdr here. This makes the function completely independent of the old recordmcount ELF wrapper. The next step will be to promote it to the C file. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.h | 13 ++--- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index 941f96e4f74b..cf420f9f64b0 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -225,7 +225,7 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, Elf_Rel **const mrelpp, const struct section * const rels, unsigned const recsym_index, - uint_t const recval, + unsigned long const recval, unsigned const reltype) { uint_t *const mloc0 = mlocp; @@ -319,9 +319,8 @@ static int nop_mcount(struct section * const rels, */ static int find_section_sym_index(unsigned const txtndx, char const *const txtname, - uint_t *const recvalp, - unsigned int *sym_index, - Elf_Ehdr const *const ehdr) + unsigned long *const recvalp, + unsigned int *sym_index) { struct symbol *sym; struct section *txts = find_section_by_index(lf, txtndx); @@ -336,7 +335,7 @@ static int find_section_sym_index(unsigned const txtndx, /* avoid symbols with weak binding */ if ((sym->bind == STB_LOCAL) || (sym->bind == STB_GLOBAL)) { /* function symbols on ARM have quirks, avoid them */ - if (w2(ehdr->e_machine) == EM_ARM + if (lf->ehdr.e_machine == EM_ARM && sym->type == STT_FUNC) continue; @@ -424,12 +423,12 @@ static int do_func(Elf_Ehdr *const ehdr, txtname = has_rel_mcount(sec); if (txtname && is_mcounted_section_name(txtname)) { + unsigned long recval = 0; unsigned int recsym; - uint_t recval = 0; symsec_sh_link = sec->sh.sh_link; result = find_section_sym_index(sec->sh.sh_info, - txtname, &recval, &recsym, ehdr); + txtname, &recval, &recsym); if (result) goto out; -- 2.20.1
[RFC][PATCH v5 18/51] objtool: mcount: Move find_section_sym_index()
This function is no longer dependent upon the old recordmcount ELF wrapper code -- it doesn't use the wrapper's Elf_* types nor does it call wrapped functions. Move it into the C file. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 42 tools/objtool/recordmcount.h | 47 +--- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index 24b019b82795..2225479157e5 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -482,6 +482,48 @@ static int (*is_fake_mcount)(struct reloc const *reloc) = fn_is_fake_mcount; static const unsigned int missing_sym = (unsigned int)-1; +/* + * Find a symbol in the given section, to be used as the base for relocating + * the table of offsets of calls to mcount. A local or global symbol suffices, + * but avoid a Weak symbol because it may be overridden; the change in value + * would invalidate the relocations of the offsets of the calls to mcount. + * Often the found symbol will be the unnamed local symbol generated by + * GNU 'as' for the start of each section. For example: + *Num:Value Size TypeBind Vis Ndx Name + * 2: 0 SECTION LOCAL DEFAULT1 + */ +static int find_section_sym_index(unsigned const txtndx, + char const *const txtname, + unsigned long *const recvalp, + unsigned int *sym_index) +{ + struct symbol *sym; + struct section *txts = find_section_by_index(lf, txtndx); + + if (!txts) { + fprintf(stderr, "Cannot find section %u: %s.\n", + txtndx, txtname); + return missing_sym; + } + + list_for_each_entry(sym, &txts->symbol_list, list) { + /* avoid symbols with weak binding */ + if ((sym->bind == STB_LOCAL) || (sym->bind == STB_GLOBAL)) { + /* function symbols on ARM have quirks, avoid them */ + if (lf->ehdr.e_machine == EM_ARM + && sym->type == STT_FUNC) + continue; + + *recvalp = sym->sym.st_value; + *sym_index = sym->idx; + return 0; + } + } + fprintf(stderr, "Cannot find symbol for section %u: %s.\n", + txtndx, txtname); + return missing_sym; +} + /* 32 bit and 64 bit are very similar */ #include "recordmcount.h" #define RECORD_MCOUNT_64 diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index cf420f9f64b0..eed592954f37 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -21,7 +21,6 @@ #undef mcount_adjust #undef sift_rel_mcount #undef nop_mcount -#undef find_section_sym_index #undef has_rel_mcount #undef tot_relsize #undef get_shnum @@ -44,7 +43,6 @@ # define append_func append64 # define sift_rel_mcount sift64_rel_mcount # define nop_mcountnop_mcount_64 -# define find_section_sym_indexfind64_section_sym_index # define has_rel_mcounthas64_rel_mcount # define tot_relsize tot64_relsize # define get_shnum get_shnum64 @@ -67,7 +65,6 @@ # define append_func append32 # define sift_rel_mcount sift32_rel_mcount # define nop_mcountnop_mcount_32 -# define find_section_sym_indexfind32_section_sym_index # define has_rel_mcounthas32_rel_mcount # define tot_relsize tot32_relsize # define get_shnum get_shnum32 @@ -307,48 +304,6 @@ static int nop_mcount(struct section * const rels, return 0; } -/* - * Find a symbol in the given section, to be used as the base for relocating - * the table of offsets of calls to mcount. A local or global symbol suffices, - * but avoid a Weak symbol because it may be overridden; the change in value - * would invalidate the relocations of the offsets of the calls to mcount. - * Often the found symbol will be the unnamed local symbol generated by - * GNU 'as' for the start of each section. For example: - *Num:Value Size TypeBind Vis Ndx Name - * 2: 0 SECTION LOCAL DEFAULT1 - */ -static int find_section_sym_index(unsigned const txtndx, - char const *const txtname, - unsigned long *const recvalp, - unsigned int *sym_index) -{ - struct symbol *sym; - struct section *txts = find_section_by_index(lf, txtndx); - - if (!txts) { - fprintf(stderr, "Cannot find section %u: %s.\n", - txtndx, txtname); -
[RFC][PATCH v5 11/51] objtool: mcount: Use symbol structs to find mcount relocations
Rather than open coding symbol name lookups in get_sym_and_*() we rename the structure and use objtool's lookup function to get the symbol name for a relocation. We also change the name of the function to better reflect its purpose. Signed-off-by: Matt Helsley --- tools/objtool/elf.c | 2 +- tools/objtool/elf.h | 1 + tools/objtool/recordmcount.h | 54 ++-- 3 files changed, 17 insertions(+), 40 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 17e39b3a1719..8dcdea8020a5 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -196,7 +196,7 @@ struct section *find_section_by_index(const struct elf *elf, unsigned int idx) return NULL; } -static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx) +struct symbol *find_symbol_by_index(const struct elf *elf, unsigned int idx) { struct symbol *sym; diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 60eb44661658..09fa0d085341 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -135,6 +135,7 @@ struct section *find_section_by_index(const struct elf *elf, unsigned int idx); struct symbol *find_func_by_offset(struct section *sec, unsigned long offset); struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); struct symbol *find_symbol_by_name(const struct elf *elf, const char *name); +struct symbol *find_symbol_by_index(const struct elf *elf, unsigned int idx); struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset); struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset); struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec, diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index b10f7fcd33c3..3dae878f11a8 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -31,7 +31,7 @@ #undef get_shnum #undef set_shnum #undef get_shstrndx -#undef get_sym_str_and_relp +#undef get_relp #undef do_func #undef Elf_Addr #undef Elf_Ehdr @@ -62,7 +62,7 @@ # define get_shnum get_shnum64 # define set_shnum set_shnum64 # define get_shstrndx get_shstrndx64 -# define get_sym_str_and_relp get_sym_str_and_relp_64 +# define get_relp get_relp_64 # define do_func do64 # define get_mcountsym get_mcountsym_64 # define is_fake_mcountis_fake_mcount64 @@ -97,7 +97,7 @@ # define get_shnum get_shnum32 # define set_shnum set_shnum32 # define get_shstrndx get_shstrndx32 -# define get_sym_str_and_relp get_sym_str_and_relp_32 +# define get_relp get_relp_32 # define do_func do32 # define get_mcountsym get_mcountsym_32 # define is_fake_mcountis_fake_mcount32 @@ -298,15 +298,10 @@ static int append_func(Elf_Ehdr *const ehdr, return elf_write(lf); } -static unsigned get_mcountsym(Elf_Sym const *const sym0, - Elf_Rel const *relp, - char const *const str0) +static unsigned get_mcountsym(Elf_Rel const *relp) { - unsigned mcountsym = 0; - - Elf_Sym const *const symp = - &sym0[Elf_r_sym(relp)]; - char const *symname = &str0[w(symp->st_name)]; + struct symbol *sym = find_symbol_by_index(lf, Elf_r_sym(relp)); + char const *symname = sym->name; char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; char const *fentry = "__fentry__"; @@ -315,31 +310,16 @@ static unsigned get_mcountsym(Elf_Sym const *const sym0, if (strcmp(mcount, symname) == 0 || (altmcount && strcmp(altmcount, symname) == 0) || (strcmp(fentry, symname) == 0)) - mcountsym = Elf_r_sym(relp); - - return mcountsym; + return Elf_r_sym(relp); + return 0; } -static void get_sym_str_and_relp(const struct section * const rels, -Elf_Ehdr const *const ehdr, -Elf_Sym const **sym0, -char const **str0, -Elf_Rel const **relp) +static void get_relp(const struct section * const rels, + Elf_Ehdr const *const ehdr, + Elf_Rel const **relp) { - Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) - + (void *)ehdr); - unsigned const symsec_sh_link = rels->sh.sh_link; - Elf_Shdr const *const symsec = &shdr0[symsec_sh_link]; - Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; Elf_Rel const *const rel0 = (Elf_Rel const *)(rels->sh.sh_offset + (void *)ehdr); - - *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset) -
[RFC][PATCH v5 05/51] objtool: recordmcount: Search for __mcount_loc before walking the sections
recordmcount iterates over the sections in the order they're listed in the ELF file and checks whether the section name indicates it's of interest. Objtool's elf code works differently -- it scans the elf file and builds up data structures representing the headers, sections, etc. and then supplies functions to search these structures. Both walk the elf file in order, however objtool uses more memory to enable faster searches it needs for other tools such as the reliable backtrace support offered by the ORC unwinder. Rather than walk the section table a second time in the recordmcount code, we use objtool's elf code to search for the section recordmcount is interested in. This also simplifies flow and means we can easily check for already-processed object files before we do any of the more complex things recordmcount does. This also allows us to remove the already_has_rel_mcount string pointer trick. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.c | 4 tools/objtool/recordmcount.h | 17 +++-- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c index b2c606eb269b..f585bf7f45f5 100644 --- a/tools/objtool/recordmcount.c +++ b/tools/objtool/recordmcount.c @@ -208,8 +208,6 @@ static void *mmap_file(char const *fname) } else mmap_failed = 0; out: - elf_close(lf); - lf = NULL; fd_map = -1; file_end = file_map + sb.st_size; @@ -424,8 +422,6 @@ static int is_mcounted_section_name(char const *const txtname) strcmp(".cpuidle.text", txtname) == 0; } -static char const *already_has_rel_mcount = "success"; /* our work here is done! */ - /* 32 bit and 64 bit are very similar */ #include "recordmcount.h" #define RECORD_MCOUNT_64 diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index f9b19524da11..a96ffcef515a 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -554,11 +554,6 @@ static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */ Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)]; char const *const txtname = &shstrtab[w(txthdr->sh_name)]; - if (strcmp("__mcount_loc", txtname) == 0) { - fprintf(stderr, "warning: __mcount_loc already exists: %s\n", - fname); - return already_has_rel_mcount; - } if (w(txthdr->sh_type) != SHT_PROGBITS || !(_w(txthdr->sh_flags) & SHF_EXECINSTR)) return NULL; @@ -587,10 +582,6 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0, for (; nhdr; --nhdr, ++shdrp) { txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname); - if (txtname == already_has_rel_mcount) { - totrelsz = 0; - break; - } if (txtname && is_mcounted_section_name(txtname)) totrelsz += _w(shdrp->sh_size); } @@ -628,6 +619,9 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname, int result = 0; + if (find_section_by_name(lf, "__mcount_loc") != NULL) + return 0; + totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname); if (totrelsz == 0) return 0; @@ -649,11 +643,6 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname, for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { char const *const txtname = has_rel_mcount(relhdr, shdr0, shstrtab, fname); - if (txtname == already_has_rel_mcount) { - result = 0; - file_updated = 0; - goto out; /* Nothing to be done; don't append! */ - } if (txtname && is_mcounted_section_name(txtname)) { unsigned int recsym; uint_t recval = 0; -- 2.20.1
[RFC][PATCH v5 06/51] objtool: recordmcount: Convert do_func() relhdrs
Use objtool's ELF data structures to visit the relocation sections in the top-level ELF file walking function, do_func(). This means we can pass pointers to the relocation header structures into nested functions and avoid the indexing patterns for them. These conversions don't use libelf/objtool to modify the ELF file -- it only changes the way we walk the ELF sections and do lookups to find the relocations. Signed-off-by: Matt Helsley --- tools/objtool/recordmcount.h | 61 +++- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h index a96ffcef515a..b46e855d32bf 100644 --- a/tools/objtool/recordmcount.h +++ b/tools/objtool/recordmcount.h @@ -364,7 +364,7 @@ static unsigned get_mcountsym(Elf_Sym const *const sym0, return mcountsym; } -static void get_sym_str_and_relp(Elf_Shdr const *const relhdr, +static void get_sym_str_and_relp(GElf_Shdr const *const relhdr, Elf_Ehdr const *const ehdr, Elf_Sym const **sym0, char const **str0, @@ -372,10 +372,10 @@ static void get_sym_str_and_relp(Elf_Shdr const *const relhdr, { Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) + (void *)ehdr); - unsigned const symsec_sh_link = w(relhdr->sh_link); + unsigned const symsec_sh_link = relhdr->sh_link; Elf_Shdr const *const symsec = &shdr0[symsec_sh_link]; Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; - Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset) + Elf_Rel const *const rel0 = (Elf_Rel const *)(relhdr->sh_offset + (void *)ehdr); *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset) @@ -395,9 +395,9 @@ static void get_sym_str_and_relp(Elf_Shdr const *const relhdr, static uint_t *sift_rel_mcount(uint_t *mlocp, unsigned const offbase, Elf_Rel **const mrelpp, - Elf_Shdr const *const relhdr, + GElf_Shdr const *const relhdr, Elf_Ehdr const *const ehdr, - unsigned const recsym, + unsigned const recsym_index, uint_t const recval, unsigned const reltype) { @@ -406,8 +406,8 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, Elf_Sym const *sym0; char const *str0; Elf_Rel const *relp; - unsigned rel_entsize = _w(relhdr->sh_entsize); - unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; + unsigned int rel_entsize = relhdr->sh_entsize; + unsigned const nrel = relhdr->sh_size / rel_entsize; unsigned mcountsym = 0; unsigned t; @@ -423,7 +423,7 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, _w(_w(relp->r_offset) - recval + mcount_adjust); mrelp->r_offset = _w(offbase + ((void *)mlocp - (void *)mloc0)); - Elf_r_info(mrelp, recsym, reltype); + Elf_r_info(mrelp, recsym_index, reltype); if (rel_entsize == sizeof(Elf_Rela)) { ((Elf_Rela *)mrelp)->r_addend = addend; *mlocp++ = 0; @@ -443,7 +443,7 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, * that are not going to be traced. The mcount calls here will be converted * into nops. */ -static int nop_mcount(Elf_Shdr const *const relhdr, +static int nop_mcount(GElf_Shdr const *const relhdr, Elf_Ehdr const *const ehdr, const char *const txtname) { @@ -452,9 +452,9 @@ static int nop_mcount(Elf_Shdr const *const relhdr, Elf_Sym const *sym0; char const *str0; Elf_Rel const *relp; - Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)]; - unsigned rel_entsize = _w(relhdr->sh_entsize); - unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; + Elf_Shdr const *const shdr = &shdr0[relhdr->sh_info]; + unsigned int rel_entsize = relhdr->sh_entsize; + unsigned const nrel = relhdr->sh_size / rel_entsize; unsigned mcountsym = 0; unsigned t; int once = 0; @@ -545,13 +545,13 @@ static int find_secsym_ndx(unsigned const txtndx, } /* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */ -static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */ +static char const * __has_rel_mcount(GElf_Shdr const *const relhdr, /* reltype */ Elf_Shdr const *const shdr0, ch
[RFC][PATCH v5 01/51] objtool: Factor out reasons to build objtool
Currently the reasons to build and run objtool are: Stack validation (objtool subcmds: orc + check) Orc data generation (objtool subcmds: orc) Code analysis (objtool subcmds: check) Since the reasons are varied and the stack validation step is skipped with a warning if libelf is missing, the logic of Kconfig and the Makefiles is somewhat messy and will only get messier the more subcommands objtool supports. In preparation for adding new subcommands, break up the current configurations such as CONFIG_STACK_VALIDATION, CONFIG_UNWINDER_ORC, etc. so that we translate them into the objtool subcommands that we need to build into objtool and whether the objtool pass is optional (SKIP_STACK_VALIDATION=1). This allows us to greatly simplify the objtool Makefile so that the arch-dependence of the subcommands can be encoded in the usual place, arch/Kconfig, rather than a bunch of per-supported-arch ifdef blocks in tools/objtool/Makefile. Signed-off-by: Matt Helsley --- Makefile | 15 --- arch/Kconfig | 23 +++ arch/x86/Kconfig.debug | 1 + lib/Kconfig.debug | 1 + tools/objtool/Makefile | 5 +++-- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index ae5d8220f431..cf731709ebe7 100644 --- a/Makefile +++ b/Makefile @@ -1051,18 +1051,19 @@ mod_sign_cmd = true endif export mod_sign_cmd +ifdef CONFIG_OBJTOOL_SUBCMDS HOST_LIBELF_LIBS = $(shell pkg-config libelf --libs 2>/dev/null || echo -lelf) - -ifdef CONFIG_STACK_VALIDATION - has_libelf := $(call try-run,\ +has_libelf := $(call try-run,\ echo "int main() {}" | $(HOSTCC) -xc -o /dev/null $(HOST_LIBELF_LIBS) -,1,0) - ifeq ($(has_libelf),1) -objtool_target := tools/objtool FORCE - else +ifeq ($(has_libelf),1) + objtool_target := tools/objtool FORCE +else + ifdef CONFIG_STACK_VALIDATION SKIP_STACK_VALIDATION := 1 export SKIP_STACK_VALIDATION endif -endif +endif # has_libelf +endif # CONFIG_OBJTOOL_SUBCMDS PHONY += prepare0 diff --git a/arch/Kconfig b/arch/Kconfig index 8cc35dc556c7..4919412031eb 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -767,6 +767,29 @@ config HAVE_STACK_VALIDATION Architecture supports the 'objtool check' host tool command, which performs compile-time stack metadata validation. +config OBJTOOL_SUBCMD_CHECK + bool + select OBJTOOL_SUBCMDS + help + Run the 'objtool check' host tool command, which + performs compile-time stack metadata validation. + +config OBJTOOL_SUBCMD_ORC + bool + select OBJTOOL_SUBCMDS + help + Run the 'objtool orc' host tool command, which collects information + enabling reliable runtime kernel stack traces. + +config OBJTOOL_SUBCMDS + bool + default n + help + Other configurations require running objtool host tool commands. + For example, stack validation is available on the architecture + (HAVE_STACK_VALIDATION=y) and has been enabled (STACK_VALIDATION=y) + which selects OBJTOOL_SUBCMD_CHECK and OBJTOOL_SUBCMDS + config HAVE_RELIABLE_STACKTRACE bool help diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 0dd319e6e5b4..4f2d596505c1 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -241,6 +241,7 @@ config UNWINDER_ORC bool "ORC unwinder" depends on X86_64 select STACK_VALIDATION + select OBJTOOL_SUBCMD_ORC help This option enables the ORC (Oops Rewind Capability) unwinder for unwinding kernel stack traces. It uses a custom data format which is diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index d74ac0fd6b2d..e38e6cb22aa5 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -386,6 +386,7 @@ config FRAME_POINTER config STACK_VALIDATION bool "Compile-time stack metadata validation" depends on HAVE_STACK_VALIDATION + select OBJTOOL_SUBCMD_CHECK default n help Add compile-time checks to validate stack metadata, including frame diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 7770edcda3a0..aa0c6d3d2d46 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 include ../scripts/Makefile.include include ../scripts/Makefile.arch +include $(OUTPUT)/../../include/config/auto.conf # always use the host compiler ifneq ($(LLVM),) @@ -47,8 +48,8 @@ CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) AWK = awk -SUBCMD_CHECK := n -SUBCMD_ORC := n +SUBCMD_CHECK := $(CONFIG_OBJTOOL_SUBCMD_CHECK) +SUBCMD_ORC := $(CONFIG_OBJTOOL_SUBCMD_ORC) ifeq ($(SRCARCH),x86) SUBCMD_CHECK := y -- 2.20.1
[RFC][PATCH v5 00/51] objtool: Make recordmcount a subcommand
1590785960.git.mhels...@vmware.com/ [5] https://lore.kernel.org/lkml/20190802134712.2d8cc...@gandalf.local.home/ [6] https://lore.kernel.org/lkml/cover.1586468801.git.mhels...@vmware.com/ Matt Helsley (51): objtool: Factor out reasons to build objtool objtool: Prepare to merge recordmcount objtool: Make recordmcount into mcount subcmd objtool: recordmcount: Start using objtool's elf wrapper objtool: recordmcount: Search for __mcount_loc before walking the sections objtool: recordmcount: Convert do_func() relhdrs objtool: mcount: Move nhdr into find_symtab() objtool: mcount: Remove unused fname parameter objtool: mcount: Use libelf for section header names objtool: mcount: Walk objtool Elf structs in find_secsym_ndx objtool: mcount: Use symbol structs to find mcount relocations objtool: mcount: Walk relocation lists objtool: mcount: Return symbol from mcountsym objtool: mcount: Move get_mcountsym objtool: mcount: Replace MIPS offset types objtool: mcount: Move is_fake_mcount() objtool: mcount: Stop using ehdr in find_section_sym_index objtool: mcount: Move find_section_sym_index() objtool: mcount: Restrict using ehdr in append_func() objtool: mcount: Use objtool ELF to write objtool: mcount: Move nop_mcount() objtool: mcount: Move has_rel_mcount() and tot_relsize() objtool: mcount: Move relocation entry size detection objtool: mcount: Only keep ELF file size objtool: mcount: Use ELF header from objtool objtool: mcount: Remove unused file mapping objtool: mcount: Reduce usage of _size wrapper objtool: mcount: Move mcount_adjust out of wrapper objtool: mcount: Pre-allocate new ELF sections objtool: mcount: Generic location and relocation table types objtool: mcount: Use objtool relocation section objtool: mcount: Move sift_rel_mcount out of wrapper file objtool: mcount: Remove wrapper for ELF relocation type objtool: mcount: Remove wrapper double-include trick objtool: mcount: Remove endian wrappers objtool: mcount: Rename to mcount.c objtool: mcount: Simplify mcount name matching objtool: mcount: mcount symbol name simplification objtool: mcount: Verify x86 instruction with memcmp() objtool: mcount: const-ify ARM instruction patterns objtool: mcount: Convert nop writes to elf_write_insn() objtool: mcount: Move mcount symbol name testing objtool: check: Use class to recognize kcov calls objtool: mcount: Keep lists locations and relocations objtool: mcount: Move mcount section test to objtool ELF objtool: mcount: Flag mcount relocation sections objtool: mcount: Merge section mcount flags objtool: mcount: Eliminate first pass objtool: mcount: Remove relocation size check objtool: mcount: Remove useless lookup objtool: mcount: Remove stale description Documentation/dontdiff | 2 +- Documentation/trace/ftrace-design.rst | 4 +- Documentation/trace/ftrace.rst | 6 +- Makefile | 39 +- arch/Kconfig | 23 + arch/arm64/include/asm/ftrace.h| 2 +- arch/x86/Kconfig.debug | 1 + arch/x86/include/asm/ftrace.h | 2 +- kernel/trace/Kconfig | 9 +- lib/Kconfig.debug | 1 + scripts/.gitignore | 1 - scripts/Makefile | 1 - scripts/Makefile.build | 22 +- scripts/recordmcount.c | 663 scripts/recordmcount.h | 692 - scripts/sorttable.h| 2 +- tools/objtool/.gitignore | 1 + tools/objtool/Build| 2 + tools/objtool/Makefile | 14 +- tools/objtool/builtin-mcount.c | 50 ++ tools/objtool/builtin.h| 1 + tools/objtool/check.c | 3 +- tools/objtool/elf.c| 60 +- tools/objtool/elf.h| 12 +- tools/objtool/mcount.c | 596 ++ tools/objtool/objtool.c| 1 + tools/objtool/objtool.h| 1 + {scripts => tools/objtool}/recordmcount.pl | 0 tools/objtool/weak.c | 5 + 29 files changed, 806 insertions(+), 1410 deletions(-) delete mode 100644 scripts/recordmcount.c delete mode 100644 scripts/recordmcount.h create mode 100644 tools/objtool/builtin-mcount.c create mode 100644 tools/objtool/mcount.c rename {scripts => tools/objtool}/recordmcount.pl (100%) base-commit: 14bda4e5293ed9722f1dc39b543024e37707d6c6 prerequisite-patch-id: b9f6483185e4e80fccbb6ec7276bf61ce0329472 prerequisite-patch-id: 6d3fec64974cdce64fec35141ff71f0532cb8c82 prerequisite-patch-id: b71e084f3d2adeb4d05e4327183b75b388a20e6d prerequisite-patch-id: 261f5d8102f4ecee86df2eb93be6a29495702717 prereq
[PATCH] pci: pcie: AER: Fix logging of Correctable errors
The AER documentation indicates that correctable (severity=Corrected) errors should be output as a warning so that users can filter these errors if they choose to; This functionality does not appear to have been implemented. This patch modifies the functions aer_print_error and __aer_print_error to send correctable errors as a warning (pci_warn), rather than as an error (pci_err). It partially addresses several bugs in relation to kernel message buffer spam for misbehaving devices - the root cause (possibly device firmware?) isn't addressed, but the dmesg output is less alarming for end users, and can be filtered separately from uncorrectable errors. This should hopefully reduce the need for users to disable AER to suppress corrected errors. Link: https://bugzilla.kernel.org/show_bug.cgi?id=201517 Link: https://bugzilla.kernel.org/show_bug.cgi?id=196183 Signed-off-by: Matt Jolly --- drivers/pci/pcie/aer.c | 36 ++-- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 3acf56683915..131ecc0df2cb 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -662,12 +662,18 @@ static void __aer_print_error(struct pci_dev *dev, errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ? aer_uncorrectable_error_string[i] : NULL; - if (errmsg) - pci_err(dev, " [%2d] %-22s%s\n", i, errmsg, - info->first_error == i ? " (First)" : ""); - else + if (errmsg) { + if (info->severity == AER_CORRECTABLE) { + pci_warn(dev, " [%2d] %-22s%s\n", i, errmsg, + info->first_error == i ? " (First)" : ""); + } else { + pci_err(dev, " [%2d] %-22s%s\n", i, errmsg, + info->first_error == i ? " (First)" : ""); + } + } else { pci_err(dev, " [%2d] Unknown Error Bit%s\n", i, info->first_error == i ? " (First)" : ""); + } } pci_dev_aer_stats_incr(dev, info); } @@ -686,13 +692,23 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) layer = AER_GET_LAYER_ERROR(info->severity, info->status); agent = AER_GET_AGENT(info->severity, info->status); - pci_err(dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n", - aer_error_severity_string[info->severity], - aer_error_layer[layer], aer_agent_string[agent]); + if (info->severity == AER_CORRECTABLE) { + pci_warn(dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n", + aer_error_severity_string[info->severity], + aer_error_layer[layer], aer_agent_string[agent]); - pci_err(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", - dev->vendor, dev->device, - info->status, info->mask); + pci_warn(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", + dev->vendor, dev->device, + info->status, info->mask); + } else { + pci_err(dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n", + aer_error_severity_string[info->severity], + aer_error_layer[layer], aer_agent_string[agent]); + + pci_err(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", + dev->vendor, dev->device, + info->status, info->mask); + } __aer_print_error(dev, info); -- 2.26.2
[PATCH] x86/asm/64: Align start of __clear_user() loop to 16-bytes
x86 CPUs can suffer severe performance drops if a tight loop, such as the ones in __clear_user(), straddles a 16-byte instruction fetch window, or worse, a 64-byte cacheline. This issues was discovered in the SUSE kernel with the following commit, 1153933703d9 ("x86/asm/64: Micro-optimize __clear_user() - Use immediate constants") which increased the code object size from 10 bytes to 15 bytes and caused the 8-byte copy loop in __clear_user() to be split across a 64-byte cacheline. Aligning the start of the loop to 16-bytes makes this fit neatly inside a single instruction fetch window again and restores the performance of __clear_user() which is used heavily when reading from /dev/zero. Here are some numbers from running libmicro's read_z* and pread_z* microbenchmarks which read from /dev/zero: Zen 1 (Naples) libmicro-file 5.7.0-rc6 5.7.0-rc6 5.7.0-rc6 revert-1153933703d9+ align16+ Time mean95-pread_z100k 9.9195 ( 0.00%) 5.9856 ( 39.66%) 5.9938 ( 39.58%) Time mean95-pread_z10k1.1378 ( 0.00%) 0.7450 ( 34.52%) 0.7467 ( 34.38%) Time mean95-pread_z1k 0.2623 ( 0.00%) 0.2251 ( 14.18%) 0.2252 ( 14.15%) Time mean95-pread_zw100k 9.9974 ( 0.00%) 6.0648 ( 39.34%) 6.0756 ( 39.23%) Time mean95-read_z100k9.8940 ( 0.00%) 5.9885 ( 39.47%) 5.9994 ( 39.36%) Time mean95-read_z10k 1.1394 ( 0.00%) 0.7483 ( 34.33%) 0.7482 ( 34.33%) Note that this doesn't affect Haswell or Broadwell microarchitectures which seem to avoid the alignment issue by executing the loop straight out of the Loop Stream Detector (verified using perf events). Fixes: 1153933703d9 ("x86/asm/64: Micro-optimize __clear_user() - Use immediate constants") Cc: "Grimm, Jon" Cc: "Kumar, Venkataramanan" CC: Jan Kara Cc: # v4.19+ Signed-off-by: Matt Fleming --- arch/x86/lib/usercopy_64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index fff28c6f73a2..b0dfac3d3df7 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -24,6 +24,7 @@ unsigned long __clear_user(void __user *addr, unsigned long size) asm volatile( " testq %[size8],%[size8]\n" " jz 4f\n" + " .align 16\n" "0: movq $0,(%[dst])\n" " addq $8,%[dst]\n" " decl %%ecx ; jnz 0b\n" -- 2.17.1
Re: [RFC][PATCH v4 18/32] objtool: mcount: Move nop_mcount()
On Fri, Jun 12, 2020 at 06:05:34PM +0200, Peter Zijlstra wrote: > On Fri, Jun 12, 2020 at 03:26:57PM +0200, Peter Zijlstra wrote: > > On Tue, Jun 02, 2020 at 12:50:11PM -0700, Matt Helsley wrote: > > > +static int nop_mcount(struct section * const rels, > > > + const char *const txtname) > > > +{ > > > + struct reloc *reloc; > > > + struct section *txts = find_section_by_index(lf, rels->sh.sh_info); > > > + unsigned mcountsym = 0; > > > + int once = 0; > > > + > > > + list_for_each_entry(reloc, &rels->reloc_list, list) { > > > + int ret = -1; > > > + > > > + if (!mcountsym) > > > + mcountsym = get_mcountsym(reloc); > > > + > > > + if (mcountsym == GELF_R_INFO(reloc->sym->idx, reloc->type) && > > > !is_fake_mcount(reloc)) { > > > > This makes no sense to me; why not have mcountsym be a 'struct symbol > > *' and have get_mcountsym() return one of those. > > > > if (reloc->sym == mcountsym && ... ) > > > > is much nicer, no? (this is already incorporated in my unposted revisions but...) > > On top of that, I suppose we can do something like the below. > > Then you can simply write: > > if (reloc->sym->class == SYM_MCOUNT && ..) This looks like a good way to move towards a "single pass" through the ELF data for mcount. What order do you want to see this patch go in? Before this series (i.e. perhaps just a kcov SYM_ class to start)? Early or late in this series? After? Right now I'm thinking of putting this on the end of my series because I'm focusing on converting recordmcount in the series and this isn't strictly necessary but is definitely nicer. > > --- > > diff --git a/kernel/locking/Makefile b/kernel/locking/Makefile > index 45452facff3b..94e4b8fcf9c1 100644 > --- a/kernel/locking/Makefile > +++ b/kernel/locking/Makefile > @@ -1,7 +1,7 @@ > # SPDX-License-Identifier: GPL-2.0 > # Any varying coverage in these files is non-deterministic > # and is generally not a function of system call inputs. > -KCOV_INSTRUMENT := n > +# KCOV_INSTRUMENT:= n > > obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o > > diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c > index 432417a83902..133c0c285be6 100644 > --- a/tools/objtool/elf.c > +++ b/tools/objtool/elf.c > @@ -341,6 +341,24 @@ static int read_sections(struct elf *elf) > return 0; > } > > +static bool is_mcount_symbol(const char *name) > +{ > + if (name[0] == '.') > + name++; > + > + if (name[0] == '_') > + name++; > + > + return !strcmp(name, "mcount", 6) || Looks like you intended this to be a strncmp() but I don't see a reason to use strncmp(). Am I missing something? > +!strcmp(name, "_fentry__") || > +!strcmp(name, "_gnu_mcount_nc"); > +} This mashes all of the arch-specific mcount name checks together. I don't see a problem with that because I doubt there will be a collision with other functions. Just to be careful I looked through the Clang and GCC sources, though I only dug through the history of Clang's output -- GCC's history with respect to mcount symbol names across architectures is much harder to trace so I only looked at the current sources. (the rest looks good) Cheers, -Matt Helsley
[tip: objtool/core] objtool: Rename rela to reloc
The following commit has been merged into the objtool/core branch of tip: Commit-ID: f1974222634010486c1692e843af0ab11304dd2c Gitweb: https://git.kernel.org/tip/f1974222634010486c1692e843af0ab11304dd2c Author:Matt Helsley AuthorDate:Fri, 29 May 2020 14:01:13 -07:00 Committer: Josh Poimboeuf CommitterDate: Mon, 01 Jun 2020 09:40:58 -05:00 objtool: Rename rela to reloc Before supporting additional relocation types rename the relevant types and functions from "rela" to "reloc". This work be done with the following regex: sed -e 's/struct rela/struct reloc/g' \ -e 's/\([_\*]\)rela\(s\{0,1\}\)/\1reloc\2/g' \ -e 's/tmprela\(s\{0,1\}\)/tmpreloc\1/g' \ -e 's/relasec/relocsec/g' \ -e 's/rela_list/reloc_list/g' \ -e 's/rela_hash/reloc_hash/g' \ -e 's/add_rela/add_reloc/g' \ -e 's/rela->/reloc->/g' \ -e '/rela[,\.]/{ s/\([^\.>]\)rela\([\.,]\)/\1reloc\2/g ; }' \ -e 's/rela =/reloc =/g' \ -e 's/relas =/relocs =/g' \ -e 's/relas\[/relocs[/g' \ -e 's/relaname =/relocname =/g' \ -e 's/= rela\;/= reloc\;/g' \ -e 's/= relas\;/= relocs\;/g' \ -e 's/= relaname\;/= relocname\;/g' \ -e 's/, rela)/, reloc)/g' \ -e 's/\([ @]\)rela\([ "]\)/\1reloc\2/g' \ -e 's/ rela$/ reloc/g' \ -e 's/, relaname/, relocname/g' \ -e 's/sec->rela/sec->reloc/g' \ -e 's/(\(!\{0,1\}\)rela/(\1reloc/g' \ -i \ arch.h \ arch/x86/decode.c \ check.c \ check.h \ elf.c \ elf.h \ orc_gen.c \ special.c Notable exceptions which complicate the regex include gelf_* library calls and standard/expected section names which still use "rela" because they encode the type of relocation expected. Also, keep "rela" in the struct because it encodes a specific type of relocation we currently expect. It will eventually turn into a member of an anonymous union when a susequent patch adds implicit addend, or "rel", relocation support. Signed-off-by: Matt Helsley Signed-off-by: Josh Poimboeuf --- tools/objtool/arch.h| 2 +- tools/objtool/arch/x86/decode.c | 2 +- tools/objtool/check.c | 196 +++ tools/objtool/check.h | 2 +- tools/objtool/elf.c | 138 +++--- tools/objtool/elf.h | 22 +-- tools/objtool/orc_gen.c | 46 +++ tools/objtool/special.c | 28 ++-- 8 files changed, 218 insertions(+), 218 deletions(-) diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h index eda15a5..d0969a9 100644 --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h @@ -82,6 +82,6 @@ bool arch_callee_saved_reg(unsigned char reg); unsigned long arch_jump_destination(struct instruction *insn); -unsigned long arch_dest_rela_offset(int addend); +unsigned long arch_dest_reloc_offset(int addend); #endif /* _ARCH_H */ diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 4b504fc..fe83d4c 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -67,7 +67,7 @@ bool arch_callee_saved_reg(unsigned char reg) } } -unsigned long arch_dest_rela_offset(int addend) +unsigned long arch_dest_reloc_offset(int addend) { return addend + 4; } diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 63d65a7..28ce311 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -352,7 +352,7 @@ static struct instruction *find_last_insn(struct objtool_file *file, static int add_dead_ends(struct objtool_file *file) { struct section *sec; - struct rela *rela; + struct reloc *reloc; struct instruction *insn; /* @@ -370,24 +370,24 @@ static int add_dead_ends(struct objtool_file *file) if (!sec) goto reachable; - list_for_each_entry(rela, &sec->rela_list, list) { - if (rela->sym->type != STT_SECTION) { + list_for_each_entry(reloc, &sec->reloc_list, list) { + if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", sec->name); return -1; } - insn = find_insn(file, rela->sym->sec, rela->addend); + insn = find_insn(file, reloc->sym->sec, reloc->addend); if (insn) insn = list_prev_entry(insn, list); - else if (rela->addend == rela->sym->sec->len) { - insn = find_last_insn(file, rela->sym->sec); + else if (reloc->
[tip: objtool/core] objtool: Add support for relocations without addends
The following commit has been merged into the objtool/core branch of tip: Commit-ID: fb414783b65c880606fbc1463e6849f017e60d46 Gitweb: https://git.kernel.org/tip/fb414783b65c880606fbc1463e6849f017e60d46 Author:Matt Helsley AuthorDate:Fri, 29 May 2020 14:01:14 -07:00 Committer: Josh Poimboeuf CommitterDate: Tue, 02 Jun 2020 15:37:04 -05:00 objtool: Add support for relocations without addends Currently objtool only collects information about relocations with addends. In recordmcount, which we are about to merge into objtool, some supported architectures do not use rela relocations. Signed-off-by: Matt Helsley Reviewed-by: Julien Thierry Reviewed-by: Kamalesh Babulal Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 145 ++- tools/objtool/elf.h | 7 +- tools/objtool/orc_gen.c | 2 +- 3 files changed, 134 insertions(+), 20 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 3160931..95d86bc 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -496,6 +496,32 @@ void elf_add_reloc(struct elf *elf, struct reloc *reloc) elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc)); } +static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx) +{ + if (!gelf_getrel(sec->data, i, &reloc->rel)) { + WARN_ELF("gelf_getrel"); + return -1; + } + reloc->type = GELF_R_TYPE(reloc->rel.r_info); + reloc->addend = 0; + reloc->offset = reloc->rel.r_offset; + *symndx = GELF_R_SYM(reloc->rel.r_info); + return 0; +} + +static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx) +{ + if (!gelf_getrela(sec->data, i, &reloc->rela)) { + WARN_ELF("gelf_getrela"); + return -1; + } + reloc->type = GELF_R_TYPE(reloc->rela.r_info); + reloc->addend = reloc->rela.r_addend; + reloc->offset = reloc->rela.r_offset; + *symndx = GELF_R_SYM(reloc->rela.r_info); + return 0; +} + static int read_relocs(struct elf *elf) { struct section *sec; @@ -505,7 +531,8 @@ static int read_relocs(struct elf *elf) unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0; list_for_each_entry(sec, &elf->sections, list) { - if (sec->sh.sh_type != SHT_RELA) + if ((sec->sh.sh_type != SHT_RELA) && + (sec->sh.sh_type != SHT_REL)) continue; sec->base = find_section_by_index(elf, sec->sh.sh_info); @@ -525,16 +552,17 @@ static int read_relocs(struct elf *elf) return -1; } memset(reloc, 0, sizeof(*reloc)); - - if (!gelf_getrela(sec->data, i, &reloc->rela)) { - WARN_ELF("gelf_getrela"); - return -1; + switch (sec->sh.sh_type) { + case SHT_REL: + if (read_rel_reloc(sec, i, reloc, &symndx)) + return -1; + break; + case SHT_RELA: + if (read_rela_reloc(sec, i, reloc, &symndx)) + return -1; + break; + default: return -1; } - - reloc->type = GELF_R_TYPE(reloc->rela.r_info); - reloc->addend = reloc->rela.r_addend; - reloc->offset = reloc->rela.r_offset; - symndx = GELF_R_SYM(reloc->rela.r_info); reloc->sym = find_symbol_by_index(elf, symndx); reloc->sec = sec; if (!reloc->sym) { @@ -722,7 +750,37 @@ struct section *elf_create_section(struct elf *elf, const char *name, return sec; } -struct section *elf_create_reloc_section(struct elf *elf, struct section *base) +static struct section *elf_create_rel_reloc_section(struct elf *elf, struct section *base) +{ + char *relocname; + struct section *sec; + + relocname = malloc(strlen(base->name) + strlen(".rel") + 1); + if (!relocname) { + perror("malloc"); + return NULL; + } + strcpy(relocname, ".rel"); + strcat(relocname, base->name); + + sec = elf_create_section(elf, relocname, sizeof(GElf_Rel), 0); + free(relocname); + if (!sec) + return NULL; + + base->reloc = sec; + sec->base = base; + + sec->sh.sh_type =
Re: [RFC][PATCH 2/3] objtool: Provide elf_write_{insn,reloc}()
On Tue, Jun 16, 2020 at 11:12:53AM +0200, Peter Zijlstra wrote: > On Fri, Jun 12, 2020 at 04:30:36PM +0200, Peter Zijlstra wrote: > > +int elf_write_insn(struct elf *elf, struct section *sec, > > + unsigned long offset, unsigned int len, > > + const char *insn) > > +{ > > + Elf_Data *data = sec->data; > > + > > + if (data->d_type != ELF_T_BYTE || data->d_off) { > > + WARN("write to unexpected data for section: %s", sec->name); > > + return -1; > > + } > > + > > + memcpy(data->d_buf + offset, insn, len); > > + elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY); > > + > > + sec->changed = true; > > + elf->changed = true; > > + > > + return 0; > > +} > > + > > +int elf_write_reloc(struct elf *elf, struct reloc *reloc) > > +{ > > + struct section *sec = reloc->sec; > > + > > + if (sec->sh.sh_type == SHT_REL) { > > + reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); > > + reloc->rel.r_offset = reloc->offset; > > + > > + if (!gelf_update_rel(sec->data, reloc->idx, &reloc->rel)) { > > + WARN_ELF("gelf_update_rel"); > > + return -1; > > + } > > + } else { > > + reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); > > + reloc->rela.r_addend = reloc->addend; > > + reloc->rela.r_offset = reloc->offset; > > + > > + if (!gelf_update_rela(sec->data, reloc->idx, &reloc->rela)) { > > + WARN_ELF("gelf_update_rela"); > > + return -1; > > + } > > + } > > + > > + sec->changed = true; > > + elf->changed = true; > > + > > + return 0; > > +} > > Doing the change Matt asked for #1, I realized that sec->changed is only > required if we need to rewrite the section header, neither of these two > changes requires that, they already mark the elf data dirty so > elf_update() DTRT. This is really useful information. As long as you're adding the elf->changed flag it might make sense to add this as a comment in the struct section definition or even rename sec->changed to reflect this (e.g. sec->shdr_changed). Cheers, -Matt Helsley
Re: [RFC][PATCH 1/3] objtool: Clean up elf_write() condition
On Fri, Jun 12, 2020 at 04:30:35PM +0200, Peter Zijlstra wrote: > With there being multiple ways to change the ELF data, let's more > concisely track modification. > > Signed-off-by: Peter Zijlstra (Intel) Would it make sense to set the relocation section's "changed" flag in addition to the elf struct's changed flag in elf_rebuild_reloc_section()? Right now I think the code is assuming that it's a newly created section but it would be more defensive to set it during a rebuild too I think. Otherwise looks good to me. > --- > tools/objtool/check.c |2 ++ > tools/objtool/elf.c |8 +++- > tools/objtool/elf.h |3 ++- > 3 files changed, 11 insertions(+), 2 deletions(-) > > --- a/tools/objtool/check.c > +++ b/tools/objtool/check.c > @@ -2779,7 +2779,9 @@ int check(const char *_objname, bool orc > ret = create_orc_sections(&file); > if (ret < 0) > goto out; > + } > > + if (file.elf->changed) { > ret = elf_write(file.elf); > if (ret < 0) > goto out; > --- a/tools/objtool/elf.c > +++ b/tools/objtool/elf.c > @@ -746,6 +746,8 @@ struct section *elf_create_section(struc > elf_hash_add(elf->section_hash, &sec->hash, sec->idx); > elf_hash_add(elf->section_name_hash, &sec->name_hash, > str_hash(sec->name)); > > + elf->changed = true; > + > return sec; > } > > @@ -862,7 +864,7 @@ int elf_rebuild_reloc_section(struct sec > return elf_rebuild_rela_section(sec, nr); > } > > -int elf_write(const struct elf *elf) > +int elf_write(struct elf *elf) > { > struct section *sec; > Elf_Scn *s; > @@ -879,6 +881,8 @@ int elf_write(const struct elf *elf) > WARN_ELF("gelf_update_shdr"); > return -1; > } > + > + sec->changed = false; > } > } > > @@ -891,6 +895,8 @@ int elf_write(const struct elf *elf) > return -1; > } > > + elf->changed = false; > + > return 0; > } > > --- a/tools/objtool/elf.h > +++ b/tools/objtool/elf.h > @@ -79,6 +79,7 @@ struct elf { > Elf *elf; > GElf_Ehdr ehdr; > int fd; > + bool changed; > char *name; > struct list_head sections; > DECLARE_HASHTABLE(symbol_hash, ELF_HASH_BITS); > @@ -121,7 +122,7 @@ struct elf *elf_open_read(const char *na > struct section *elf_create_section(struct elf *elf, const char *name, size_t > entsize, int nr); > struct section *elf_create_reloc_section(struct elf *elf, struct section > *base, int reltype); > void elf_add_reloc(struct elf *elf, struct reloc *reloc); > -int elf_write(const struct elf *elf); > +int elf_write(struct elf *elf); > void elf_close(struct elf *elf); > > struct section *find_section_by_name(const struct elf *elf, const char > *name); > >
Re: [RFC][PATCH 0/3] objtool: KCOV vs noinstr
On Fri, Jun 12, 2020 at 04:30:34PM +0200, Peter Zijlstra wrote: > Hi All, > > These patches go on top of objtool/core, although possibly we need them > earlier. > > In order to solve the KCOV-vs-noinstr situation, we need objtool to rewrite > calls to __sanitizer_cov_*() into NOPs, similar to what recordmcount does. > > I'm hoping the pending objtool-recordmcount patches can also reuse some of > this. This sounds great to me -- I'll have a look through your series and will try rebasing my work on this. Cheers, -Matt Helsley
Re: [RFC][PATCH v4 18/32] objtool: mcount: Move nop_mcount()
On Fri, Jun 12, 2020 at 03:26:56PM +0200, Peter Zijlstra wrote: > On Tue, Jun 02, 2020 at 12:50:11PM -0700, Matt Helsley wrote: > > +static int nop_mcount(struct section * const rels, > > + const char *const txtname) > > +{ > > + struct reloc *reloc; > > + struct section *txts = find_section_by_index(lf, rels->sh.sh_info); > > + unsigned mcountsym = 0; > > + int once = 0; > > + > > + list_for_each_entry(reloc, &rels->reloc_list, list) { > > + int ret = -1; > > + > > + if (!mcountsym) > > + mcountsym = get_mcountsym(reloc); > > + > > + if (mcountsym == GELF_R_INFO(reloc->sym->idx, reloc->type) && > > !is_fake_mcount(reloc)) { > > This makes no sense to me; why not have mcountsym be a 'struct symbol > *' and have get_mcountsym() return one of those. > > if (reloc->sym == mcountsym && ... ) > > is much nicer, no? Indeed! I'll change it from returning an unsigned long to struct symbol * before I move it out of the wrapper code. > > > + if (make_nop) { > > + ret = make_nop(txts, reloc->offset); > > + if (ret < 0) > > + return -1; > > + } > > + if (warn_on_notrace_sect && !once) { > > + printf("Section %s has mcount callers being > > ignored\n", > > + txtname); > > + once = 1; > > + /* just warn? */ > > + if (!make_nop) > > + return 0; > > + } > > + } > > + > > + /* > > +* If we successfully removed the mcount, mark the relocation > > +* as a nop (don't do anything with it). > > +*/ > > + if (!ret) { > > + reloc->type = rel_type_nop; > > + rels->changed = true; > > I have an elf_write_rela(), I'll make sure to Cc you. Thanks! I might also make use of your patch to rewrite instructions. We need a way to turn certain prologue instructions into nops. Would it be more widely useful to move that functionality out of mcount and into the objtool ELF/per-arch code or do you think it's better inside the mcount subcommand code? Cheers, -Matt
[PULL] alpha.git
Hi Linus, Please pull a few changes for alpha. They're mostly small janitorial fixes but there's also a build fix and most notably a patch from Mikulas that fixes a hang on boot on the Avanti platform, which required quite a bit of work and review. Thanks, Matt The following changes since commit 79ca035d2d941839f55f3b8b69f8e81c66946ed8: Merge branch 'proc-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace (2020-06-10 15:00:11 -0700) are available in the Git repository at: https://git.kernel.org/pub/scm/linux/kernel/git/mattst88/alpha.git for-linus for you to fetch changes up to 47f634ba765085373f851e9c48dccb12ad52: alpha: Fix build around srm_sysrq_reboot_op (2020-06-12 17:43:18 -0700) Chuhong Yuan (1): alpha: Replace strncmp with str_has_prefix Enrico Weigelt, metux IT consult (1): alpha: Kconfig: pedantic formatting Jason Yan (2): alpha: remove unneeded semicolon in osf_sys.c alpha: remove unneeded semicolon in sys_eiger.c Joerg Roedel (1): alpha: Fix build around srm_sysrq_reboot_op Matt Turner (1): alpha: c_next should increase position index Mikulas Patocka (2): alpha: fix rtc port ranges alpha: fix memory barriers so that they conform to the specification Xu Wang (1): alpha: Replace sg++ with sg = sg_next(sg) arch/alpha/Kconfig | 4 +-- arch/alpha/boot/tools/objstrip.c | 2 +- arch/alpha/include/asm/io.h | 74 arch/alpha/kernel/io.c | 60 arch/alpha/kernel/osf_sys.c | 2 +- arch/alpha/kernel/pci_iommu.c| 2 +- arch/alpha/kernel/setup.c| 12 +-- arch/alpha/kernel/sys_eiger.c| 2 +- 8 files changed, 127 insertions(+), 31 deletions(-) signature.asc Description: PGP signature
Re: [PATCH] alpha: Fix build around srm_sysrq_reboot_op
On Thu, Jun 11, 2020 at 2:14 AM Joerg Roedel wrote: > > From: Joerg Roedel > > The patch introducing the struct was probably never compile tested, > because it sets a handler with a wrong function signature. Wrap the > handler into a functions with the correct signature to fix the build. > > Fixes: 0f1c9688a194 ("tty/sysrq: alpha: export and use __sysrq_get_key_op()") > Cc: Emil Velikov > Cc: Guenter Roeck > Signed-off-by: Joerg Roedel > --- Thanks, applied.
Re: Regression bisected to f2f84b05e02b (bug: consolidate warn_slowpath_fmt() usage)
On Tue, Jun 2, 2020 at 11:03 AM Kees Cook wrote: > > On Mon, Jun 01, 2020 at 07:48:04PM -0700, Matt Turner wrote: > > I bisected a regression on alpha to f2f84b05e02b (bug: consolidate > > warn_slowpath_fmt() usage) which looks totally innocuous. > > > > Reverting it on master confirms that it somehow is the trigger. At or a > > little after starting userspace, I'll see an oops like this: > > > > Unable to handle kernel paging request at virtual address > > CPU 0 > > kworker/u2:5(98): Oops -1 > > pc = [<>] ra = [<>] ps = Not > > tainted > > pc is at 0x0 > > so, the instruction pointer is NULL. The only way I can imagine > that happening would be from this line: > > worker->current_func(work); > > > ra is at 0x0 > > v0 = 0007 t0 = 0001 t1 = 0001 > > t2 = t3 = fc00bfe68780 t4 = 0001 > > t5 = fc00bf8cc780 t6 = 026f8000 t7 = fc00bfe7 > > s0 = fc000250d310 s1 = fc000250d310 s2 = fc000250d310 > > s3 = fc000250ca40 s4 = fc000250caa0 s5 = > > s6 = fc000250ca40 > > a0 = fc00024f0488 a1 = fc00bfe73d98 a2 = fc00bfe68800 > > a3 = fc00bf881400 a4 = 0001 a5 = 0002 > > t8 = t9 = t10= 01321800 > > t11= ba4e pv = fc000189ca00 at = > > gp = fc000253e430 sp = 43a83c2e > > Disabling lock debugging due to kernel taint > > Trace: > > [] process_one_work+0x25c/0x5a0 > > Can you verify where this ^^ is? It is kernel/workqueue.c:2268, which contains worker->current_func(work); as you predicted. > > [] worker_thread+0x5c/0x7d0 > > [] kthread+0x188/0x1f0 > > [] ret_from_kernel_thread+0x18/0x20 > > [] kthread+0x0/0x1f0 > > [] worker_thread+0x0/0x7d0 > > > > Code: > > > > > > 00063301 > > 12e2 > > > > 0005ffde > > > > It seems to cause a hard lock on an SMP system, but not on a system with > > a single CPU. Similarly, if I boot the SMP system (2 CPUs) with > > maxcpus=1 the oops doesn't happen. Until I tested on a non-SMP system > > today I suspected that it was unaffected, but I saw the oops there too. > > With the revert applied, I don't see a warning or an oops. > > > > Any clues how this patch could have triggered the oops? > > I cannot begin to imagine. :P Compared to other things I've seen like > this in the past maybe it's some kind of effect from the code size > changing the location/alignment or timing of something else? > > Various questions ranging in degrees of sanity: > > Does alpha use work queues for WARN? I do not know. I don't see much in a few greps of arch/alpha that would indicate that it uses work queues. > Which work queue is getting a NULL function? (And then things like "if > WARN was much slower or much faster, is there a race to something > setting itself to NULL?") > > Was there a WARN before the above Oops? No, which I suspect means that your much scarier suggestion that this is somehow due to code size or alignment is increasingly plausible. > Does WARN have side-effects on alpha? alpha just uses the asm-generic implementation of WARN as far as I can tell, so I think not. > Does __WARN_printf() do something bad that warn_slowpath_null() doesn't? > > Does making incremental changes narrow anything down? (e.g. instead of > this revert, remove the __warn() call in warn_slowpath_fmt() that was > added? (I mean, that'll be quite broken for WARN, but will it not oops?) Commenting out the added __warn does not work around the problem. Readding warn_slowpath_null and the EXPORT_SYMBOL (but not calling it from WARN) does not work around the problem. Calling warn_slowpath_fmt() with fmt=" " instead of fmt=NULL does not work around the problem. I also tried GCC-10.1 as a stab in the dark, and that doesn't work around the problem. So I'm thinking it's something about code size or alignment. I would be worried it's to do with memory ordering (since this is on Alpha) but I'm seeing the problem on a single CPU system, so that should be ruled out, I think? Using CONFIG_CC_OPTIMIZE_FOR_SIZE=y doesn't work around the problem. So that hurts the theory of code size being the trigger. Since I noticed earlier that using maxcpus=1 on a 2-CPU system prevented the system from hanging, I tried disabling CONFIG_SMP on my 1-CPU system as
Re: [PATCH] capabilities: Introduce CAP_RESTORE
child! > Cleaning up... > > For the clone3() based approach: > $ cat clone3_set_tid.c > #define _GNU_SOURCE > #include > #include > #include > #include > #include > #include > #include > #include > #include > > #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr))) > > int main(int argc, char *argv[]) > { > struct clone_args c_args = { }; > pid_t pid, new_pid; > > if (argc != 2) > return 1; > > pid = atoi(argv[1]); > c_args.set_tid = ptr_to_u64(&pid); > c_args.set_tid_size = 1; > > printf("Forking...\n"); > new_pid = syscall(__NR_clone3, &c_args, sizeof(c_args)); (Note: I'm going to call the capability CAP_RESTORE but I think this applies regardless of whether the permissions stay with CAP_SYS_ADMIN..) I haven't fully reviewed the discussion of the security consequences but my sense is this would require retaining CAP_RESTORE down the entire tree of processes being restored so each parent could call clone3() with the correct pid value for its child(ren). Ideally you would drop CAP_RESTORE sooner -- preferrably only one process would need it. I think you could do that by changing what you pass down; instead of passing down a capability and a pid number, pass down a special "reservation" pidfd: 1. Have CAP_RESTORE enable opening a pidfd with the desired pid as a reservation for the pid (i.e. can't use it to signal, wait, ... perhaps these return -EBUSY, -EAGAIN or something...). 2. Only one process needs CAP_RESTORE -- it can drop CAP_RESTORE after reserving all of the pids but before kicking off the clone3() calls to recreate all of the tasks. 3. Pass the pidfd down the tree of restoring processes. Note how the set of specific pids to be created is limited at this point -- the software cannot be tricked into recreating processes other pids using a capability, CAP_RESTORE, it doesn't have. You might even set a flag on the pidfd which closes the pidfd in the sender when it's passed over a socket so that only the appropriate processes retain the pidfd. 4. The parent can then pass the *reserved* pidfd into clone3(). The reserved pidfd seamlessly turns into a pidfd reference to the child if clone3() succeeds. If it fails the eservation is still consumed -- a given pidfd reserved for clone3() can only be passed to clone3() and succeed once. Perhaps this scheme could concentrate the need for CAP_SYS_ADMIN to one process so maybe it would obviate the need for CAP_RESTORE. That said, perhaps there's something that prevents implementing such a pidfd or perhaps I have misunderstood what CRIU is doing and this pidfd idea isn't workable. Cheers, -Matt Helsley
Re: [RFC][PATCH v4 02/32] objtool: Make recordmcount into mcount subcmd
On Tue, Jun 09, 2020 at 02:52:07PM -0400, Steven Rostedt wrote: > On Tue, 9 Jun 2020 11:39:51 -0700 > Matt Helsley wrote: > > > > > +ifeq ($(SRCARCH),sparc) > > > > + SUBCMD_MCOUNT := y > > > > > > Is there some arch for which MCOUNT is not supported? If not you could > > > just > > > have MCOUNT default to 'y' and avoid adding all those tests (or maybe > > > reduce > > > the numbers and set to 'n' only for arches not supporting it). > > > > Yes, there are some which it does not support. For those architectures > > we keep recordmcount.pl around. > > > > It occured to me that with your suggestion to use more CONFIG_ variables > > we could eliminate this pattern and replace it with these pseudo-patches: > > > > +++ b/kernel/trace/Kconfig > > > > +config OBJTOOL_SUBCMD_MCOUNT > > + bool > > + depends on HAVE_C_RECORDMCOUNT > > + select OBJTOOL_SUBCMDS > > + help > > + Record mcount call locations using objtool > > > > and then change the Makefiles to use the CONFIG_ variables > > rather than have one ifeq block per arch: > > > > +++ b/tools/objtool/Makefile > > > > +SUBCMD_MCOUNT := $(CONFIG_OBJTOOL_SUBCMD_MCOUNT) > > If you can make this work, this is definitely the way to go. I think I can so I'll give it a go! Cheers, -Matt Helsley
Re: [RFC][PATCH v4 02/32] objtool: Make recordmcount into mcount subcmd
On Tue, Jun 09, 2020 at 10:00:59AM +0100, Julien Thierry wrote: > Hi Matt, > > On 6/2/20 8:49 PM, Matt Helsley wrote: > > Rather than a standalone executable merge recordmcount as a sub command > > of objtool. This is a small step towards cleaning up recordmcount and > > eventually sharing ELF code with objtool. > > > > For the initial step all that's required is a bit of Makefile changes > > and invoking the former main() function from recordmcount.c because the > > subcommand code uses similar function arguments as main when dispatching. > > > > objtool ignores some object files that tracing does not, specifically > > those with OBJECT_FILES_NON_STANDARD Makefile variables. For this reason > > we keep the recordmcount_dep separate from the objtool_dep. When using > > objtool mcount we can also, like the other objtool invocations, just > > depend on the binary rather than the source the binary is built from. > > > > Subsequent patches will gradually convert recordmcount to use > > more and more of libelf/objtool's ELF accessor code. This will both > > clean up recordmcount to be more easily readable and remove > > recordmcount's crude accessor wrapping code. > > > > Signed-off-by: Matt Helsley > > --- ... > > diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig > > index 743647005f64..ae74647b06fa 100644 > > --- a/kernel/trace/Kconfig > > +++ b/kernel/trace/Kconfig > > @@ -59,7 +59,7 @@ config HAVE_NOP_MCOUNT > > config HAVE_C_RECORDMCOUNT > > bool > > help > > - C version of recordmcount available? > > + C version of objtool mcount available? > > The "C version" doesn't make much sense here. "Objtool mcount available?" or > "mcount subcommand of objtool available?" perhaps? Agreed, "C version" is nonsense at this point. Looking at the other HAVE_* help messages in that Kconfig suggests: Arch supports objtool mcount subcommand So I've changed it to that. > > diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile > > index 285474a77fe9..ffef73f7f47e 100644 > > --- a/tools/objtool/Makefile > > +++ b/tools/objtool/Makefile > > @@ -31,12 +31,6 @@ OBJTOOL_IN := $(OBJTOOL)-in.o > > LIBELF_FLAGS := $(shell pkg-config libelf --cflags 2>/dev/null) > > LIBELF_LIBS := $(shell pkg-config libelf --libs 2>/dev/null || echo > > -lelf) > > -RECORDMCOUNT := $(OUTPUT)recordmcount > > -RECORDMCOUNT_IN := $(RECORDMCOUNT)-in.o > > -ifeq ($(BUILD_C_RECORDMCOUNT),y) > > -all: $(RECORDMCOUNT) > > -endif > > - > > all: $(OBJTOOL) > > INCLUDES := -I$(srctree)/tools/include \ > > @@ -55,13 +49,47 @@ AWK = awk > > SUBCMD_CHECK := n > > SUBCMD_ORC := n > > +SUBCMD_MCOUNT := n > > ifeq ($(SRCARCH),x86) > > SUBCMD_CHECK := y > > SUBCMD_ORC := y > > + SUBCMD_MCOUNT := y > > +endif > > + > > +ifeq ($(SRCARCH),arm) > > + SUBCMD_MCOUNT := y > > +endif > > + > > +ifeq ($(SRCARCH),arm64) > > + SUBCMD_MCOUNT := y > > +endif > > + > > +ifeq ($(SRCARCH),ia64) > > + SUBCMD_MCOUNT := y > > +endif > > + > > +ifeq ($(SRCARCH),mips) > > + SUBCMD_MCOUNT := y > > +endif > > + > > +ifeq ($(SRCARCH),powerpc) > > + SUBCMD_MCOUNT := y > > +endif > > + > > +ifeq ($(SRCARCH),s390) > > + SUBCMD_MCOUNT := y > > +endif > > + > > +ifeq ($(SRCARCH),sh) > > + SUBCMD_MCOUNT := y > > +endif > > + > > +ifeq ($(SRCARCH),sparc) > > + SUBCMD_MCOUNT := y > > Is there some arch for which MCOUNT is not supported? If not you could just > have MCOUNT default to 'y' and avoid adding all those tests (or maybe reduce > the numbers and set to 'n' only for arches not supporting it). Yes, there are some which it does not support. For those architectures we keep recordmcount.pl around. It occured to me that with your suggestion to use more CONFIG_ variables we could eliminate this pattern and replace it with these pseudo-patches: +++ b/kernel/trace/Kconfig +config OBJTOOL_SUBCMD_MCOUNT + bool + depends on HAVE_C_RECORDMCOUNT + select OBJTOOL_SUBCMDS + help + Record mcount call locations using objtool and then change the Makefiles to use the CONFIG_ variables rather than have one ifeq block per arch: +++ b/tools/objtool/Makefile +SUBCMD_MCOUNT := $(CONFIG_OBJTOOL_SUBCMD_MCOUNT) Does this seem like a good use of CONFIG_ variables or is it going too far? I haven't changed to this pattern just yet -- I'm
Re: [RFC][PATCH v4 27/32] objtool: mcount: Generic location and relocation table types
On Tue, Jun 09, 2020 at 12:11:55PM +0530, Kamalesh Babulal wrote: > On 6/3/20 1:20 AM, Matt Helsley wrote: > > Rather than building the exact ELF section data we need and > > avoiding libelf's conversion step, use more GElf types > > and then libelf's elfxx_xlatetof() functions to convert > > the mcount locations (GElf_Addr) and associated relocations. > > > > This converts sift_rel_mcount() so that it doesn't use the > > recordmcount wrapper. The next patch will move it out of the > > wrapper. > > > > Signed-off-by: Matt Helsley > > --- > > tools/objtool/recordmcount.c | 44 +++-- > > tools/objtool/recordmcount.h | 120 ++- > > 2 files changed, 59 insertions(+), 105 deletions(-) > > > > diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c > > index 06a8f8ddefa7..ef3c360a3db9 100644 > > --- a/tools/objtool/recordmcount.c > > +++ b/tools/objtool/recordmcount.c > > [...] > > > -static uint_t *sift_rel_mcount(uint_t *mlocp, > > - unsigned const offbase, > > - Elf_Rel **const mrelpp, > > +static void sift_rel_mcount(GElf_Addr **mlocpp, > > + GElf_Sxword *r_offsetp, > > + void **const mrelpp, > >const struct section * const rels, > >unsigned const recsym_index, > >unsigned long const recval, > > - unsigned const reltype) > > + unsigned const reltype, > > + bool is_rela) > > { > > - uint_t *const mloc0 = mlocp; > > - Elf_Rel *mrelp = *mrelpp; > > - unsigned int rel_entsize = rels->sh.sh_entsize; > > - unsigned mcountsym = 0; > > + GElf_Rel *mrelp = *mrelpp; > > + GElf_Rela *mrelap = *mrelpp; > > + unsigned int mcount_sym_info = 0; > > struct reloc *reloc; > > > > list_for_each_entry(reloc, &rels->reloc_list, list) { > > - if (!mcountsym) > > - mcountsym = get_mcountsym(reloc); > > - > > - if (mcountsym == GELF_R_INFO(reloc->sym->idx, reloc->type) && > > !is_fake_mcount(reloc)) { > > - uint_t const addend = > > - _w(reloc->offset - recval + mcount_adjust); > > - mrelp->r_offset = _w(offbase > > - + ((void *)mlocp - (void *)mloc0)); > > - Elf_r_info(mrelp, recsym_index, reltype); > > - if (rel_entsize == sizeof(Elf_Rela)) { > > - ((Elf_Rela *)mrelp)->r_addend = addend; > > - *mlocp++ = 0; > > - } else > > - *mlocp++ = addend; > > - > > - mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp); > > + unsigned long addend; > > + > > + if (!mcount_sym_info) > > + mcount_sym_info = get_mcount_sym_info(reloc); > > + > > + if (mcount_sym_info != GELF_R_INFO(reloc->sym->idx, > > reloc->type) || is_fake_mcount(reloc)) > > + continue; > > Hi Matt, > > I was trying out the patch series on ppc64le and found that __mcount_loc > and .rela__mcount_loc section pairs do not get generated. > > # readelf -S fs/proc/cmdline.o|grep mcount > # > > Debugged the cause to get_mcountsym()'s return type. It returns reloc > type from GELF_R_INFO() and expects Elf64_Xword a.k.a unsigned long > to be the return type but get_mcountsym() returns unsigned int on 64-bit. > > On power the _mcount is of relocation type R_PPC64_REL24 (info 0x17000a), > using unsigned int truncates the value to 0xa and fails the above check. > Using below fix, that converts mcount_sym_info to use unsigned long, generates > the __mcount_loc section pairs. > > --- a/tools/objtool/mcount.c > +++ b/tools/objtool/mcount.c > @@ -163,7 +163,7 @@ static int is_mcounted_section_name(char const *const > txtname) > strcmp(".cpuidle.text", txtname) == 0; > } > > -static unsigned int get_mcount_sym_info(struct reloc *reloc) > +static unsigned long get_mcount_sym_info(struct reloc *reloc) > { > struct symbol *sym = reloc->sym; > char const *symname = sym->name; > @@ -274,7 +274,7 @@ static int nop_mcount(struct section * const rels, > { > struct reloc *reloc;
Re: [RFC][PATCH v4 01/32] objtool: Prepare to merge recordmcount
On Tue, Jun 09, 2020 at 09:54:33AM +0100, Julien Thierry wrote: > Hi Matt, > > On 6/2/20 8:49 PM, Matt Helsley wrote: > > Move recordmcount into the objtool directory. We keep this step separate > > so changes which turn recordmcount into a subcommand of objtool don't > > get obscured. > > > > Signed-off-by: Matt Helsley > > diff --git a/Makefile b/Makefile > > index 04f5662ae61a..d353a0a65a71 100644 > > --- a/Makefile > > +++ b/Makefile > > @@ -844,6 +844,7 @@ ifdef CONFIG_DYNAMIC_FTRACE > > ifdef CONFIG_HAVE_C_RECORDMCOUNT > > BUILD_C_RECORDMCOUNT := y > > export BUILD_C_RECORDMCOUNT > > + objtool_target := tools/objtool FORCE > > endif > > endif > > endif > > @@ -1023,10 +1024,10 @@ endif > > export mod_sign_cmd > > HOST_LIBELF_LIBS = $(shell pkg-config libelf --libs 2>/dev/null || echo > > -lelf) > > +has_libelf := $(call try-run,\ > > + echo "int main() {}" | $(HOSTCC) -xc -o /dev/null > > $(HOST_LIBELF_LIBS) -,1,0) > > Maybe there could be some build dependency, e.g. CONFIG_OBJTOOL_SUBCMDS that > sets the "objtool_target" and "has_libelf" when selected. > > Then the CONFIG_UNWINDER_ORC, RECORD_MCOUNT and STACK_VALIDATION would just > had to select that config option. That might save a good amount of control flow in the Makefiles. We could take it one step further and have specific CONFIG_OBJTOOL_ which might help us remove the per-architecture control-flow in the multi-arch subcmd support found in tools/objtool/Makefile. What do folks think of that -- too far? > > > ifdef CONFIG_STACK_VALIDATION > > - has_libelf := $(call try-run,\ > > - echo "int main() {}" | $(HOSTCC) -xc -o /dev/null > > $(HOST_LIBELF_LIBS) -,1,0) > > ifeq ($(has_libelf),1) > > objtool_target := tools/objtool FORCE > > else > > @@ -1163,13 +1164,15 @@ uapi-asm-generic: > > PHONY += prepare-objtool > > prepare-objtool: $(objtool_target) > > -ifeq ($(SKIP_STACK_VALIDATION),1) > > -ifdef CONFIG_UNWINDER_ORC > > +ifneq ($(has_libelf),1) > > + ifdef CONFIG_UNWINDER_ORC > > @echo "error: Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, > > please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 > > @false > > -else > > + else > > +ifeq ($(SKIP_STACK_VALIDATION),1) > > @echo "warning: Cannot use CONFIG_STACK_VALIDATION=y, please install > > libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 > > > I think this would be more readable without the else branch: > > ifneq ($(has_libelf),1) > ifdef > Note: error not warn > endif > ifdef > > endif > <...> > endif I think the next patch, which makes recordmcount a subcmd, makes it a little clearer what the pattern is because it adds another ifdef block in the way you suggest. As for the else around the SKIP_STACK_VALIDATION check -- it is special in a couple ways -- at least as best I can tell. It's not a CONFIG_* -- it actually breaks the normal pattern with CONFIG_* in that.. It's about a judgement call that it's OK to merely warn and skip the stack validation rather than produce an error. The other, CONFIG_* blocks produce errors. These two reasons are why I think it makes sense to keep the logic distinct with the "else". Cheers, -Matt Helsley