Bug Summary

File:dev/dt/dt_dev.c
Warning:line 611, column 18
The left operand of '!=' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name dt_dev.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/dt/dt_dev.c
1/* $OpenBSD: dt_dev.c,v 1.19 2022/01/09 05:42:37 jsg Exp $ */
2
3/*
4 * Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/systm.h>
21#include <sys/param.h>
22#include <sys/device.h>
23#include <sys/malloc.h>
24#include <sys/proc.h>
25
26#include <dev/dt/dtvar.h>
27
28/*
29 * Number of frames to skip in stack traces.
30 *
31 * The number of frames required to execute dt(4) profiling code
32 * depends on the probe, context, architecture and possibly the
33 * compiler.
34 *
35 * Static probes (tracepoints) are executed in the context of the
36 * current thread and only need to skip frames up to the recording
37 * function. For example the syscall provider:
38 *
39 * dt_prov_syscall_entry+0x141
40 * syscall+0x205 <--- start here
41 * Xsyscall+0x128
42 *
43 * Probes executed in their own context, like the profile provider,
44 * need to skip the frames of that context which are different for
45 * every architecture. For example the profile provider executed
46 * from hardclock(9) on amd64:
47 *
48 * dt_prov_profile_enter+0x6e
49 * hardclock+0x1a9
50 * lapic_clockintr+0x3f
51 * Xresume_lapic_ltimer+0x26
52 * acpicpu_idle+0x1d2 <---- start here.
53 * sched_idle+0x225
54 * proc_trampoline+0x1c
55 */
56#if defined(__amd64__1)
57#define DT_FA_PROFILE5 5
58#define DT_FA_STATIC2 2
59#elif defined(__powerpc64__)
60#define DT_FA_PROFILE5 6
61#define DT_FA_STATIC2 2
62#elif defined(__sparc64__)
63#define DT_FA_PROFILE5 5
64#define DT_FA_STATIC2 1
65#else
66#define DT_FA_STATIC2 0
67#define DT_FA_PROFILE5 0
68#endif
69
70#define DT_EVTRING_SIZE16 16 /* # of slots in per PCB event ring */
71
72#define DPRINTF(x...) /* nothing */
73
74/*
75 * Descriptor associated with each program opening /dev/dt. It is used
76 * to keep track of enabled PCBs.
77 *
78 * Locks used to protect struct members in this file:
79 * m per-softc mutex
80 * K kernel lock
81 */
82struct dt_softc {
83 SLIST_ENTRY(dt_softc)struct { struct dt_softc *sle_next; } ds_next; /* [K] descriptor list */
84 int ds_unit; /* [I] D_CLONE unique unit */
85 pid_t ds_pid; /* [I] PID of tracing program */
86
87 struct mutex ds_mtx;
88
89 struct dt_pcb_list ds_pcbs; /* [K] list of enabled PCBs */
90 struct dt_evt *ds_bufqueue; /* [K] copy evts to userland */
91 size_t ds_bufqlen; /* [K] length of the queue */
92 int ds_recording; /* [K] currently recording? */
93 int ds_evtcnt; /* [m] # of readable evts */
94
95 /* Counters */
96 uint64_t ds_readevt; /* [m] # of events read */
97 uint64_t ds_dropevt; /* [m] # of events dropped */
98};
99
100SLIST_HEAD(, dt_softc)struct { struct dt_softc *slh_first; } dtdev_list; /* [K] list of open /dev/dt nodes */
101
102/*
103 * Probes are created during dt_attach() and never modified/freed during
104 * the lifetime of the system. That's why we consider them as [I]mmutable.
105 */
106unsigned int dt_nprobes; /* [I] # of probes available */
107SIMPLEQ_HEAD(, dt_probe)struct { struct dt_probe *sqh_first; struct dt_probe **sqh_last
; }
dt_probe_list; /* [I] list of probes */
108
109struct rwlock dt_lock = RWLOCK_INITIALIZER("dtlk"){ 0, "dtlk" };
110volatile uint32_t dt_tracing = 0; /* [K] # of processes tracing */
111
112int allowdt;
113
114void dtattach(struct device *, struct device *, void *);
115int dtopen(dev_t, int, int, struct proc *);
116int dtclose(dev_t, int, int, struct proc *);
117int dtread(dev_t, struct uio *, int);
118int dtioctl(dev_t, u_long, caddr_t, int, struct proc *);
119
120struct dt_softc *dtlookup(int);
121
122int dt_ioctl_list_probes(struct dt_softc *, struct dtioc_probe *);
123int dt_ioctl_get_stats(struct dt_softc *, struct dtioc_stat *);
124int dt_ioctl_record_start(struct dt_softc *);
125void dt_ioctl_record_stop(struct dt_softc *);
126int dt_ioctl_probe_enable(struct dt_softc *, struct dtioc_req *);
127int dt_ioctl_probe_disable(struct dt_softc *, struct dtioc_req *);
128
129int dt_pcb_ring_copy(struct dt_pcb *, struct dt_evt *, size_t, uint64_t *);
130
131void
132dtattach(struct device *parent, struct device *self, void *aux)
133{
134 SLIST_INIT(&dtdev_list){ ((&dtdev_list)->slh_first) = ((void *)0); };
135 SIMPLEQ_INIT(&dt_probe_list)do { (&dt_probe_list)->sqh_first = ((void *)0); (&
dt_probe_list)->sqh_last = &(&dt_probe_list)->sqh_first
; } while (0)
;
136
137 /* Init providers */
138 dt_nprobes += dt_prov_profile_init();
139 dt_nprobes += dt_prov_syscall_init();
140 dt_nprobes += dt_prov_static_init();
141#ifdef DDBPROF
142 dt_nprobes += dt_prov_kprobe_init();
143#endif
144}
145
146int
147dtopen(dev_t dev, int flags, int mode, struct proc *p)
148{
149 struct dt_softc *sc;
150 int unit = minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
;
151
152 if (!allowdt)
153 return EPERM1;
154
155 KASSERT(dtlookup(unit) == NULL)((dtlookup(unit) == ((void *)0)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/dev/dt/dt_dev.c", 155, "dtlookup(unit) == NULL"
))
;
156
157 sc = malloc(sizeof(*sc), M_DEVBUF2, M_WAITOK0x0001|M_CANFAIL0x0004|M_ZERO0x0008);
158 if (sc == NULL((void *)0))
159 return ENOMEM12;
160
161 /*
162 * Enough space to empty 2 full rings of events in a single read.
163 */
164 sc->ds_bufqlen = 2 * DT_EVTRING_SIZE16;
165 sc->ds_bufqueue = mallocarray(sc->ds_bufqlen, sizeof(*sc->ds_bufqueue),
166 M_DEVBUF2, M_WAITOK0x0001|M_CANFAIL0x0004);
167 if (sc->ds_bufqueue == NULL((void *)0))
168 goto bad;
169
170 sc->ds_unit = unit;
171 sc->ds_pid = p->p_p->ps_pid;
172 TAILQ_INIT(&sc->ds_pcbs)do { (&sc->ds_pcbs)->tqh_first = ((void *)0); (&
sc->ds_pcbs)->tqh_last = &(&sc->ds_pcbs)->
tqh_first; } while (0)
;
173 mtx_init(&sc->ds_mtx, IPL_HIGH)do { (void)(((void *)0)); (void)(0); __mtx_init((&sc->
ds_mtx), ((((0xd)) > 0x0 && ((0xd)) < 0x9) ? 0x9
: ((0xd)))); } while (0)
;
174 sc->ds_evtcnt = 0;
175 sc->ds_readevt = 0;
176 sc->ds_dropevt = 0;
177
178 SLIST_INSERT_HEAD(&dtdev_list, sc, ds_next)do { (sc)->ds_next.sle_next = (&dtdev_list)->slh_first
; (&dtdev_list)->slh_first = (sc); } while (0)
;
179
180 DPRINTF("dt%d: pid %d open\n", sc->ds_unit, sc->ds_pid);
181
182 return 0;
183
184bad:
185 free(sc, M_DEVBUF2, sizeof(*sc));
186 return ENOMEM12;
187}
188
189int
190dtclose(dev_t dev, int flags, int mode, struct proc *p)
191{
192 struct dt_softc *sc;
193 int unit = minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
;
194
195 sc = dtlookup(unit);
196 KASSERT(sc != NULL)((sc != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 196, "sc != NULL"))
;
197
198 DPRINTF("dt%d: pid %d close\n", sc->ds_unit, sc->ds_pid);
199
200 SLIST_REMOVE(&dtdev_list, sc, dt_softc, ds_next)do { if ((&dtdev_list)->slh_first == (sc)) { do { ((&
dtdev_list))->slh_first = ((&dtdev_list))->slh_first
->ds_next.sle_next; } while (0); } else { struct dt_softc *
curelm = (&dtdev_list)->slh_first; while (curelm->ds_next
.sle_next != (sc)) curelm = curelm->ds_next.sle_next; curelm
->ds_next.sle_next = curelm->ds_next.sle_next->ds_next
.sle_next; } ((sc)->ds_next.sle_next) = ((void *)-1); } while
(0)
;
201 dt_ioctl_record_stop(sc);
202 dt_pcb_purge(&sc->ds_pcbs);
203
204 free(sc->ds_bufqueue, M_DEVBUF2,
205 sc->ds_bufqlen * sizeof(*sc->ds_bufqueue));
206 free(sc, M_DEVBUF2, sizeof(*sc));
207
208 return 0;
209}
210
211int
212dtread(dev_t dev, struct uio *uio, int flags)
213{
214 struct sleep_state sls;
215 struct dt_softc *sc;
216 struct dt_evt *estq;
217 struct dt_pcb *dp;
218 int error = 0, unit = minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
;
219 size_t qlen, count, read = 0;
220 uint64_t dropped = 0;
221
222 sc = dtlookup(unit);
223 KASSERT(sc != NULL)((sc != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 223, "sc != NULL"))
;
224
225 count = howmany(uio->uio_resid, sizeof(struct dt_evt))(((uio->uio_resid) + ((sizeof(struct dt_evt)) - 1)) / (sizeof
(struct dt_evt)))
;
226 if (count < 1)
227 return (EMSGSIZE40);
228
229 while (!sc->ds_evtcnt) {
230 sleep_setup(&sls, sc, PWAIT32 | PCATCH0x100, "dtread", 0);
231 error = sleep_finish(&sls, !sc->ds_evtcnt);
232 if (error == EINTR4 || error == ERESTART-1)
233 break;
234 }
235 if (error)
236 return error;
237
238 estq = sc->ds_bufqueue;
239 qlen = MIN(sc->ds_bufqlen, count)(((sc->ds_bufqlen)<(count))?(sc->ds_bufqlen):(count)
)
;
240
241 KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 241, "_kernel_lock_held()"))
;
242 TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext)for((dp) = ((&sc->ds_pcbs)->tqh_first); (dp) != ((void
*)0); (dp) = ((dp)->dp_snext.tqe_next))
{
243 count = dt_pcb_ring_copy(dp, estq, qlen, &dropped);
244 read += count;
245 estq += count; /* pointer arithmetic */
246 qlen -= count;
247 if (qlen == 0)
248 break;
249 }
250 if (read > 0)
251 uiomove(sc->ds_bufqueue, read * sizeof(struct dt_evt), uio);
252
253 mtx_enter(&sc->ds_mtx);
254 sc->ds_evtcnt -= read;
255 sc->ds_readevt += read;
256 sc->ds_dropevt += dropped;
257 mtx_leave(&sc->ds_mtx);
258
259 return 0;
260}
261
262int
263dtioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
264{
265 struct dt_softc *sc;
266 int unit = minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >>
8))
;
267 int on, error = 0;
268
269 sc = dtlookup(unit);
270 KASSERT(sc != NULL)((sc != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 270, "sc != NULL"))
;
271
272 switch (cmd) {
273 case DTIOCGPLIST(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct dtioc_probe) & 0x1fff) << 16) | ((('D')) <<
8) | ((1)))
:
274 return dt_ioctl_list_probes(sc, (struct dtioc_probe *)addr);
275 case DTIOCGSTATS((unsigned long)0x40000000 | ((sizeof(struct dtioc_stat) &
0x1fff) << 16) | ((('D')) << 8) | ((2)))
:
276 return dt_ioctl_get_stats(sc, (struct dtioc_stat *)addr);
277 case DTIOCRECORD((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('D')) << 8) | ((3)))
:
278 case DTIOCPRBENABLE((unsigned long)0x80000000 | ((sizeof(struct dtioc_req) &
0x1fff) << 16) | ((('D')) << 8) | ((4)))
:
279 case DTIOCPRBDISABLE((unsigned long)0x80000000 | ((sizeof(struct dtioc_req) &
0x1fff) << 16) | ((('D')) << 8) | ((5)))
:
280 /* root only ioctl(2) */
281 break;
282 default:
283 return ENOTTY25;
284 }
285
286 if ((error = suser(p)) != 0)
287 return error;
288
289 switch (cmd) {
290 case DTIOCRECORD((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('D')) << 8) | ((3)))
:
291 on = *(int *)addr;
292 if (on)
293 error = dt_ioctl_record_start(sc);
294 else
295 dt_ioctl_record_stop(sc);
296 break;
297 case DTIOCPRBENABLE((unsigned long)0x80000000 | ((sizeof(struct dtioc_req) &
0x1fff) << 16) | ((('D')) << 8) | ((4)))
:
298 error = dt_ioctl_probe_enable(sc, (struct dtioc_req *)addr);
299 break;
300 case DTIOCPRBDISABLE((unsigned long)0x80000000 | ((sizeof(struct dtioc_req) &
0x1fff) << 16) | ((('D')) << 8) | ((5)))
:
301 error = dt_ioctl_probe_disable(sc, (struct dtioc_req *)addr);
302 break;
303 default:
304 KASSERT(0)((0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 304, "0"))
;
305 }
306
307 return error;
308}
309
310struct dt_softc *
311dtlookup(int unit)
312{
313 struct dt_softc *sc;
314
315 KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 315, "_kernel_lock_held()"))
;
316
317 SLIST_FOREACH(sc, &dtdev_list, ds_next)for((sc) = ((&dtdev_list)->slh_first); (sc) != ((void *
)0); (sc) = ((sc)->ds_next.sle_next))
{
318 if (sc->ds_unit == unit)
319 break;
320 }
321
322 return sc;
323}
324
325int
326dtioc_req_isvalid(struct dtioc_req *dtrq)
327{
328 switch (dtrq->dtrq_filter.dtf_operand) {
329 case DT_OP_NONE:
330 case DT_OP_EQ:
331 case DT_OP_NE:
332 break;
333 default:
334 return 0;
335 }
336
337 switch (dtrq->dtrq_filter.dtf_variable) {
338 case DT_FV_NONE:
339 case DT_FV_PID:
340 case DT_FV_TID:
341 break;
342 default:
343 return 0;
344 }
345
346 return 1;
347}
348
349int
350dt_ioctl_list_probes(struct dt_softc *sc, struct dtioc_probe *dtpr)
351{
352 struct dtioc_probe_info info, *dtpi;
353 struct dt_probe *dtp;
354 size_t size;
355 int error = 0;
356
357 size = dtpr->dtpr_size;
358 dtpr->dtpr_size = dt_nprobes * sizeof(*dtpi);
359 if (size == 0)
360 return 0;
361
362 dtpi = dtpr->dtpr_probes;
363 memset(&info, 0, sizeof(info))__builtin_memset((&info), (0), (sizeof(info)));
364 SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next)for((dtp) = ((&dt_probe_list)->sqh_first); (dtp) != ((
void *)0); (dtp) = ((dtp)->dtp_next.sqe_next))
{
365 if (size < sizeof(*dtpi)) {
366 error = ENOSPC28;
367 break;
368 }
369 info.dtpi_pbn = dtp->dtp_pbn;
370 info.dtpi_nargs = dtp->dtp_nargs;
371 strlcpy(info.dtpi_prov, dtp->dtp_prov->dtpv_name,
372 sizeof(info.dtpi_prov));
373 strlcpy(info.dtpi_func, dtp->dtp_func, sizeof(info.dtpi_func));
374 strlcpy(info.dtpi_name, dtp->dtp_name, sizeof(info.dtpi_name));
375 error = copyout(&info, dtpi, sizeof(*dtpi));
376 if (error)
377 break;
378 size -= sizeof(*dtpi);
379 dtpi++;
380 };
381
382 return error;
383}
384
385int
386dt_ioctl_get_stats(struct dt_softc *sc, struct dtioc_stat *dtst)
387{
388 mtx_enter(&sc->ds_mtx);
389 dtst->dtst_readevt = sc->ds_readevt;
390 dtst->dtst_dropevt = sc->ds_dropevt;
391 mtx_leave(&sc->ds_mtx);
392
393 return 0;
394}
395
396int
397dt_ioctl_record_start(struct dt_softc *sc)
398{
399 struct dt_pcb *dp;
400
401 if (sc->ds_recording)
402 return EBUSY16;
403
404 KERNEL_ASSERT_LOCKED()((_kernel_lock_held()) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 404, "_kernel_lock_held()"))
;
405 if (TAILQ_EMPTY(&sc->ds_pcbs)(((&sc->ds_pcbs)->tqh_first) == ((void *)0)))
406 return ENOENT2;
407
408 rw_enter_write(&dt_lock);
409 TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext)for((dp) = ((&sc->ds_pcbs)->tqh_first); (dp) != ((void
*)0); (dp) = ((dp)->dp_snext.tqe_next))
{
410 struct dt_probe *dtp = dp->dp_dtp;
411
412 SMR_SLIST_INSERT_HEAD_LOCKED(&dtp->dtp_pcbs, dp, dp_pnext)do { (dp)->dp_pnext.smr_sle_next = (&dtp->dtp_pcbs)
->smr_slh_first; do { __asm volatile("" ::: "memory"); } while
(0); (&dtp->dtp_pcbs)->smr_slh_first = (dp); } while
(0)
;
413 dtp->dtp_recording++;
414 dtp->dtp_prov->dtpv_recording++;
415 }
416 rw_exit_write(&dt_lock);
417
418 sc->ds_recording = 1;
419 dt_tracing++;
420
421 return 0;
422}
423
424void
425dt_ioctl_record_stop(struct dt_softc *sc)
426{
427 struct dt_pcb *dp;
428
429 if (!sc->ds_recording)
430 return;
431
432 DPRINTF("dt%d: pid %d disable\n", sc->ds_unit, sc->ds_pid);
433
434 dt_tracing--;
435 sc->ds_recording = 0;
436
437 rw_enter_write(&dt_lock);
438 TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext)for((dp) = ((&sc->ds_pcbs)->tqh_first); (dp) != ((void
*)0); (dp) = ((dp)->dp_snext.tqe_next))
{
439 struct dt_probe *dtp = dp->dp_dtp;
440
441 dtp->dtp_recording--;
442 dtp->dtp_prov->dtpv_recording--;
443 SMR_SLIST_REMOVE_LOCKED(&dtp->dtp_pcbs, dp, dt_pcb, dp_pnext)do { if ((&dtp->dtp_pcbs)->smr_slh_first == (dp)) {
do { ((&dtp->dtp_pcbs))->smr_slh_first = ((&dtp
->dtp_pcbs))->smr_slh_first->dp_pnext.smr_sle_next;}
while (0); } else { struct dt_pcb *curelm = (&dtp->dtp_pcbs
)->smr_slh_first; while (curelm->dp_pnext.smr_sle_next !=
(dp)) curelm = curelm->dp_pnext.smr_sle_next; curelm->
dp_pnext.smr_sle_next = curelm->dp_pnext.smr_sle_next->
dp_pnext.smr_sle_next; } } while (0)
;
444 }
445 rw_exit_write(&dt_lock);
446
447 /* Wait until readers cannot access the PCBs. */
448 smr_barrier()smr_barrier_impl(0);
449}
450
451int
452dt_ioctl_probe_enable(struct dt_softc *sc, struct dtioc_req *dtrq)
453{
454 struct dt_pcb_list plist;
455 struct dt_probe *dtp;
456 int error;
457
458 if (!dtioc_req_isvalid(dtrq))
459 return EINVAL22;
460
461 SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next)for((dtp) = ((&dt_probe_list)->sqh_first); (dtp) != ((
void *)0); (dtp) = ((dtp)->dtp_next.sqe_next))
{
462 if (dtp->dtp_pbn == dtrq->dtrq_pbn)
463 break;
464 }
465 if (dtp == NULL((void *)0))
466 return ENOENT2;
467
468 TAILQ_INIT(&plist)do { (&plist)->tqh_first = ((void *)0); (&plist)->
tqh_last = &(&plist)->tqh_first; } while (0)
;
469 error = dtp->dtp_prov->dtpv_alloc(dtp, sc, &plist, dtrq);
470 if (error)
471 return error;
472
473 DPRINTF("dt%d: pid %d enable %u : %b\n", sc->ds_unit, sc->ds_pid,
474 dtrq->dtrq_pbn, (unsigned int)dtrq->dtrq_evtflags, DTEVT_FLAG_BITS);
475
476 /* Append all PCBs to this instance */
477 TAILQ_CONCAT(&sc->ds_pcbs, &plist, dp_snext)do { if (!(((&plist)->tqh_first) == ((void *)0))) { *(
&sc->ds_pcbs)->tqh_last = (&plist)->tqh_first
; (&plist)->tqh_first->dp_snext.tqe_prev = (&sc
->ds_pcbs)->tqh_last; (&sc->ds_pcbs)->tqh_last
= (&plist)->tqh_last; do { ((&plist))->tqh_first
= ((void *)0); ((&plist))->tqh_last = &((&plist
))->tqh_first; } while (0); } } while (0)
;
478
479 return 0;
480}
481
482int
483dt_ioctl_probe_disable(struct dt_softc *sc, struct dtioc_req *dtrq)
484{
485 struct dt_probe *dtp;
486 int error;
487
488 if (!dtioc_req_isvalid(dtrq))
489 return EINVAL22;
490
491 SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next)for((dtp) = ((&dt_probe_list)->sqh_first); (dtp) != ((
void *)0); (dtp) = ((dtp)->dtp_next.sqe_next))
{
492 if (dtp->dtp_pbn == dtrq->dtrq_pbn)
493 break;
494 }
495 if (dtp == NULL((void *)0))
496 return ENOENT2;
497
498 if (dtp->dtp_prov->dtpv_dealloc) {
499 error = dtp->dtp_prov->dtpv_dealloc(dtp, sc, dtrq);
500 if (error)
501 return error;
502 }
503
504 DPRINTF("dt%d: pid %d dealloc\n", sc->ds_unit, sc->ds_pid,
505 dtrq->dtrq_pbn);
506
507 return 0;
508}
509
510struct dt_probe *
511dt_dev_alloc_probe(const char *func, const char *name, struct dt_provider *dtpv)
512{
513 struct dt_probe *dtp;
514
515 dtp = malloc(sizeof(*dtp), M_DT2, M_NOWAIT0x0002|M_ZERO0x0008);
516 if (dtp == NULL((void *)0))
517 return NULL((void *)0);
518
519 SMR_SLIST_INIT(&dtp->dtp_pcbs)do { (&dtp->dtp_pcbs)->smr_slh_first = ((void *)0);
} while (0)
;
520 dtp->dtp_prov = dtpv;
521 dtp->dtp_func = func;
522 dtp->dtp_name = name;
523 dtp->dtp_sysnum = -1;
524 dtp->dtp_ref = 0;
525
526 return dtp;
527}
528
529void
530dt_dev_register_probe(struct dt_probe *dtp)
531{
532 static uint64_t probe_nb;
533
534 dtp->dtp_pbn = ++probe_nb;
535 SIMPLEQ_INSERT_TAIL(&dt_probe_list, dtp, dtp_next)do { (dtp)->dtp_next.sqe_next = ((void *)0); *(&dt_probe_list
)->sqh_last = (dtp); (&dt_probe_list)->sqh_last = &
(dtp)->dtp_next.sqe_next; } while (0)
;
536}
537
538struct dt_pcb *
539dt_pcb_alloc(struct dt_probe *dtp, struct dt_softc *sc)
540{
541 struct dt_pcb *dp;
542
543 dp = malloc(sizeof(*dp), M_DT2, M_WAITOK0x0001|M_CANFAIL0x0004|M_ZERO0x0008);
544 if (dp == NULL((void *)0))
545 goto bad;
546
547 dp->dp_ring = mallocarray(DT_EVTRING_SIZE16, sizeof(*dp->dp_ring), M_DT2,
548 M_WAITOK0x0001|M_CANFAIL0x0004|M_ZERO0x0008);
549 if (dp->dp_ring == NULL((void *)0))
550 goto bad;
551
552 mtx_init(&dp->dp_mtx, IPL_HIGH)do { (void)(((void *)0)); (void)(0); __mtx_init((&dp->
dp_mtx), ((((0xd)) > 0x0 && ((0xd)) < 0x9) ? 0x9
: ((0xd)))); } while (0)
;
553 dp->dp_sc = sc;
554 dp->dp_dtp = dtp;
555 return dp;
556bad:
557 dt_pcb_free(dp);
558 return NULL((void *)0);
559}
560
561void
562dt_pcb_free(struct dt_pcb *dp)
563{
564 if (dp == NULL((void *)0))
565 return;
566 free(dp->dp_ring, M_DT2, DT_EVTRING_SIZE16 * sizeof(*dp->dp_ring));
567 free(dp, M_DT2, sizeof(*dp));
568}
569
570void
571dt_pcb_purge(struct dt_pcb_list *plist)
572{
573 struct dt_pcb *dp;
574
575 while ((dp = TAILQ_FIRST(plist)((plist)->tqh_first)) != NULL((void *)0)) {
576 TAILQ_REMOVE(plist, dp, dp_snext)do { if (((dp)->dp_snext.tqe_next) != ((void *)0)) (dp)->
dp_snext.tqe_next->dp_snext.tqe_prev = (dp)->dp_snext.tqe_prev
; else (plist)->tqh_last = (dp)->dp_snext.tqe_prev; *(dp
)->dp_snext.tqe_prev = (dp)->dp_snext.tqe_next; ((dp)->
dp_snext.tqe_prev) = ((void *)-1); ((dp)->dp_snext.tqe_next
) = ((void *)-1); } while (0)
;
577 dt_pcb_free(dp);
578 }
579}
580
581int
582dt_pcb_filter(struct dt_pcb *dp)
583{
584 struct dt_filter *dtf = &dp->dp_filter;
585 struct proc *p = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
;
586 unsigned int var;
2
'var' declared without an initial value
587 int match = 1;
588
589 /* Filter out tracing program. */
590 if (dp->dp_sc->ds_pid == p->p_p->ps_pid)
3
Assuming field 'ds_pid' is not equal to field 'ps_pid'
4
Taking false branch
591 return 1;
592
593 switch (dtf->dtf_variable) {
5
Control jumps to 'case DT_FV_NONE:' at line 600
594 case DT_FV_PID:
595 var = p->p_p->ps_pid;
596 break;
597 case DT_FV_TID:
598 var = p->p_tid + THREAD_PID_OFFSET100000;
599 break;
600 case DT_FV_NONE:
601 break;
6
Execution continues on line 606
602 default:
603 KASSERT(0)((0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 603, "0"))
;
604 }
605
606 switch (dtf->dtf_operand) {
7
Control jumps to 'case DT_OP_NE:' at line 610
607 case DT_OP_EQ:
608 match = !!(var == dtf->dtf_value);
609 break;
610 case DT_OP_NE:
611 match = !!(var != dtf->dtf_value);
8
The left operand of '!=' is a garbage value
612 break;
613 case DT_OP_NONE:
614 break;
615 default:
616 KASSERT(0)((0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 616, "0"))
;
617 }
618
619 return !match;
620}
621
622
623/*
624 * Get a reference to the next free event state from the ring.
625 */
626struct dt_evt *
627dt_pcb_ring_get(struct dt_pcb *dp, int profiling)
628{
629 struct proc *p = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
;
630 struct dt_evt *dtev;
631 int distance;
632
633 if (dt_pcb_filter(dp))
1
Calling 'dt_pcb_filter'
634 return NULL((void *)0);
635
636 mtx_enter(&dp->dp_mtx);
637 distance = dp->dp_prod - dp->dp_cons;
638 if (distance == 1 || distance == (1 - DT_EVTRING_SIZE16)) {
639 /* read(2) isn't finished */
640 dp->dp_dropevt++;
641 mtx_leave(&dp->dp_mtx);
642 return NULL((void *)0);
643 }
644
645 /*
646 * Save states in next free event slot.
647 */
648 dtev = &dp->dp_ring[dp->dp_cons];
649 memset(dtev, 0, sizeof(*dtev))__builtin_memset((dtev), (0), (sizeof(*dtev)));
650
651 dtev->dtev_pbn = dp->dp_dtp->dtp_pbn;
652 dtev->dtev_cpu = cpu_number()(({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_cpuid)
;
653 dtev->dtev_pid = p->p_p->ps_pid;
654 dtev->dtev_tid = p->p_tid + THREAD_PID_OFFSET100000;
655 nanotime(&dtev->dtev_tsp);
656
657 if (ISSET(dp->dp_evtflags, DTEVT_EXECNAME)((dp->dp_evtflags) & ((1 << 0))))
658 memcpy(dtev->dtev_comm, p->p_p->ps_comm, DTMAXCOMLEN - 1)__builtin_memcpy((dtev->dtev_comm), (p->p_p->ps_comm
), (16 - 1))
;
659
660 if (ISSET(dp->dp_evtflags, DTEVT_KSTACK|DTEVT_USTACK)((dp->dp_evtflags) & ((1 << 2)|(1 << 1)))) {
661 if (profiling)
662 stacktrace_save_at(&dtev->dtev_kstack, DT_FA_PROFILE5);
663 else
664 stacktrace_save_at(&dtev->dtev_kstack, DT_FA_STATIC2);
665 }
666
667 return dtev;
668}
669
670void
671dt_pcb_ring_consume(struct dt_pcb *dp, struct dt_evt *dtev)
672{
673 MUTEX_ASSERT_LOCKED(&dp->dp_mtx)do { if (((&dp->dp_mtx)->mtx_owner != ({struct cpu_info
*__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof
(struct cpu_info, ci_self))); __ci;})) && !(panicstr ||
db_active)) panic("mutex %p not held in %s", (&dp->dp_mtx
), __func__); } while (0)
;
674 KASSERT(dtev == &dp->dp_ring[dp->dp_cons])((dtev == &dp->dp_ring[dp->dp_cons]) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c", 674, "dtev == &dp->dp_ring[dp->dp_cons]"
))
;
675
676 dp->dp_cons = (dp->dp_cons + 1) % DT_EVTRING_SIZE16;
677 mtx_leave(&dp->dp_mtx);
678
679 mtx_enter(&dp->dp_sc->ds_mtx);
680 dp->dp_sc->ds_evtcnt++;
681 mtx_leave(&dp->dp_sc->ds_mtx);
682 wakeup(dp->dp_sc);
683}
684
685/*
686 * Copy at most `qlen' events from `dp', producing the same amount
687 * of free slots.
688 */
689int
690dt_pcb_ring_copy(struct dt_pcb *dp, struct dt_evt *estq, size_t qlen,
691 uint64_t *dropped)
692{
693 size_t count, copied = 0;
694 unsigned int cons, prod;
695
696 KASSERT(qlen > 0)((qlen > 0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/dt/dt_dev.c"
, 696, "qlen > 0"))
;
697
698 mtx_enter(&dp->dp_mtx);
699 cons = dp->dp_cons;
700 prod = dp->dp_prod;
701
702 if (cons < prod)
703 count = DT_EVTRING_SIZE16 - prod;
704 else
705 count = cons - prod;
706
707 if (count == 0)
708 goto out;
709
710 *dropped += dp->dp_dropevt;
711 dp->dp_dropevt = 0;
712
713 count = MIN(count, qlen)(((count)<(qlen))?(count):(qlen));
714
715 memcpy(&estq[0], &dp->dp_ring[prod], count * sizeof(*estq))__builtin_memcpy((&estq[0]), (&dp->dp_ring[prod]),
(count * sizeof(*estq)))
;
716 copied += count;
717
718 /* Produce */
719 prod = (prod + count) % DT_EVTRING_SIZE16;
720
721 /* If the queue is full or the ring didn't wrap, stop here. */
722 if (qlen == copied || prod != 0 || cons == 0)
723 goto out;
724
725 count = MIN(cons, (qlen - copied))(((cons)<((qlen - copied)))?(cons):((qlen - copied)));
726 memcpy(&estq[copied], &dp->dp_ring[0], count * sizeof(*estq))__builtin_memcpy((&estq[copied]), (&dp->dp_ring[0]
), (count * sizeof(*estq)))
;
727 copied += count;
728 prod += count;
729
730out:
731 dp->dp_prod = prod;
732 mtx_leave(&dp->dp_mtx);
733 return copied;
734}