|
12 | 12 | #include <R_ext/Parse.h> |
13 | 13 | #include <stdint.h> |
14 | 14 | #include <inttypes.h> |
| 15 | +#include <limits.h> |
15 | 16 | #include <math.h> |
16 | 17 | #include <stdlib.h> |
17 | 18 | #include <string.h> |
@@ -46,6 +47,7 @@ SEXP RC_libtcc_compile_string(SEXP ext, SEXP code); |
46 | 47 | SEXP RC_libtcc_add_symbol(SEXP ext, SEXP name, SEXP addr); |
47 | 48 | SEXP RC_libtcc_relocate(SEXP ext); |
48 | 49 | SEXP RC_libtcc_get_symbol(SEXP ext, SEXP name); |
| 50 | +SEXP RC_libtcc_list_symbols(SEXP ext); |
49 | 51 | SEXP RC_libtcc_call_symbol(SEXP ext, SEXP name, SEXP ret_type); |
50 | 52 | SEXP RC_libtcc_ptr_valid(SEXP ptr); |
51 | 53 | SEXP RC_libtcc_output_file(SEXP ext, SEXP filename); |
@@ -553,6 +555,87 @@ SEXP RC_libtcc_get_symbol(SEXP ext, SEXP name) { |
553 | 555 | return ptr; |
554 | 556 | } |
555 | 557 |
|
| 558 | +typedef struct { |
| 559 | + R_xlen_t count; |
| 560 | +} RC_tcc_symbol_count_t; |
| 561 | + |
| 562 | +typedef struct { |
| 563 | + SEXP names; |
| 564 | + SEXP addresses; |
| 565 | + R_xlen_t index; |
| 566 | +} RC_tcc_symbol_collect_t; |
| 567 | + |
| 568 | +static void RC_libtcc_count_symbol_cb(void *ctx, const char *name, const void *val) { |
| 569 | + (void) name; |
| 570 | + (void) val; |
| 571 | + RC_tcc_symbol_count_t *counter = (RC_tcc_symbol_count_t *) ctx; |
| 572 | + counter->count++; |
| 573 | +} |
| 574 | + |
| 575 | +static void RC_libtcc_collect_symbol_cb(void *ctx, const char *name, const void *val) { |
| 576 | + RC_tcc_symbol_collect_t *collect = (RC_tcc_symbol_collect_t *) ctx; |
| 577 | + R_xlen_t i = collect->index++; |
| 578 | + if (i >= XLENGTH(collect->names)) { |
| 579 | + return; |
| 580 | + } |
| 581 | + |
| 582 | + char addr_buf[2 + (sizeof(uintptr_t) * 2) + 1]; |
| 583 | + if (val == NULL) { |
| 584 | + snprintf(addr_buf, sizeof(addr_buf), "0x0"); |
| 585 | + } else { |
| 586 | + snprintf(addr_buf, sizeof(addr_buf), "0x%" PRIxPTR, (uintptr_t) val); |
| 587 | + } |
| 588 | + |
| 589 | + SET_STRING_ELT( |
| 590 | + collect->names, |
| 591 | + i, |
| 592 | + Rf_mkCharCE(name == NULL ? "" : name, CE_UTF8) |
| 593 | + ); |
| 594 | + SET_STRING_ELT(collect->addresses, i, Rf_mkChar(addr_buf)); |
| 595 | +} |
| 596 | + |
| 597 | +/** |
| 598 | + * List global symbols known to a TCC state. |
| 599 | + * Ownership: none. |
| 600 | + * Allocation: result data frame only. |
| 601 | + * Protection: PROTECT(6), UNPROTECT(6). |
| 602 | + */ |
| 603 | +SEXP RC_libtcc_list_symbols(SEXP ext) { |
| 604 | + TCCState *s = RC_tcc_state(ext); |
| 605 | + |
| 606 | + RC_tcc_symbol_count_t counter = {0}; |
| 607 | + tcc_list_symbols(s, &counter, RC_libtcc_count_symbol_cb); |
| 608 | + if (counter.count > INT_MAX) { |
| 609 | + Rf_error("too many TCC symbols to return as a data frame"); |
| 610 | + } |
| 611 | + |
| 612 | + SEXP names_vec = PROTECT(Rf_allocVector(STRSXP, counter.count)); |
| 613 | + SEXP addresses_vec = PROTECT(Rf_allocVector(STRSXP, counter.count)); |
| 614 | + |
| 615 | + RC_tcc_symbol_collect_t collect = {names_vec, addresses_vec, 0}; |
| 616 | + tcc_list_symbols(s, &collect, RC_libtcc_collect_symbol_cb); |
| 617 | + |
| 618 | + SEXP out = PROTECT(Rf_allocVector(VECSXP, 2)); |
| 619 | + SET_VECTOR_ELT(out, 0, names_vec); |
| 620 | + SET_VECTOR_ELT(out, 1, addresses_vec); |
| 621 | + |
| 622 | + SEXP out_names = PROTECT(Rf_allocVector(STRSXP, 2)); |
| 623 | + SET_STRING_ELT(out_names, 0, Rf_mkChar("name")); |
| 624 | + SET_STRING_ELT(out_names, 1, Rf_mkChar("address")); |
| 625 | + Rf_setAttrib(out, R_NamesSymbol, out_names); |
| 626 | + |
| 627 | + SEXP row_names = PROTECT(Rf_allocVector(INTSXP, 2)); |
| 628 | + INTEGER(row_names)[0] = NA_INTEGER; |
| 629 | + INTEGER(row_names)[1] = -(int) counter.count; |
| 630 | + Rf_setAttrib(out, R_RowNamesSymbol, row_names); |
| 631 | + |
| 632 | + SEXP class_str = PROTECT(Rf_mkString("data.frame")); |
| 633 | + Rf_setAttrib(out, R_ClassSymbol, class_str); |
| 634 | + |
| 635 | + UNPROTECT(6); |
| 636 | + return out; |
| 637 | +} |
| 638 | + |
556 | 639 | /** |
557 | 640 | * Call a zero-argument symbol, casting to the requested return type. |
558 | 641 | * Ownership: none. |
|
0 commit comments