2 * udebug - debug ring buffer library
4 * Copyright (C) 2023 Felix Fietkau <nbd@nbd.name>
6 * Permission to use, copy, modify, and/or 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.
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.
19 #include <sys/types.h>
21 #include <sys/socket.h>
29 #include "udebug-priv.h"
32 #define ALIGN(i, sz) (((i) + (sz) - 1) & ~((sz) - 1))
35 #define MAP_ANONYMOUS MAP_ANON
38 #define UDEBUG_MIN_ALLOC_LEN 128
39 static struct blob_buf b
;
40 static unsigned int page_size
;
42 static void __randname(char *template)
48 clock_gettime(CLOCK_REALTIME
, &ts
);
49 r
= ts
.tv_sec
+ ts
.tv_nsec
;
50 for (i
=0; i
<6; i
++, r
>>=5)
51 template[i
] = 'A'+(r
&15)+(r
&16)*2;
54 int udebug_id_cmp(const void *k1
, const void *k2
, void *ptr
)
56 uint32_t id1
= (uint32_t)(uintptr_t)k1
, id2
= (uint32_t)(uintptr_t)k2
;
65 shm_open_anon(char *name
)
67 char *template = name
+ strlen(name
) - 6;
70 if (template < name
|| memcmp(template, "XXXXXX", 6) != 0)
73 for (int i
= 0; i
< 100; i
++) {
75 fd
= shm_open(name
, O_RDWR
| O_CREAT
| O_EXCL
, 0600);
77 if (shm_unlink(name
) < 0) {
84 if (fd
< 0 && errno
!= EEXIST
)
91 static void __udebug_disconnect(struct udebug
*ctx
, bool reconnect
)
93 uloop_fd_delete(&ctx
->fd
);
96 ctx
->poll_handle
= -1;
97 if (ctx
->reconnect
.cb
&& reconnect
)
98 uloop_timeout_set(&ctx
->reconnect
, 1);
101 uint64_t udebug_timestamp(void)
106 clock_gettime(CLOCK_REALTIME
, &ts
);
109 val
*= UDEBUG_TS_SEC
;
110 val
+= ts
.tv_nsec
/ 1000;
116 __udebug_buf_map(struct udebug_buf
*buf
, int fd
)
118 unsigned int pad
= 0;
124 ptr
= mmap(NULL
, buf
->head_size
+ 2 * buf
->data_size
+ pad
, PROT_NONE
,
125 MAP_ANONYMOUS
| MAP_PRIVATE
, -1, 0);
126 if (ptr
== MAP_FAILED
)
130 ptr
= (void *)ALIGN((unsigned long)ptr
, page_size
);
133 ptr2
= mmap(ptr
, buf
->head_size
+ buf
->data_size
,
134 PROT_READ
| PROT_WRITE
, MAP_FIXED
| MAP_SHARED
, fd
, 0);
138 ptr2
= mmap(ptr
+ buf
->head_size
+ buf
->data_size
, buf
->data_size
,
139 PROT_READ
| PROT_WRITE
, MAP_FIXED
| MAP_SHARED
, fd
,
141 if (ptr2
!= ptr
+ buf
->head_size
+ buf
->data_size
)
145 buf
->data
= ptr
+ buf
->head_size
;
149 munmap(ptr
, buf
->head_size
+ 2 * buf
->data_size
);
154 writev_retry(int fd
, struct iovec
*iov
, int iov_len
, int sock_fd
)
156 uint8_t fd_buf
[CMSG_SPACE(sizeof(int))] = { 0 };
157 struct msghdr msghdr
= { 0 };
158 struct cmsghdr
*cmsg
;
162 msghdr
.msg_iov
= iov
,
163 msghdr
.msg_iovlen
= iov_len
,
164 msghdr
.msg_control
= fd_buf
;
165 msghdr
.msg_controllen
= sizeof(fd_buf
);
167 cmsg
= CMSG_FIRSTHDR(&msghdr
);
168 cmsg
->cmsg_type
= SCM_RIGHTS
;
169 cmsg
->cmsg_level
= SOL_SOCKET
;
170 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
172 pfd
= (int *) CMSG_DATA(cmsg
);
173 msghdr
.msg_controllen
= cmsg
->cmsg_len
;
179 msghdr
.msg_control
= NULL
;
180 msghdr
.msg_controllen
= 0;
185 cur_len
= sendmsg(fd
, &msghdr
, 0);
187 struct pollfd pfd
= {
208 while (cur_len
>= (ssize_t
) iov
->iov_len
) {
209 cur_len
-= iov
->iov_len
;
215 iov
->iov_base
+= cur_len
;
216 iov
->iov_len
-= cur_len
;
217 msghdr
.msg_iov
= iov
;
218 msghdr
.msg_iovlen
= iov_len
;
221 /* Should never reach here */
226 recv_retry(int fd
, struct iovec
*iov
, bool wait
, int *recv_fd
)
228 uint8_t fd_buf
[CMSG_SPACE(sizeof(int))] = { 0 };
229 struct msghdr msghdr
= { 0 };
230 struct cmsghdr
*cmsg
;
235 msghdr
.msg_iov
= iov
,
236 msghdr
.msg_iovlen
= 1,
237 msghdr
.msg_control
= fd_buf
;
238 msghdr
.msg_controllen
= sizeof(fd_buf
);
240 cmsg
= CMSG_FIRSTHDR(&msghdr
);
241 cmsg
->cmsg_type
= SCM_RIGHTS
;
242 cmsg
->cmsg_level
= SOL_SOCKET
;
243 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
245 pfd
= (int *) CMSG_DATA(cmsg
);
247 while (iov
->iov_len
> 0) {
249 msghdr
.msg_control
= fd_buf
;
250 msghdr
.msg_controllen
= cmsg
->cmsg_len
;
252 msghdr
.msg_control
= NULL
;
253 msghdr
.msg_controllen
= 0;
257 bytes
= recvmsg(fd
, &msghdr
, 0);
280 iov
->iov_len
-= bytes
;
281 iov
->iov_base
+= bytes
;
284 if (iov
->iov_len
> 0) {
285 struct pollfd pfd
= {
291 ret
= poll(&pfd
, 1, UDEBUG_TIMEOUT
);
292 } while (ret
< 0 && errno
== EINTR
);
294 if (!(pfd
.revents
& POLLIN
))
303 udebug_send_msg(struct udebug
*ctx
, struct udebug_client_msg
*msg
,
304 struct blob_attr
*meta
, int fd
)
306 struct iovec iov
[2] = {
307 { .iov_base
= msg
, .iov_len
= sizeof(*msg
) },
312 blob_buf_init(&b
, 0);
316 iov
[1].iov_base
= meta
;
317 iov
[1].iov_len
= blob_pad_len(meta
);
318 writev_retry(ctx
->fd
.fd
, iov
, ARRAY_SIZE(iov
), fd
);
322 udebug_recv_msg(struct udebug
*ctx
, struct udebug_client_msg
*msg
, int *fd
,
327 .iov_len
= sizeof(*msg
)
331 ret
= recv_retry(ctx
->fd
.fd
, &iov
, wait
, fd
);
333 __udebug_disconnect(ctx
, true);
335 return ret
== sizeof(*msg
);
338 static struct udebug_client_msg
*
339 __udebug_poll(struct udebug
*ctx
, int *fd
, bool wait
)
341 static struct udebug_client_msg msg
= {};
343 while (udebug_recv_msg(ctx
, &msg
, fd
, wait
)) {
344 struct udebug_remote_buf
*rb
;
347 if (msg
.type
!= CL_MSG_RING_NOTIFY
)
356 key
= (void *)(uintptr_t)msg
.id
;
357 rb
= avl_find_element(&ctx
->remote_rings
, key
, rb
, node
);
358 if (!rb
|| !rb
->poll
)
361 if (ctx
->poll_handle
>= 0)
362 __atomic_fetch_or(&rb
->buf
.hdr
->notify
,
363 1UL << ctx
->poll_handle
,
365 ctx
->notify_cb(ctx
, rb
);
371 static struct udebug_client_msg
*
372 udebug_wait_for_response(struct udebug
*ctx
, struct udebug_client_msg
*msg
, int *rfd
)
374 int type
= msg
->type
;
381 msg
= __udebug_poll(ctx
, &fd
, true);
382 } while (msg
&& msg
->type
!= type
);
395 udebug_buf_msg(struct udebug_buf
*buf
, enum udebug_client_msg_type type
)
397 struct udebug_client_msg msg
= {
402 udebug_send_msg(buf
->ctx
, &msg
, NULL
, -1);
403 udebug_wait_for_response(buf
->ctx
, &msg
, NULL
);
406 static size_t __udebug_headsize(unsigned int ring_size
)
408 ring_size
*= sizeof(struct udebug_ptr
);
409 return ALIGN(sizeof(struct udebug_hdr
) + ring_size
, page_size
);
412 static void udebug_init_page_size(void)
416 page_size
= sysconf(_SC_PAGESIZE
);
418 /* leave extra alignment room to account for data cache aliases */
419 if (page_size
< 32 * 1024)
420 page_size
= 32 * 1024;
424 int udebug_buf_open(struct udebug_buf
*buf
, int fd
, uint32_t ring_size
, uint32_t data_size
)
426 udebug_init_page_size();
427 INIT_LIST_HEAD(&buf
->list
);
428 buf
->ring_size
= ring_size
;
429 buf
->head_size
= __udebug_headsize(ring_size
);
430 buf
->data_size
= data_size
;
432 if (buf
->ring_size
> (1U << 24) || buf
->data_size
> (1U << 29))
435 if (__udebug_buf_map(buf
, fd
))
438 if (buf
->ring_size
!= buf
->hdr
->ring_size
||
439 buf
->data_size
!= buf
->hdr
->data_size
) {
440 munmap(buf
->hdr
, buf
->head_size
+ 2 * buf
->data_size
);
450 int udebug_buf_init(struct udebug_buf
*buf
, size_t entries
, size_t size
)
452 char filename
[] = "/udebug.XXXXXX";
453 unsigned int order
= 12;
454 uint8_t ring_order
= 5;
458 udebug_init_page_size();
459 INIT_LIST_HEAD(&buf
->list
);
460 if (size
< page_size
)
462 while(size
> 1U << order
)
465 while (entries
> 1U << ring_order
)
467 entries
= 1 << ring_order
;
469 if (size
> (1U << 29) || entries
> (1U << 24))
472 head_size
= __udebug_headsize(entries
);
473 while (ALIGN(sizeof(*buf
->hdr
) + (entries
* 2) * sizeof(struct udebug_ptr
), page_size
) == head_size
)
476 fd
= shm_open_anon(filename
);
480 if (ftruncate(fd
, head_size
+ size
) < 0)
483 buf
->head_size
= head_size
;
484 buf
->data_size
= size
;
485 buf
->ring_size
= entries
;
487 if (__udebug_buf_map(buf
, fd
))
491 buf
->hdr
->ring_size
= entries
;
492 buf
->hdr
->data_size
= size
;
494 /* ensure hdr changes are visible */
495 __sync_synchronize();
504 static void *udebug_buf_alloc(struct udebug_buf
*buf
, uint32_t ofs
, uint32_t len
)
506 struct udebug_hdr
*hdr
= buf
->hdr
;
508 hdr
->data_used
= u32_max(hdr
->data_used
, ofs
+ len
+ 1);
510 /* ensure that data_used update is visible before clobbering data */
511 __sync_synchronize();
513 return udebug_buf_ptr(buf
, ofs
);
516 uint64_t udebug_buf_flags(struct udebug_buf
*buf
)
518 struct udebug_hdr
*hdr
= buf
->hdr
;
524 flags
= hdr
->flags
[0];
525 if (sizeof(flags
) != sizeof(uintptr_t))
526 flags
|= ((uint64_t)hdr
->flags
[1]) << 32;
531 void udebug_entry_init_ts(struct udebug_buf
*buf
, uint64_t timestamp
)
533 struct udebug_hdr
*hdr
= buf
->hdr
;
534 struct udebug_ptr
*ptr
;
539 ptr
= udebug_ring_ptr(hdr
, hdr
->head
);
540 ptr
->start
= hdr
->data_head
;
542 ptr
->timestamp
= timestamp
;
545 void *udebug_entry_append(struct udebug_buf
*buf
, const void *data
, uint32_t len
)
547 struct udebug_hdr
*hdr
= buf
->hdr
;
548 struct udebug_ptr
*ptr
;
555 ptr
= udebug_ring_ptr(hdr
, hdr
->head
);
556 ofs
= ptr
->start
+ ptr
->len
;
557 if (ptr
->len
+ len
> buf
->data_size
/ 2)
560 ret
= udebug_buf_alloc(buf
, ofs
, len
);
562 memcpy(ret
, data
, len
);
568 uint16_t udebug_entry_trim(struct udebug_buf
*buf
, uint16_t len
)
570 struct udebug_hdr
*hdr
= buf
->hdr
;
571 struct udebug_ptr
*ptr
;
576 ptr
= udebug_ring_ptr(hdr
, hdr
->head
);
583 void udebug_entry_set_length(struct udebug_buf
*buf
, uint16_t len
)
585 struct udebug_hdr
*hdr
= buf
->hdr
;
586 struct udebug_ptr
*ptr
;
591 ptr
= udebug_ring_ptr(hdr
, hdr
->head
);
595 int udebug_entry_printf(struct udebug_buf
*buf
, const char *fmt
, ...)
601 ret
= udebug_entry_vprintf(buf
, fmt
, ap
);
607 int udebug_entry_vprintf(struct udebug_buf
*buf
, const char *fmt
, va_list ap
)
609 struct udebug_hdr
*hdr
= buf
->hdr
;
610 struct udebug_ptr
*ptr
;
619 ptr
= udebug_ring_ptr(hdr
, hdr
->head
);
620 ofs
= ptr
->start
+ ptr
->len
;
621 if (ptr
->len
> buf
->data_size
/ 2)
624 str
= udebug_buf_alloc(buf
, ofs
, UDEBUG_MIN_ALLOC_LEN
);
626 len
= vsnprintf(str
, UDEBUG_MIN_ALLOC_LEN
, fmt
, ap2
);
628 if (len
<= UDEBUG_MIN_ALLOC_LEN
)
631 if (ptr
->len
+ len
> buf
->data_size
/ 2)
634 udebug_buf_alloc(buf
, ofs
, len
+ 1);
635 len
= vsnprintf(str
, len
, fmt
, ap
);
642 void udebug_entry_add(struct udebug_buf
*buf
)
644 struct udebug_hdr
*hdr
= buf
->hdr
;
645 struct udebug_ptr
*ptr
;
652 ptr
= udebug_ring_ptr(hdr
, hdr
->head
);
654 /* ensure strings are always 0-terminated */
655 data
= udebug_buf_ptr(buf
, ptr
->start
+ ptr
->len
);
657 hdr
->data_head
= ptr
->start
+ ptr
->len
+ 1;
659 /* ensure that all data changes are visible before advancing head */
660 __sync_synchronize();
662 u32_set(&hdr
->head
, u32_get(&hdr
->head
) + 1);
663 if (!u32_get(&hdr
->head
))
664 u32_set(&hdr
->head_hi
, u32_get(&hdr
->head_hi
) + 1);
666 /* ensure that head change is visible */
667 __sync_synchronize();
669 notify
= __atomic_exchange_n(&hdr
->notify
, 0, __ATOMIC_RELAXED
);
671 struct udebug_client_msg msg
= {
672 .type
= CL_MSG_RING_NOTIFY
,
674 .notify_mask
= notify
,
676 blob_buf_init(&b
, 0);
678 udebug_send_msg(buf
->ctx
, &msg
, b
.head
, -1);
681 void udebug_buf_free(struct udebug_buf
*buf
)
683 struct udebug
*ctx
= buf
->ctx
;
685 if (!list_empty(&buf
->list
) && buf
->list
.prev
)
686 list_del(&buf
->list
);
688 if (ctx
&& ctx
->fd
.fd
>= 0)
689 udebug_buf_msg(buf
, CL_MSG_RING_REMOVE
);
691 munmap(buf
->hdr
, buf
->head_size
+ 2 * buf
->data_size
);
693 memset(buf
, 0, sizeof(*buf
));
697 __udebug_buf_add(struct udebug
*ctx
, struct udebug_buf
*buf
)
699 struct udebug_client_msg msg
= {
700 .type
= CL_MSG_RING_ADD
,
702 .ring_size
= buf
->hdr
->ring_size
,
703 .data_size
= buf
->hdr
->data_size
,
705 const struct udebug_buf_meta
*meta
= buf
->meta
;
708 blob_buf_init(&b
, 0);
709 blobmsg_add_string(&b
, "name", meta
->name
);
710 c
= blobmsg_open_array(&b
, "flags");
711 for (size_t i
= 0; i
< meta
->n_flags
; i
++) {
712 const struct udebug_buf_flag
*flag
= &meta
->flags
[i
];
713 void *e
= blobmsg_open_array(&b
, NULL
);
714 blobmsg_add_string(&b
, NULL
, flag
->name
);
715 blobmsg_add_u64(&b
, NULL
, flag
->mask
);
716 blobmsg_close_array(&b
, e
);
718 blobmsg_close_array(&b
, c
);
720 udebug_send_msg(ctx
, &msg
, b
.head
, buf
->fd
);
721 udebug_wait_for_response(ctx
, &msg
, NULL
);
724 int udebug_buf_add(struct udebug
*ctx
, struct udebug_buf
*buf
,
725 const struct udebug_buf_meta
*meta
)
730 list_add_tail(&buf
->list
, &ctx
->local_rings
);
733 buf
->id
= ctx
->next_id
++;
734 buf
->hdr
->format
= meta
->format
;
735 buf
->hdr
->sub_format
= meta
->sub_format
;
738 __udebug_buf_add(ctx
, buf
);
743 void udebug_init(struct udebug
*ctx
)
745 INIT_LIST_HEAD(&ctx
->local_rings
);
746 avl_init(&ctx
->remote_rings
, udebug_id_cmp
, true, NULL
);
748 ctx
->poll_handle
= -1;
751 static void udebug_reconnect_cb(struct uloop_timeout
*t
)
753 struct udebug
*ctx
= container_of(t
, struct udebug
, reconnect
);
755 if (udebug_connect(ctx
, ctx
->socket_path
) < 0) {
756 uloop_timeout_set(&ctx
->reconnect
, 1000);
760 udebug_add_uloop(ctx
);
763 void udebug_auto_connect(struct udebug
*ctx
, const char *path
)
765 free(ctx
->socket_path
);
766 ctx
->reconnect
.cb
= udebug_reconnect_cb
;
767 ctx
->socket_path
= path
? strdup(path
) : NULL
;
771 udebug_reconnect_cb(&ctx
->reconnect
);
774 int udebug_connect(struct udebug
*ctx
, const char *path
)
776 struct udebug_remote_buf
*rb
;
777 struct udebug_buf
*buf
;
784 path
= UDEBUG_SOCK_NAME
;
786 ctx
->fd
.fd
= usock(USOCK_UNIX
, path
, NULL
);
790 list_for_each_entry(buf
, &ctx
->local_rings
, list
)
791 __udebug_buf_add(ctx
, buf
);
793 avl_for_each_element(&ctx
->remote_rings
, rb
, node
) {
798 udebug_remote_buf_set_poll(ctx
, rb
, true);
804 void udebug_poll(struct udebug
*ctx
)
806 while (__udebug_poll(ctx
, NULL
, false));
809 struct udebug_client_msg
*
810 udebug_send_and_wait(struct udebug
*ctx
, struct udebug_client_msg
*msg
, int *rfd
)
812 udebug_send_msg(ctx
, msg
, NULL
, -1);
814 return udebug_wait_for_response(ctx
, msg
, rfd
);
817 static void udebug_fd_cb(struct uloop_fd
*fd
, unsigned int events
)
819 struct udebug
*ctx
= container_of(fd
, struct udebug
, fd
);
822 __udebug_disconnect(ctx
, true);
827 void udebug_add_uloop(struct udebug
*ctx
)
829 if (ctx
->fd
.registered
)
832 ctx
->fd
.cb
= udebug_fd_cb
;
833 uloop_fd_add(&ctx
->fd
, ULOOP_READ
);
836 void udebug_free(struct udebug
*ctx
)
838 struct udebug_remote_buf
*rb
, *tmp
;
839 struct udebug_buf
*buf
;
841 free(ctx
->socket_path
);
842 ctx
->socket_path
= NULL
;
844 __udebug_disconnect(ctx
, false);
845 uloop_timeout_cancel(&ctx
->reconnect
);
847 while (!list_empty(&ctx
->local_rings
)) {
848 buf
= list_first_entry(&ctx
->local_rings
, struct udebug_buf
, list
);
849 udebug_buf_free(buf
);
852 avl_for_each_element_safe(&ctx
->remote_rings
, rb
, node
, tmp
)
853 udebug_remote_buf_unmap(ctx
, rb
);