2 #include <libubox/utils.h>
3 #include <libubox/usock.h>
4 #include <libubox/udebug.h>
5 #include <ucode/module.h>
6 #include "udebug-pcap.h"
8 static uc_resource_type_t
*rbuf_type
, *wbuf_type
, *snapshot_type
, *pcap_type
;
9 static uc_value_t
*registry
;
10 static struct udebug u
;
14 struct pcap_context pcap
;
19 static size_t add_registry(uc_value_t
*val
)
23 while (ucv_array_get(registry
, i
))
26 ucv_array_set(registry
, i
, ucv_get(val
));
32 uc_udebug_notify_cb(struct udebug
*ctx
, struct udebug_remote_buf
*rb
)
34 uintptr_t idx
= (uintptr_t)rb
->priv
;
35 uc_value_t
*cb
, *this;
38 this = ucv_array_get(registry
, idx
);
39 cb
= ucv_array_get(registry
, idx
+ 1);
41 if (!ucv_is_callable(cb
))
44 uc_vm_stack_push(vm
, ucv_get(this));
45 uc_vm_stack_push(vm
, ucv_get(cb
));
46 if (uc_vm_call(vm
, true, 0) != EXCEPTION_NONE
)
49 ucv_put(uc_vm_stack_pop(vm
));
53 uc_udebug_init(uc_vm_t
*vm
, size_t nargs
)
55 uc_value_t
*arg
= uc_fn_arg(0);
56 uc_value_t
*flag_auto
= uc_fn_arg(1);
57 const char *path
= NULL
;
59 if (ucv_type(arg
) == UC_STRING
)
60 path
= ucv_string_get(arg
);
63 u
.notify_cb
= uc_udebug_notify_cb
;
64 if (flag_auto
&& !ucv_is_truish(flag_auto
)) {
65 if (udebug_connect(&u
, path
))
68 udebug_auto_connect(&u
, path
);
71 return ucv_boolean_new(true);
75 uc_udebug_get_ring(uc_vm_t
*vm
, size_t nargs
)
77 struct udebug_remote_buf
*rb
;
78 struct udebug_packet_info
*info
;
79 uc_value_t
*arg
= uc_fn_arg(0);
80 uc_value_t
*id
, *proc
, *name
, *pid
;
81 int ifname_len
, ifdesc_len
;
82 char *ifname_buf
, *ifdesc_buf
;
86 #define R_IFACE_DESC "%s:%d"
88 if (ucv_type(arg
) != UC_OBJECT
)
91 id
= ucv_object_get(arg
, "id", NULL
);
92 proc
= ucv_object_get(arg
, "proc_name", NULL
);
93 name
= ucv_object_get(arg
, "ring_name", NULL
);
94 pid
= ucv_object_get(arg
, "pid", NULL
);
96 if (ucv_type(id
) != UC_INTEGER
||
97 ucv_type(proc
) != UC_STRING
||
98 ucv_type(name
) != UC_STRING
||
99 ucv_type(pid
) != UC_INTEGER
)
102 ifname_len
= strlen(ucv_string_get(name
)) + 1;
103 ifdesc_len
= sizeof(R_IFACE_DESC
) + strlen(ucv_string_get(proc
)) + 10;
104 rb
= calloc_a(sizeof(*rb
),
105 &info
, sizeof(*info
),
106 &ifname_buf
, ifname_len
,
107 &ifdesc_buf
, ifdesc_len
);
110 strcpy(ifname_buf
, ucv_string_get(name
));
111 info
->attr
[UDEBUG_META_IFACE_NAME
] = ifname_buf
;
112 snprintf(ifdesc_buf
, ifdesc_len
, R_IFACE_DESC
,
113 ucv_string_get(proc
), (unsigned int)ucv_int64_get(pid
));
114 info
->attr
[UDEBUG_META_IFACE_DESC
] = ifdesc_buf
;
116 if (udebug_remote_buf_map(&u
, rb
, (uint32_t)ucv_int64_get(id
))) {
121 res
= uc_resource_new(rbuf_type
, rb
);
122 idx
= add_registry(res
);
123 rb
->priv
= (void *)idx
;
128 static void rbuf_free(void *ptr
)
130 struct udebug_remote_buf
*rb
= ptr
;
136 idx
= (uintptr_t)rb
->priv
;
137 ucv_array_set(registry
, idx
, NULL
);
138 ucv_array_set(registry
, idx
+ 1, NULL
);
139 udebug_remote_buf_unmap(&u
, rb
);
144 uc_udebug_rbuf_fetch(uc_vm_t
*vm
, size_t nargs
)
146 struct udebug_remote_buf
*rb
= uc_fn_thisval("udebug.rbuf");
147 struct udebug_snapshot
*s
;
152 s
= udebug_remote_buf_snapshot(rb
);
156 return uc_resource_new(snapshot_type
, s
);
160 uc_udebug_rbuf_set_poll_cb(uc_vm_t
*vm
, size_t nargs
)
162 struct udebug_remote_buf
*rb
= uc_fn_thisval("udebug.rbuf");
163 uc_value_t
*val
= uc_fn_arg(0);
169 idx
= (uintptr_t)rb
->priv
;
170 ucv_array_set(registry
, idx
+ 1, ucv_get(val
));
171 if (!u
.fd
.registered
)
172 udebug_add_uloop(&u
);
173 udebug_remote_buf_set_poll(&u
, rb
, ucv_is_callable(val
));
179 uc_udebug_rbuf_set_fetch_duration(uc_vm_t
*vm
, size_t nargs
)
181 struct udebug_remote_buf
*rb
= uc_fn_thisval("udebug.rbuf");
182 uc_value_t
*val
= uc_fn_arg(0);
189 t
= ucv_double_get(val
);
193 ts
= udebug_timestamp();
194 ts
-= (uint64_t)(fabs(t
) * UDEBUG_TS_SEC
);
195 udebug_remote_buf_set_start_time(rb
, ts
);
197 return ucv_boolean_new(true);
201 uc_udebug_rbuf_set_fetch_count(uc_vm_t
*vm
, size_t nargs
)
203 struct udebug_remote_buf
*rb
= uc_fn_thisval("udebug.rbuf");
204 uc_value_t
*val
= uc_fn_arg(0);
210 count
= ucv_int64_get(val
);
211 udebug_remote_buf_set_start_offset(rb
, count
);
213 return ucv_boolean_new(true);
217 uc_udebug_rbuf_change_flags(uc_vm_t
*vm
, size_t nargs
)
219 struct udebug_remote_buf
*rb
= uc_fn_thisval("udebug.rbuf");
220 uc_value_t
*mask
= uc_fn_arg(0);
221 uc_value_t
*set
= uc_fn_arg(1);
226 if (ucv_type(mask
) != UC_INTEGER
|| ucv_type(set
) != UC_INTEGER
)
229 udebug_remote_buf_set_flags(rb
, ucv_int64_get(mask
), ucv_int64_get(set
));
230 return ucv_boolean_new(true);
234 uc_udebug_rbuf_get_flags(uc_vm_t
*vm
, size_t nargs
)
236 struct udebug_remote_buf
*rb
= uc_fn_thisval("udebug.rbuf");
240 return ucv_int64_new(udebug_buf_flags(&rb
->buf
));
244 uc_udebug_rbuf_close(uc_vm_t
*vm
, size_t nargs
)
246 void **p
= uc_fn_this("udebug.rbuf");
258 uc_udebug_pcap_init(struct uc_pcap
*p
, uc_value_t
*args
)
260 uc_value_t
*hw
, *os
, *app
;
261 struct pcap_meta meta
= {};
263 if (ucv_type(args
) == UC_OBJECT
) {
264 hw
= ucv_object_get(args
, "hw", NULL
);
265 os
= ucv_object_get(args
, "os", NULL
);
266 app
= ucv_object_get(args
, "app", NULL
);
268 meta
.hw
= ucv_string_get(hw
);
269 meta
.os
= ucv_string_get(os
);
270 meta
.app
= ucv_string_get(app
);
273 pcap_init(&p
->pcap
, &meta
);
277 write_retry(int fd
, const void *data
, size_t len
)
282 cur
= write(fd
, data
, len
);
296 uc_udebug_pcap_write_block(struct uc_pcap
*p
)
301 data
= pcap_block_get(&len
);
302 write_retry(p
->fd
, data
, len
);
306 uc_debug_pcap_init(int fd
, uc_value_t
*args
)
313 p
= calloc(1, sizeof(*p
));
315 uc_udebug_pcap_init(p
, args
);
316 uc_udebug_pcap_write_block(p
);
318 return uc_resource_new(pcap_type
, p
);
322 uc_udebug_pcap_file(uc_vm_t
*vm
, size_t nargs
)
324 uc_value_t
*file
= uc_fn_arg(0);
325 uc_value_t
*args
= uc_fn_arg(1);
328 if (ucv_type(file
) == UC_STRING
) {
329 fd
= open(ucv_string_get(file
), O_WRONLY
| O_CREAT
, 0644);
330 if (ftruncate(fd
, 0) < 0) {
337 return uc_debug_pcap_init(fd
, args
);
341 uc_udebug_pcap_udp(uc_vm_t
*vm
, size_t nargs
)
343 uc_value_t
*host
= uc_fn_arg(0);
344 uc_value_t
*port
= uc_fn_arg(1);
345 uc_value_t
*args
= uc_fn_arg(2);
346 const char *port_str
;
349 if (ucv_type(host
) != UC_STRING
)
352 if (ucv_type(port
) == UC_STRING
)
353 port_str
= ucv_string_get(port
);
354 else if (ucv_type(port
) == UC_INTEGER
)
355 port_str
= usock_port(ucv_int64_get(port
));
359 fd
= usock(USOCK_UDP
, ucv_string_get(host
), port_str
);
361 return uc_debug_pcap_init(fd
, args
);
364 static struct udebug_snapshot
*
365 uc_get_snapshot(uc_value_t
*val
)
367 return ucv_resource_data(val
, "udebug.snapshot");
371 uc_udebug_pcap_write(uc_vm_t
*vm
, size_t nargs
)
373 struct uc_pcap
*p
= uc_fn_thisval("udebug.pcap");
374 uc_value_t
*arg
= uc_fn_arg(0);
375 size_t n
= ucv_type(arg
) == UC_ARRAY
? ucv_array_length(arg
) : 1;
376 struct udebug_snapshot
**s
;
377 struct udebug_iter it
;
382 s
= alloca(n
* sizeof(*s
));
383 if (ucv_type(arg
) == UC_ARRAY
)
384 for (size_t i
= 0; i
< n
; i
++) {
385 if ((s
[i
] = uc_get_snapshot(ucv_array_get(arg
, i
))) == NULL
)
388 if ((s
[0] = uc_get_snapshot(arg
)) == NULL
)
392 udebug_iter_start(&it
, s
, n
);
393 while (udebug_iter_next(&it
)) {
394 struct udebug_remote_buf
*rb
;
396 rb
= udebug_remote_buf_get(&u
, it
.s
->rbuf_idx
);
397 if (!pcap_interface_is_valid(&p
->pcap
, rb
->pcap_iface
)) {
398 if (pcap_interface_rbuf_init(&p
->pcap
, rb
))
401 uc_udebug_pcap_write_block(p
);
404 if (pcap_snapshot_packet_init(&u
, &it
))
407 uc_udebug_pcap_write_block(p
);
414 uc_udebug_pcap_free(void *ptr
)
416 struct uc_pcap
*p
= ptr
;
427 uc_udebug_pcap_close(uc_vm_t
*vm
, size_t nargs
)
429 void **p
= uc_fn_this("udebug.pcap");
434 uc_udebug_pcap_free(*p
);
441 uc_udebug_snapshot_get_ring(uc_vm_t
*vm
, size_t nargs
)
443 struct udebug_snapshot
*s
= uc_fn_thisval("udebug.snapshot");
444 struct udebug_remote_buf
*rb
;
450 rb
= udebug_remote_buf_get(&u
, s
->rbuf_idx
);
454 idx
= (uintptr_t)rb
->priv
;
455 return ucv_array_get(registry
, idx
);
459 uc_udebug_foreach_packet(uc_vm_t
*vm
, size_t nargs
)
461 uc_value_t
*arg
= uc_fn_arg(0);
462 uc_value_t
*fn
= uc_fn_arg(1);
463 size_t n
= ucv_type(arg
) == UC_ARRAY
? ucv_array_length(arg
) : 1;
464 struct udebug_snapshot
**s
;
465 struct udebug_iter it
;
467 if (!ucv_is_callable(fn
))
470 s
= alloca(n
* sizeof(*s
));
471 if (ucv_type(arg
) == UC_ARRAY
)
472 for (size_t i
= 0; i
< n
; i
++) {
473 if ((s
[i
] = uc_get_snapshot(ucv_array_get(arg
, i
))) == NULL
)
476 if ((s
[0] = uc_get_snapshot(arg
)) == NULL
)
480 udebug_iter_start(&it
, s
, n
);
481 while (udebug_iter_next(&it
)) {
484 if (ucv_type(arg
) == UC_ARRAY
)
485 s_obj
= ucv_array_get(arg
, it
.s_idx
);
489 uc_vm_stack_push(vm
, ucv_get(_uc_fn_this_res(vm
)));
490 uc_vm_stack_push(vm
, ucv_get(fn
));
491 uc_vm_stack_push(vm
, ucv_get(s_obj
));
492 uc_vm_stack_push(vm
, ucv_string_new_length(it
.data
, it
.len
));
494 if (uc_vm_call(vm
, true, 2) != EXCEPTION_NONE
)
497 ucv_put(uc_vm_stack_pop(vm
));
504 uc_udebug_create_ring(uc_vm_t
*vm
, size_t nargs
)
506 uc_value_t
*name
, *flags_arr
, *size
, *entries
;
507 uc_value_t
*meta_obj
= uc_fn_arg(0);
508 struct udebug_buf_flag
*flags
;
509 struct udebug_buf_meta
*meta
;
510 struct udebug_buf
*buf
;
511 size_t flag_str_len
= 0;
512 size_t flags_len
= 0;
513 char *name_buf
, *flag_name_buf
;
515 if (ucv_type(meta_obj
) != UC_OBJECT
)
518 name
= ucv_object_get(meta_obj
, "name", NULL
);
519 flags_arr
= ucv_object_get(meta_obj
, "flags", NULL
);
520 size
= ucv_object_get(meta_obj
, "size", NULL
);
521 entries
= ucv_object_get(meta_obj
, "entries", NULL
);
523 if (ucv_type(name
) != UC_STRING
||
524 ucv_type(size
) != UC_INTEGER
|| ucv_type(entries
) != UC_INTEGER
)
527 if (ucv_type(flags_arr
) == UC_ARRAY
) {
528 flags_len
= ucv_array_length(flags_arr
);
529 for (size_t i
= 0; i
< flags_len
; i
++) {
530 uc_value_t
*f
= ucv_array_get(flags_arr
, i
);
531 if (ucv_type(f
) != UC_STRING
)
533 flag_str_len
+= strlen(ucv_string_get(f
)) + 1;
537 buf
= calloc_a(sizeof(*buf
),
538 &name_buf
, strlen(ucv_string_get(name
)) + 1,
540 &flags
, flags_len
* sizeof(*flags
),
541 &flag_name_buf
, flag_str_len
);
542 meta
->name
= strcpy(name_buf
, ucv_string_get(name
));
543 meta
->format
= UDEBUG_FORMAT_STRING
;
546 for (size_t i
= 0; i
< flags_len
; i
++) {
547 uc_value_t
*f
= ucv_array_get(flags_arr
, i
);
548 const char *str
= ucv_string_get(f
);
549 size_t len
= strlen(str
) + 1;
551 flags
->name
= memcpy(name_buf
, str
, len
);
552 flags
->mask
= 1ULL << i
;
557 if (udebug_buf_init(buf
, ucv_int64_get(size
), ucv_int64_get(entries
))) {
562 udebug_buf_add(&u
, buf
, meta
);
564 return uc_resource_new(wbuf_type
, buf
);
567 static void wbuf_free(void *ptr
)
572 udebug_buf_free(ptr
);
577 uc_udebug_wbuf_flags(uc_vm_t
*vm
, size_t nargs
)
579 struct udebug_buf
*buf
= uc_fn_thisval("udebug.wbuf");
584 return ucv_int64_new(udebug_buf_flags(buf
));
588 uc_udebug_wbuf_close(uc_vm_t
*vm
, size_t nargs
)
590 void **p
= uc_fn_this("udebug.wbuf");
602 uc_udebug_wbuf_add_string(struct udebug_buf
*buf
, uc_value_t
*val
)
604 udebug_entry_init(buf
);
605 udebug_entry_append(buf
, ucv_string_get(val
), ucv_string_length(val
));
606 udebug_entry_add(buf
);
610 uc_udebug_wbuf_add(uc_vm_t
*vm
, size_t nargs
)
612 struct udebug_buf
*buf
= uc_fn_thisval("udebug.wbuf");
613 uc_value_t
*arg
= uc_fn_arg(0);
615 if (!buf
|| ucv_type(arg
) != UC_STRING
)
618 uc_udebug_wbuf_add_string(buf
, arg
);
620 return ucv_boolean_new(true);
623 static const uc_function_list_t pcap_fns
[] = {
624 { "close", uc_udebug_pcap_close
},
625 { "write", uc_udebug_pcap_write
},
628 static const uc_function_list_t snapshot_fns
[] = {
629 { "get_ring", uc_udebug_snapshot_get_ring
}
632 static const uc_function_list_t wbuf_fns
[] = {
633 { "add", uc_udebug_wbuf_add
},
634 { "flags", uc_udebug_wbuf_flags
},
635 { "close", uc_udebug_wbuf_close
},
638 static const uc_function_list_t rbuf_fns
[] = {
639 { "set_poll_cb", uc_udebug_rbuf_set_poll_cb
},
640 { "fetch", uc_udebug_rbuf_fetch
},
641 { "change_flags", uc_udebug_rbuf_change_flags
},
642 { "get_flags", uc_udebug_rbuf_get_flags
},
643 { "set_fetch_duration", uc_udebug_rbuf_set_fetch_duration
},
644 { "set_fetch_count", uc_udebug_rbuf_set_fetch_count
},
645 { "close", uc_udebug_rbuf_close
},
648 static const uc_function_list_t global_fns
[] = {
649 { "init", uc_udebug_init
},
650 { "create_ring", uc_udebug_create_ring
},
651 { "get_ring", uc_udebug_get_ring
},
652 { "pcap_file", uc_udebug_pcap_file
},
653 { "pcap_udp", uc_udebug_pcap_udp
},
654 { "foreach_packet", uc_udebug_foreach_packet
},
657 void uc_module_init(uc_vm_t
*vm
, uc_value_t
*scope
)
660 uc_function_list_register(scope
, global_fns
);
662 wbuf_type
= uc_type_declare(vm
, "udebug.wbuf", wbuf_fns
, wbuf_free
);
663 rbuf_type
= uc_type_declare(vm
, "udebug.rbuf", rbuf_fns
, rbuf_free
);
664 snapshot_type
= uc_type_declare(vm
, "udebug.snapshot", snapshot_fns
, free
);
665 pcap_type
= uc_type_declare(vm
, "udebug.pcap", pcap_fns
, uc_udebug_pcap_free
);
667 registry
= ucv_array_new(vm
);
668 uc_vm_registry_set(vm
, "udebug.registry", registry
);