1 /* 2 * udebug - debug ring buffer library 3 * 4 * Copyright (C) 2023 Felix Fietkau <nbd@nbd.name> 5 * 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. 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 #include "udebug-priv.h" 19 20 static int 21 udebug_remote_get_handle(struct udebug *ctx) 22 { 23 struct udebug_client_msg *msg; 24 struct udebug_client_msg send_msg = { 25 .type = CL_MSG_GET_HANDLE, 26 }; 27 28 if (ctx->poll_handle >= 0 || !udebug_is_connected(ctx)) 29 return 0; 30 31 msg = udebug_send_and_wait(ctx, &send_msg, NULL); 32 if (!msg) 33 return -1; 34 35 ctx->poll_handle = msg->id; 36 return 0; 37 } 38 39 struct udebug_remote_buf *udebug_remote_buf_get(struct udebug *ctx, uint32_t id) 40 { 41 struct udebug_remote_buf *rb; 42 void *key = (void *)(uintptr_t)id; 43 44 return avl_find_element(&ctx->remote_rings, key, rb, node); 45 } 46 47 int udebug_remote_buf_map(struct udebug *ctx, struct udebug_remote_buf *rb, uint32_t id) 48 { 49 void *key = (void *)(uintptr_t)id; 50 struct udebug_client_msg *msg; 51 struct udebug_client_msg send_msg = { 52 .type = CL_MSG_RING_GET, 53 .id = id, 54 }; 55 int fd = -1; 56 57 if (rb->buf.data || !udebug_is_connected(ctx)) 58 return -1; 59 60 msg = udebug_send_and_wait(ctx, &send_msg, &fd); 61 if (!msg || fd < 0) 62 return -1; 63 64 if (udebug_buf_open(&rb->buf, fd, msg->ring_size, msg->data_size)) { 65 close(fd); 66 return -1; 67 } 68 69 rb->pcap_iface = ~0; 70 rb->node.key = key; 71 avl_insert(&ctx->remote_rings, &rb->node); 72 73 return 0; 74 } 75 76 void udebug_remote_buf_unmap(struct udebug *ctx, struct udebug_remote_buf *rb) 77 { 78 if (!rb->buf.data) 79 return; 80 81 avl_delete(&ctx->remote_rings, &rb->node); 82 udebug_buf_free(&rb->buf); 83 rb->poll = 0; 84 rb->node.key = NULL; 85 rb->pcap_iface = ~0; 86 } 87 88 int udebug_remote_buf_set_poll(struct udebug *ctx, struct udebug_remote_buf *rb, bool val) 89 { 90 int handle; 91 92 if (!rb->buf.data) 93 return -1; 94 95 if (rb->poll == val) 96 return 0; 97 98 rb->poll = val; 99 if (!val) 100 return 0; 101 102 handle = udebug_remote_get_handle(ctx); 103 if (handle < 0) 104 return -1; 105 106 __atomic_fetch_or(&rb->buf.hdr->notify, 1UL << handle, __ATOMIC_RELAXED); 107 return 0; 108 } 109 110 static void 111 rbuf_advance_read_head(struct udebug_remote_buf *rb, uint32_t head, 112 uint32_t *data_start) 113 { 114 struct udebug_hdr *hdr = rb->buf.hdr; 115 uint32_t min_head = head + 1 - rb->buf.ring_size; 116 uint32_t min_data = u32_get(&hdr->data_used) - rb->buf.data_size; 117 struct udebug_ptr *last_ptr = udebug_ring_ptr(hdr, head - 1); 118 119 if (!u32_get(&hdr->head_hi) && u32_sub(0, min_head) > 0) 120 min_head = 0; 121 122 /* advance head to skip over any entries that are guaranteed 123 * to be overwritten now. final check will be performed after 124 * data copying */ 125 126 if (u32_sub(rb->head, min_head) < 0) 127 rb->head = min_head; 128 129 for (size_t i = 0; i < rb->buf.ring_size; i++) { 130 struct udebug_ptr *ptr = udebug_ring_ptr(hdr, rb->head); 131 132 if (data_start) { 133 *data_start = u32_get(&ptr->start); 134 __sync_synchronize(); 135 } 136 137 if (rb->head == head) 138 break; 139 140 if (ptr->timestamp > last_ptr->timestamp) 141 continue; 142 143 if (u32_sub(ptr->start, min_data) > 0) 144 break; 145 146 rb->head++; 147 } 148 } 149 150 void udebug_remote_buf_set_start_time(struct udebug_remote_buf *rb, uint64_t ts) 151 { 152 struct udebug_hdr *hdr = rb->buf.hdr; 153 uint32_t head = u32_get(&hdr->head); 154 uint32_t start = rb->head, end = head; 155 uint32_t diff; 156 157 if (!hdr) 158 return; 159 160 rbuf_advance_read_head(rb, head, NULL); 161 while ((diff = u32_sub(end, start)) > 0) { 162 uint32_t cur = start + diff / 2; 163 struct udebug_ptr *ptr; 164 165 ptr = udebug_ring_ptr(hdr, cur); 166 if (ptr->timestamp > ts) 167 end = cur - 1; 168 else 169 start = cur + 1; 170 } 171 172 rb->head = start; 173 } 174 175 void udebug_remote_buf_set_start_offset(struct udebug_remote_buf *rb, uint32_t idx) 176 { 177 if (!rb->buf.hdr) 178 return; 179 180 rb->head = rb->buf.hdr->head - idx; 181 } 182 183 void udebug_remote_buf_set_flags(struct udebug_remote_buf *rb, uint64_t mask, uint64_t set) 184 { 185 struct udebug_hdr *hdr = rb->buf.hdr; 186 187 if (!hdr) 188 return; 189 190 if ((uintptr_t)mask) 191 __atomic_and_fetch(&hdr->flags[0], (uintptr_t)~mask, __ATOMIC_RELAXED); 192 if ((uintptr_t)set) 193 __atomic_or_fetch(&hdr->flags[0], (uintptr_t)set, __ATOMIC_RELAXED); 194 195 if (sizeof(mask) == sizeof(unsigned long)) 196 return; 197 198 mask >>= 32; 199 if ((uintptr_t)mask) 200 __atomic_and_fetch(&hdr->flags[1], (uintptr_t)~mask, __ATOMIC_RELAXED); 201 if ((uintptr_t)set) 202 __atomic_or_fetch(&hdr->flags[1], (uintptr_t)set, __ATOMIC_RELAXED); 203 } 204 205 struct udebug_snapshot * 206 udebug_remote_buf_snapshot(struct udebug_remote_buf *rb) 207 { 208 struct udebug_hdr *hdr = rb->buf.hdr; 209 struct udebug_ptr *last_ptr; 210 uint32_t data_start, data_end, data_used; 211 struct udebug_snapshot *s = NULL; 212 struct udebug_ptr *ptr_buf, *first_ptr; 213 uint32_t data_size, ptr_size; 214 uint32_t head, first_idx; 215 uint32_t prev_read_head = rb->head; 216 void *data_buf; 217 218 if (!hdr) 219 return NULL; 220 221 head = u32_get(&hdr->head); 222 rbuf_advance_read_head(rb, head, &data_start); 223 if (rb->head == head) 224 return NULL; 225 226 first_idx = rb->head; 227 first_ptr = udebug_ring_ptr(hdr, first_idx); 228 last_ptr = udebug_ring_ptr(hdr, head - 1); 229 data_end = last_ptr->start + last_ptr->len; 230 231 data_size = data_end - data_start; 232 ptr_size = head - rb->head; 233 if (data_size > rb->buf.data_size || ptr_size > rb->buf.ring_size) { 234 fprintf(stderr, "Invalid data size: %x > %x, %x > %x\n", data_size, (int)rb->buf.data_size, ptr_size, (int)rb->buf.ring_size); 235 goto out; 236 } 237 238 s = calloc_a(sizeof(*s), 239 &ptr_buf, ptr_size * sizeof(*ptr_buf), 240 &data_buf, data_size); 241 242 s->data = memcpy(data_buf, udebug_buf_ptr(&rb->buf, data_start), data_size); 243 s->data_size = data_size; 244 s->entries = ptr_buf; 245 s->dropped = rb->head - prev_read_head; 246 247 if (first_ptr > last_ptr) { 248 struct udebug_ptr *start_ptr = udebug_ring_ptr(hdr, 0); 249 struct udebug_ptr *end_ptr = udebug_ring_ptr(hdr, rb->buf.ring_size - 1) + 1; 250 uint32_t size = end_ptr - first_ptr; 251 memcpy(s->entries, first_ptr, size * sizeof(*s->entries)); 252 memcpy(s->entries + size, start_ptr, (last_ptr + 1 - start_ptr) * sizeof(*s->entries)); 253 } else { 254 memcpy(s->entries, first_ptr, (last_ptr + 1 - first_ptr) * sizeof(*s->entries)); 255 } 256 257 /* get a snapshot of the counter that indicates how much data has been 258 * clobbered by newly added entries */ 259 __sync_synchronize(); 260 data_used = u32_get(&hdr->data_used) - rb->buf.data_size; 261 262 s->n_entries = head - first_idx; 263 264 rbuf_advance_read_head(rb, head, NULL); 265 if (s->n_entries < rb->head - first_idx) { 266 free(s); 267 s = NULL; 268 goto out; 269 } 270 271 s->entries += rb->head - first_idx; 272 s->n_entries -= rb->head - first_idx; 273 while (s->n_entries > 0 && 274 u32_sub(s->entries[0].start, data_used) < 0) { 275 s->entries++; 276 s->n_entries--; 277 s->dropped++; 278 } 279 280 for (size_t i = 0; i < s->n_entries; i++) 281 s->entries[i].start -= data_start; 282 283 s->format = hdr->format; 284 s->sub_format = hdr->sub_format; 285 s->rbuf_idx = (uint32_t)(uintptr_t)rb->node.key; 286 287 out: 288 rb->head = head; 289 return s; 290 } 291 292 bool udebug_snapshot_get_entry(struct udebug_snapshot *s, struct udebug_iter *it, unsigned int entry) 293 { 294 struct udebug_ptr *ptr; 295 296 it->len = 0; 297 if (entry >= s->n_entries) 298 goto error; 299 300 ptr = &s->entries[entry]; 301 if (ptr->start > s->data_size || ptr->len > s->data_size || 302 ptr->start + ptr->len > s->data_size) 303 goto error; 304 305 it->s = s; 306 it->data = s->data + ptr->start; 307 it->len = ptr->len; 308 it->timestamp = ptr->timestamp; 309 return true; 310 311 error: 312 it->data = NULL; 313 return false; 314 } 315 316 void udebug_iter_start(struct udebug_iter *it, struct udebug_snapshot **s, size_t n) 317 { 318 memset(it, 0, sizeof(*it)); 319 320 it->list = s; 321 it->n = n; 322 323 for (size_t i = 0; i < it->n; i++) 324 it->list[i]->iter_idx = 0; 325 } 326 327 bool udebug_iter_next(struct udebug_iter *it) 328 { 329 while (1) { 330 struct udebug_snapshot *s; 331 uint64_t cur_ts; 332 int cur = -1; 333 334 for (size_t i = 0; i < it->n; i++) { 335 struct udebug_ptr *ptr; 336 337 s = it->list[i]; 338 if (s->iter_idx >= s->n_entries) 339 continue; 340 341 ptr = &s->entries[s->iter_idx]; 342 if (cur >= 0 && ptr->timestamp > cur_ts) 343 continue; 344 345 cur = i; 346 cur_ts = ptr->timestamp; 347 } 348 349 if (cur < 0) 350 return false; 351 352 s = it->list[cur]; 353 it->s_idx = cur; 354 if (!udebug_snapshot_get_entry(s, it, s->iter_idx++)) 355 continue; 356 357 return true; 358 } 359 } 360
This page was automatically generated by LXR 0.3.1. • OpenWrt