From e7851641a192e6eb86f0f25c039a2337b95a2ad5 Mon Sep 17 00:00:00 2001 From: York Jasper Niebuhr Date: Sun, 5 Apr 2026 10:55:34 +0200 Subject: [PATCH] Implemented array handling --- pinpoint/stage0/on_finish_decl.cpp | 31 +++++ pinpoint/stage0/separate_offset_pass.cpp | 152 +++++++++++++---------- subject/main.c | 27 ++-- subject/task_struct.h | 8 ++ 4 files changed, 143 insertions(+), 75 deletions(-) diff --git a/pinpoint/stage0/on_finish_decl.cpp b/pinpoint/stage0/on_finish_decl.cpp index d880b61..3e26921 100644 --- a/pinpoint/stage0/on_finish_decl.cpp +++ b/pinpoint/stage0/on_finish_decl.cpp @@ -36,6 +36,37 @@ static bool compile_datapin(tree type, DataPin& pin, std::size_t offset = 0, std res = true; } + if (TREE_CODE(type) == ARRAY_TYPE) { + tree elem_type = TREE_TYPE(type); + tree domain = TYPE_DOMAIN(type); + if (!elem_type || !domain) + return res; + + tree min_t = TYPE_MIN_VALUE(domain); + tree max_t = TYPE_MAX_VALUE(domain); + if (!min_t || !max_t || + TREE_CODE(min_t) != INTEGER_CST || + TREE_CODE(max_t) != INTEGER_CST) + return res; + + HOST_WIDE_INT min_i = tree_to_shwi(min_t); + HOST_WIDE_INT max_i = tree_to_shwi(max_t); + std::size_t elem_size = tree_to_uhwi(TYPE_SIZE_UNIT(elem_type)); + + for (HOST_WIDE_INT i = min_i; i <= max_i; ++i) { + bool sub_res = compile_datapin( + elem_type, + pin, + offset + (std::size_t)(i - min_i) * elem_size, + level + 1 + ); + res = res || sub_res; + } + + return res; + } + + // Note -> should probably make sure that randomized structs are never used in unions! if (TREE_CODE(type) != RECORD_TYPE /* && TREE_CODE(type) != UNION_TYPE */) return res; diff --git a/pinpoint/stage0/separate_offset_pass.cpp b/pinpoint/stage0/separate_offset_pass.cpp index 00c0861..18d0263 100644 --- a/pinpoint/stage0/separate_offset_pass.cpp +++ b/pinpoint/stage0/separate_offset_pass.cpp @@ -4,16 +4,23 @@ #include -struct ComponentRefChain { - struct Link { +struct AccessChain { + struct Step { + enum Kind { + STEP_COMPONENT, + STEP_ARRAY + } kind = STEP_COMPONENT; + tree t = NULL_TREE; + + /* COMPONENT_REF data */ bool relevant = false; - UID target; - std::size_t offset; + UID target = UID_INVALID; + std::size_t offset = 0; }; bool relevant = false; - std::list links; + std::list steps; tree base = NULL_TREE; }; @@ -35,100 +42,109 @@ static bool tree_contains_component_ref(tree ref) { return found_flag != 0; } -static bool component_ref_chain(tree ref, ComponentRefChain& chain) { +static bool access_chain(tree ref, AccessChain& chain) { if (!ref) return false; - if (TREE_CODE(ref) != COMPONENT_REF) { - if (chain.links.empty()) - return false; + switch (TREE_CODE(ref)) { + case COMPONENT_REF: { + AccessChain::Step step; + step.kind = AccessChain::Step::STEP_COMPONENT; + step.t = ref; + step.relevant = TargetType::reference(ref, step.target, step.offset); + if (step.relevant) + chain.relevant = true; + chain.steps.push_front(step); + return access_chain(TREE_OPERAND(ref, 0), chain); + } + case ARRAY_REF: + case ARRAY_RANGE_REF: { + AccessChain::Step step; + step.kind = AccessChain::Step::STEP_ARRAY; + step.t = ref; + chain.steps.push_front(step); + return access_chain(TREE_OPERAND(ref, 0), chain); + } + + default: if (tree_contains_component_ref(ref)) return false; - chain.base = ref; return true; } - - ComponentRefChain::Link link; - link.t = ref; - link.relevant = TargetType::reference(ref, link.target, link.offset); - - if (link.relevant) - chain.relevant = true; - - chain.links.push_front(link); - return component_ref_chain(TREE_OPERAND(ref, 0), chain); } static tree separate_offset_chain_maybe(tree ref, gimple_stmt_iterator* gsi) { - ComponentRefChain crc; - if (!component_ref_chain(ref, crc)) - pinpoint_fatal("separate_offset_chain_maybe encountered invalid COMPONENT_REF chain"); + AccessChain chain; + if (!access_chain(ref, chain)) { + pinpoint_fatal("separate_offset_chain_maybe encountered invalid access chain: top=%s base=%s", + get_tree_code_name(TREE_CODE(ref)), + TREE_OPERAND(ref, 0) ? get_tree_code_name(TREE_CODE(TREE_OPERAND(ref, 0))) : ""); + } - if (!crc.relevant) + if (!chain.relevant) return NULL_TREE; - // Get base pointer + tree cur_expr = chain.base; - tree base_tmp = NULL_TREE; + // NOTE -> Could fold into single call here (needs to track what offsets contribute, +irrelevant combined) - if (TREE_CODE(crc.base) == ADDR_EXPR) - pinpoint_fatal("separate_offset_chain_maybe encountered ADDR_EXPR as base of COMPONENT_REF"); + for (const AccessChain::Step& step : chain.steps) { + if (step.kind == AccessChain::Step::STEP_COMPONENT) { + if (TREE_CODE(cur_expr) == ADDR_EXPR) + pinpoint_fatal("separate_offset_chain_maybe encountered ADDR_EXPR as base of COMPONENT_REF"); - base_tmp = build_fold_addr_expr(crc.base); + tree cur_ptr = build_fold_addr_expr(cur_expr); - // For each component ref in chain, add the member offset to the pointer + tree field_ptr_type = build_pointer_type(TREE_TYPE(step.t)); + tree field_ptr; - for (const ComponentRefChain::Link& cr : crc.links) { - // NOTE -> Could fold into single call here (needs to track what offsets contribute, +irrelevant combined) - if (cr.relevant) { - // Call is a separate statement, the result is added to the base pointer - tree return_tmp = create_tmp_var(size_type_node, NULL); + if (step.relevant) { + tree return_tmp = create_tmp_var(size_type_node, NULL); + gimple* call_stmt = + make_stage0_gimple_separator(return_tmp, step.target, step.offset); + if (!call_stmt) + pinpoint_fatal("separate_offset_chain_maybe failed to make gimple separator"); - gimple* call_stmt = make_stage0_gimple_separator(return_tmp, cr.target, cr.offset); - if (!call_stmt) - pinpoint_fatal("separate_offset_chain_maybe failed to make gimple separator for target %u at offset %u", - (unsigned)cr.target, (unsigned)cr.offset); + gsi_insert_before(gsi, call_stmt, GSI_SAME_STMT); + field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type, cur_ptr, return_tmp); + } else { + tree field_decl = TREE_OPERAND(step.t, 1); - gsi_insert_before(gsi, call_stmt, GSI_SAME_STMT); + std::size_t field_offset; + bool field_bitfield; + if (!field_info(field_decl, &field_offset, nullptr, nullptr, &field_bitfield)) + pinpoint_fatal("separate_offset_chain_maybe failed to get field info of non-target access"); + if (field_bitfield) + pinpoint_fatal("separate_offset_chain_maybe encountered bitfield access in relevant COMPONENT_REF chain"); - // Add call return value to current base pointer (result is field pointer) - tree field_ptr_type = build_pointer_type(TREE_TYPE(cr.t)); - tree field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type, base_tmp, return_tmp); + field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type, + cur_ptr, build_int_cst(sizetype, field_offset)); + } - base_tmp = create_tmp_var(field_ptr_type, NULL); - gimple* field_ptr_assignment = gimple_build_assign(base_tmp, field_ptr); - gsi_insert_before(gsi, field_ptr_assignment, GSI_SAME_STMT); - } else { - // Add offsetof contant - tree field_decl = TREE_OPERAND(cr.t, 1); + tree ptr_tmp = create_tmp_var(field_ptr_type, NULL); + gimple* ptr_assign = gimple_build_assign(ptr_tmp, field_ptr); + gsi_insert_before(gsi, ptr_assign, GSI_SAME_STMT); - std::size_t field_offset; - bool field_bitfield; + // Dereference constructed pointer expression - if (!field_info(field_decl, &field_offset, nullptr, nullptr, &field_bitfield)) - pinpoint_fatal("separate_offset_chain_maybe failed to get field info of non-target access"); + tree offset0 = fold_convert(TREE_TYPE(ptr_tmp), build_int_cst(sizetype, 0)); + cur_expr = build2(MEM_REF, TREE_TYPE(step.t), ptr_tmp, offset0); + continue; + } - if (field_bitfield) - pinpoint_fatal("separate_offset_chain_maybe encountered bitfield access in relevant COMPONENT_REF chain"); + if (step.kind == AccessChain::Step::STEP_ARRAY) { + tree idx = TREE_OPERAND(step.t, 1); + tree low = TREE_OPERAND(step.t, 2); + tree elts = TREE_OPERAND(step.t, 3); - // Add constant offset to current base pointer (result is field pointer) - tree field_ptr_type = build_pointer_type(TREE_TYPE(cr.t)); - tree field_ptr = build2(POINTER_PLUS_EXPR, field_ptr_type, base_tmp, build_int_cst(sizetype, field_offset)); - - base_tmp = create_tmp_var(field_ptr_type, NULL); - gimple* field_ptr_assignment = gimple_build_assign(base_tmp, field_ptr); - gsi_insert_before(gsi, field_ptr_assignment, GSI_SAME_STMT); + cur_expr = build4(TREE_CODE(step.t), TREE_TYPE(step.t), cur_expr, idx, low, elts); + continue; } } - // Current pointer is a field pointer -> dereference - - tree offset0 = fold_convert(TREE_TYPE(base_tmp), build_int_cst(sizetype, 0)); - tree result_ref = build2(MEM_REF, TREE_TYPE(ref), base_tmp, offset0); - - return result_ref; + return cur_expr; } static void dispatch_separation_maybe(const std::list& path, gimple_stmt_iterator* gsi, unsigned& cancel_levels) { diff --git a/subject/main.c b/subject/main.c index 8a831d2..23f3e9d 100644 --- a/subject/main.c +++ b/subject/main.c @@ -7,17 +7,28 @@ const char* second_comm(); int subsecond_pid(); const char* subsecond_comm(); -struct task_struct global = { .pid = 42, .comm = "main_global" }; +struct task_struct global = { .pid = 42, .comm = "main_global", .arrfun = { + { .a = 1, .b = 2, .c = 3, .d = 4.0 }, + { .a = 5, .b = 6, .c = 7, .d = 8.0 }, + { .a = 9, .b = 10, .c = 11, .d = 12.0 }, + { .a = 13, .b = 14, .c = 15, .d = 16.0 }, + { .a = 17, .b = 18, .c = 19, .d = 20.0 } +} }; static void print_layout() { // TODO -> Make builtin __spslr_initial_offsetof(type, field) that is not patched printf("Current task_struct layout:\n"); - printf(" stuck0 (int) : %2llu -> %2llu\n", 0, offsetof(struct task_struct, stuck0)); - printf(" pid (int) : %2llu -> %2llu\n", 8, offsetof(struct task_struct, pid)); - printf(" comm (const char*) : %2llu -> %2llu\n", 16, offsetof(struct task_struct, comm)); - printf(" tasks (struct list_head) : %2llu -> %2llu\n", 24, offsetof(struct task_struct, tasks)); - printf(" stuck1 (int) : %2llu -> %2llu\n", 40, offsetof(struct task_struct, stuck1)); - printf(" stuck2 (int) : %2llu -> %2llu\n", 44, offsetof(struct task_struct, stuck2)); + printf(" stuck0 (int) : %2llu -> %2llu\n", 0, offsetof(struct task_struct, stuck0)); + printf(" pid (int) : %2llu -> %2llu\n", 8, offsetof(struct task_struct, pid)); + printf(" comm (const char*) : %2llu -> %2llu\n", 16, offsetof(struct task_struct, comm)); + printf(" arrfun (struct ArrayFun [5]) : %2llu -> %2llu\n", 24, offsetof(struct task_struct, arrfun)); + printf(" tasks (struct list_head) : %2llu -> %2llu\n", 144, offsetof(struct task_struct, tasks)); + printf(" stuck1 (int) : %2llu -> %2llu\n", 160, offsetof(struct task_struct, stuck1)); + printf(" stuck2 (int) : %2llu -> %2llu\n", 166, offsetof(struct task_struct, stuck2)); +} + +void arr_test() { + printf("Global arrfun[3].b: %d (should be 14)\n", global.arrfun[3].b); } int main(void) @@ -55,6 +66,8 @@ int main(void) printf("Second global: pid=%d comm=\"%s\"\n", second_pid(), second_comm()); printf("Subsecond global: pid=%d comm=\"%s\"\n", subsecond_pid(), subsecond_comm()); + arr_test(); + return 0; } diff --git a/subject/task_struct.h b/subject/task_struct.h index 6d16631..0af3bc6 100644 --- a/subject/task_struct.h +++ b/subject/task_struct.h @@ -43,7 +43,13 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head) #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) +struct ArrayFun { + int a, b, c; + double d; +} __attribute__((spslr)); + // A small struct like the Linux kernel's task_struct + struct task_struct { int stuck0; @@ -54,6 +60,8 @@ struct task_struct { int pid; const char *comm; + struct ArrayFun arrfun[5]; + randomized_struct_fields_end struct list_head tasks; // linkage for global task list