From 197ba14a4daed06c0a557579f13633c9e0782ddc Mon Sep 17 00:00:00 2001 From: Max Wash Date: Tue, 13 May 2025 13:23:59 +0100 Subject: [PATCH] asm: reader: implement constpool reader interface --- asm/include/ivy/asm/reader.h | 43 +++++- asm/reader.c | 292 ++++++++++++++++++++++++++++++++++- asm/reader.h | 5 + 3 files changed, 338 insertions(+), 2 deletions(-) diff --git a/asm/include/ivy/asm/reader.h b/asm/include/ivy/asm/reader.h index fe0849f..99c8d82 100644 --- a/asm/include/ivy/asm/reader.h +++ b/asm/include/ivy/asm/reader.h @@ -6,6 +6,20 @@ #include #include +#define IVY_ASM_SECTION_ANY_TYPE ((uint32_t) - 1) + +struct ivy_ident; + +enum ivy_asm_constpool_value_type { + IVY_ASM_CONSTPOOL_TYPE_NONE = 0, + IVY_ASM_CONSTPOOL_TYPE_INT, + IVY_ASM_CONSTPOOL_TYPE_UINT, + IVY_ASM_CONSTPOOL_TYPE_STRING, + IVY_ASM_CONSTPOOL_TYPE_ATOM, + IVY_ASM_CONSTPOOL_TYPE_IDENT, + IVY_ASM_CONSTPOOL_TYPE_SELECTOR, +}; + struct ivy_asm_object_info { uint32_t obj_magic; size_t obj_table_offset; @@ -18,8 +32,21 @@ struct ivy_asm_section_info { size_t s_length; }; +struct ivy_asm_constpool_value { + enum ivy_asm_constpool_value_type v_type; + + union { + long long v_int; + unsigned long long v_uint; + struct ivy_ident *v_ident; + struct ivy_selector *v_sel; + char *v_str; + }; +}; + struct ivy_asm_reader; struct ivy_asm_section_reader; +struct ivy_asm_constpool_reader; IVY_API enum ivy_status ivy_asm_reader_open(FILE *in, struct ivy_asm_reader **out); IVY_API enum ivy_status ivy_asm_reader_close(struct ivy_asm_reader *reader); @@ -30,8 +57,11 @@ IVY_API const struct ivy_asm_section_info *ivy_asm_reader_get_sections( struct ivy_asm_reader *reader); IVY_API enum ivy_status ivy_asm_reader_open_section( - struct ivy_asm_reader *reader, size_t index, + struct ivy_asm_reader *reader, uint32_t type, size_t index, struct ivy_asm_section_reader **out); +IVY_API enum ivy_status ivy_asm_reader_open_constpool( + struct ivy_asm_reader *reader, size_t constpool_index, + size_t xdat_index, struct ivy_asm_constpool_reader **out); IVY_API const struct ivy_asm_section_info *ivy_asm_section_reader_get_info( struct ivy_asm_section_reader *reader); @@ -41,6 +71,17 @@ IVY_API enum ivy_status ivy_asm_section_reader_read( struct ivy_asm_section_reader *reader, size_t offset, size_t count, void *p, size_t *nr_read); +IVY_API size_t ivy_asm_constpool_reader_get_nr_entries( + struct ivy_asm_constpool_reader *reader); +IVY_API enum ivy_status ivy_asm_constpool_reader_read_value( + struct ivy_asm_constpool_reader *reader, size_t index, + struct ivy_asm_constpool_value **out); +IVY_API enum ivy_status ivy_asm_constpool_reader_close( + struct ivy_asm_constpool_reader *reader); + +IVY_API enum ivy_status ivy_asm_constpool_value_destroy( + struct ivy_asm_constpool_value *v); + IVY_API bool ivy_asm_section_type_to_string(uint32_t in, char out[5]); #endif diff --git a/asm/reader.c b/asm/reader.c index 3b19596..6b9780d 100644 --- a/asm/reader.c +++ b/asm/reader.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -115,10 +117,38 @@ const struct ivy_asm_section_info *ivy_asm_reader_get_sections( return reader->r_sections; } +static size_t find_section(struct ivy_asm_reader *reader, uint32_t type, size_t index) +{ + if (type == IVY_ASM_SECTION_ANY_TYPE) { + return index; + } + + size_t nr_sections = reader->r_info.obj_nr_sections; + for (size_t i = 0; i < nr_sections; i++) { + if (reader->r_sections[i].s_type != type) { + continue; + } + + if (index > 0) { + index--; + continue; + } + + return i; + } + + return (size_t)-1; +} + enum ivy_status ivy_asm_reader_open_section( - struct ivy_asm_reader *reader, size_t index, + struct ivy_asm_reader *reader, uint32_t type, size_t index, struct ivy_asm_section_reader **out) { + index = find_section(reader, type, index); + if (index == (size_t)-1) { + return IVY_ERR_NO_ENTRY; + } + if (index >= reader->r_info.obj_nr_sections) { return IVY_ERR_NO_ENTRY; } @@ -137,6 +167,43 @@ enum ivy_status ivy_asm_reader_open_section( return IVY_OK; } +enum ivy_status ivy_asm_reader_open_constpool( + struct ivy_asm_reader *reader, size_t constpool_index, + size_t xdat_index, struct ivy_asm_constpool_reader **out) +{ + struct ivy_asm_section_reader *pool = NULL, *xdat = NULL; + enum ivy_status status = ivy_asm_reader_open_section( + reader, IVY_TABLE_POOL, constpool_index, &pool); + if (status == IVY_ERR_NO_ENTRY) { + return status; + } + + status = ivy_asm_reader_open_section( + reader, IVY_TABLE_XDAT, xdat_index, &xdat); + if (status == IVY_ERR_NO_ENTRY) { + ivy_asm_section_reader_close(pool); + return status; + } + + struct ivy_asm_constpool_reader *pool_reader = malloc(sizeof *pool_reader); + if (!pool_reader) { + ivy_asm_section_reader_close(pool); + ivy_asm_section_reader_close(xdat); + return IVY_ERR_NO_MEMORY; + } + + memset(pool_reader, 0x0, sizeof *pool_reader); + + pool_reader->r_pool = pool; + pool_reader->r_xdat = xdat; + pool_reader->r_nr_entries + = (pool->r_info->s_length - sizeof(struct ivy_bin_constpool)) + / sizeof(struct ivy_bin_constpool_table_entry); + + *out = pool_reader; + return IVY_OK; +} + const struct ivy_asm_section_info *ivy_asm_section_reader_get_info( struct ivy_asm_section_reader *reader) { @@ -163,6 +230,229 @@ enum ivy_status ivy_asm_section_reader_read( return ferror(fp) ? IVY_ERR_IO_FAILURE : IVY_OK; } +size_t ivy_asm_constpool_reader_get_nr_entries( + struct ivy_asm_constpool_reader *reader) +{ + return reader->r_nr_entries; +} + +static enum ivy_status read_string_xdata( + struct ivy_asm_constpool_reader *pool, size_t key, char **out) +{ + if (!key) { + *out = NULL; + return IVY_OK; + } + + size_t r; + struct ivy_bin_string str; + + enum ivy_status status = ivy_asm_section_reader_read( + pool->r_xdat, key, sizeof str, &str, &r); + + if (status != IVY_OK) { + return status; + } + + if (r != sizeof str) { + return IVY_ERR_BAD_FORMAT; + } + + size_t str_len = b_i32_btoh(str.s_len); + if (str_len == 0) { + *out = NULL; + return IVY_OK; + } + + char *s = malloc(str_len + 1); + if (!s) { + return IVY_ERR_NO_MEMORY; + } + + status = ivy_asm_section_reader_read( + pool->r_xdat, key + sizeof str, str_len, s, &r); + if (status != IVY_OK) { + free(s); + return status; + } + + if (r != str_len) { + free(s); + return IVY_ERR_BAD_FORMAT; + } + + s[str_len] = 0; + *out = s; + return IVY_OK; +} + +enum ivy_status ivy_asm_constpool_reader_read_value( + struct ivy_asm_constpool_reader *reader, size_t index, + struct ivy_asm_constpool_value **out) +{ + struct ivy_bin_constpool_table_entry entry; + enum ivy_status status = IVY_OK; + size_t r, offset + = sizeof(struct ivy_bin_constpool) + (index * sizeof entry); + + status = ivy_asm_section_reader_read( + reader->r_pool, offset, sizeof entry, &entry, &r); + + if (status != IVY_OK) { + return status; + } + + if (r != sizeof entry) { + return IVY_ERR_BAD_FORMAT; + } + + unsigned long type = b_i32_btoh(entry.e_type); + + struct ivy_asm_constpool_value *value = malloc(sizeof *value); + if (!value) { + return IVY_ERR_NO_MEMORY; + } + + memset(value, 0x0, sizeof *value); + size_t handle; + + switch (type) { + case IVY_CONSTPOOL_TABLE_STRING: { + value->v_type = IVY_ASM_CONSTPOOL_TYPE_STRING; + handle = b_i32_btoh(entry.e_ex_handle); + status = read_string_xdata(reader, handle, &value->v_str); + break; + } + case IVY_CONSTPOOL_TABLE_INT: + value->v_type = IVY_ASM_CONSTPOOL_TYPE_INT; + value->v_int = b_i32_btoh(entry.e_int); + break; + case IVY_CONSTPOOL_TABLE_UINT: + value->v_type = IVY_ASM_CONSTPOOL_TYPE_UINT; + value->v_uint = b_i32_btoh(entry.e_int); + break; + case IVY_CONSTPOOL_TABLE_ATOM: + value->v_type = IVY_ASM_CONSTPOOL_TYPE_ATOM; + break; + case IVY_CONSTPOOL_TABLE_SELECTOR: { + value->v_type = IVY_ASM_CONSTPOOL_TYPE_SELECTOR; + handle = b_i32_btoh(entry.e_ex_handle); + + struct ivy_bin_selector sel_entry; + status = ivy_asm_section_reader_read( + reader->r_xdat, handle, sizeof sel_entry, &sel_entry, &r); + + if (status != IVY_OK) { + break; + } + + if (r != sizeof sel_entry) { + status = IVY_ERR_BAD_FORMAT; + break; + } + + struct ivy_selector *sel; + status = ivy_selector_create(&sel); + if (status != IVY_OK) { + break; + } + + if (sel_entry.sel_flags & IVY_BIN_SELECTOR_OBJECT) { + ivy_selector_set_recipient(sel, IVY_SEL_OBJECT); + } else if (sel_entry.sel_flags & IVY_BIN_SELECTOR_CLASS) { + ivy_selector_set_recipient(sel, IVY_SEL_CLASS); + } + + size_t name_key = b_i32_btoh(sel_entry.sel_name); + status = read_string_xdata(reader, name_key, &sel->sel_name); + if (status != IVY_OK) { + ivy_selector_destroy(sel); + break; + } + + handle += sizeof sel_entry; + size_t nr_args = sel_entry.sel_nr_args; + for (size_t i = 0; i < nr_args; i++) { + b_i32 arg; + status = ivy_asm_section_reader_read( + reader->r_xdat, handle, sizeof arg, &arg, &r); + + if (status != IVY_OK) { + break; + } + + if (r != sizeof arg) { + status = IVY_ERR_BAD_FORMAT; + break; + } + + size_t arg_key = b_i32_btoh(arg); + char *arg_name = NULL; + status = read_string_xdata(reader, arg_key, &arg_name); + if (status != IVY_OK) { + break; + } + + ivy_selector_add_arg(sel, arg_name, NULL); + free(arg_name); + } + + if (status != IVY_OK) { + ivy_selector_destroy(sel); + break; + } + + value->v_sel = sel; + break; + } + case IVY_CONSTPOOL_TABLE_IDENT: + value->v_type = IVY_ASM_CONSTPOOL_TYPE_IDENT; + break; + default: + status = IVY_ERR_BAD_FORMAT; + break; + } + + if (status != IVY_OK) { + free(value); + value = NULL; + } + + *out = value; + return status; +} + +enum ivy_status ivy_asm_constpool_reader_close( + struct ivy_asm_constpool_reader *reader) +{ + ivy_asm_section_reader_close(reader->r_pool); + ivy_asm_section_reader_close(reader->r_xdat); + free(reader); + + return IVY_OK; +} + +enum ivy_status ivy_asm_constpool_value_destroy(struct ivy_asm_constpool_value *v) +{ + switch (v->v_type) { + case IVY_ASM_CONSTPOOL_TYPE_IDENT: + ivy_ident_destroy(v->v_ident); + break; + case IVY_ASM_CONSTPOOL_TYPE_SELECTOR: + ivy_selector_destroy(v->v_sel); + break; + case IVY_ASM_CONSTPOOL_TYPE_STRING: + free(v->v_str); + break; + default: + break; + } + + free(v); + + return IVY_OK; +} + bool ivy_asm_section_type_to_string(uint32_t in, char out[5]) { b_i32 v = b_i32_htob(in); diff --git a/asm/reader.h b/asm/reader.h index c7a0480..7a31a94 100644 --- a/asm/reader.h +++ b/asm/reader.h @@ -15,4 +15,9 @@ struct ivy_asm_section_reader { const struct ivy_asm_section_info *r_info; }; +struct ivy_asm_constpool_reader { + size_t r_nr_entries; + struct ivy_asm_section_reader *r_pool, *r_xdat; +}; + #endif