1 /* 2 * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <assert.h> 18 19 #include "ucode/chunk.h" 20 #include "ucode/types.h" 21 #include "ucode/util.h" 22 23 #define OFFSETINFO_BITS (sizeof(((uc_offsetinfo_t *)NULL)->entries[0]) * 8) 24 #define OFFSETINFO_BYTE_BITS 3 25 #define OFFSETINFO_INSN_BITS (OFFSETINFO_BITS - OFFSETINFO_BYTE_BITS) 26 #define OFFSETINFO_MAX_BYTES ((1 << OFFSETINFO_BYTE_BITS) - 1) 27 #define OFFSETINFO_MAX_INSNS ((1 << OFFSETINFO_INSN_BITS) - 1) 28 #define OFFSETINFO_NUM_BYTES(n) ((n) & OFFSETINFO_MAX_BYTES) 29 #define OFFSETINFO_NUM_INSNS(n) ((n) >> OFFSETINFO_BYTE_BITS) 30 #define OFFSETINFO_ENCODE(line, insns) ((line & OFFSETINFO_MAX_BYTES) | (((insns) << OFFSETINFO_BYTE_BITS) & ~OFFSETINFO_MAX_BYTES)) 31 32 33 void 34 uc_chunk_init(uc_chunk_t *chunk) 35 { 36 chunk->count = 0; 37 chunk->entries = NULL; 38 39 chunk->ehranges.count = 0; 40 chunk->ehranges.entries = NULL; 41 42 chunk->debuginfo.offsets.count = 0; 43 chunk->debuginfo.offsets.entries = NULL; 44 45 chunk->debuginfo.variables.count = 0; 46 chunk->debuginfo.variables.entries = NULL; 47 48 uc_vallist_init(&chunk->debuginfo.varnames); 49 } 50 51 void 52 uc_chunk_free(uc_chunk_t *chunk) 53 { 54 uc_vector_clear(chunk); 55 uc_vector_clear(&chunk->ehranges); 56 57 uc_vector_clear(&chunk->debuginfo.offsets); 58 uc_vector_clear(&chunk->debuginfo.variables); 59 uc_vallist_free(&chunk->debuginfo.varnames); 60 61 uc_chunk_init(chunk); 62 } 63 64 size_t 65 uc_chunk_add(uc_chunk_t *chunk, uint8_t byte, size_t offset) 66 { 67 uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets; 68 size_t i; 69 70 uc_vector_push(chunk, byte); 71 72 /* offset info is encoded in bytes, for each byte, the first three bits 73 * specify the number of source text bytes to advance since the last entry 74 * and the remaining five bits specify the amount of instructions belonging 75 * to any given source text offset */ 76 if (offset > 0 || offsets->count == 0) { 77 /* if this offset is farther than seven (2 ** 3 - 1) bytes apart from 78 * the last one, we need to emit intermediate "jump" bytes with zero 79 * instructions each */ 80 for (i = offset; i > OFFSETINFO_MAX_BYTES; i -= OFFSETINFO_MAX_BYTES) { 81 /* advance by 7 bytes */ 82 uc_vector_push(offsets, OFFSETINFO_ENCODE(OFFSETINFO_MAX_BYTES, 0)); 83 } 84 85 /* advance by `i` bytes, count one instruction */ 86 uc_vector_push(offsets, OFFSETINFO_ENCODE(i, 1)); 87 } 88 89 /* update instruction count at current offset entry */ 90 else { 91 /* since we encode the per-offset instruction count in five bits, we 92 * can only count up to 31 instructions. If we exceed that limit, 93 * emit another offset entry with the initial three bits set to zero */ 94 if (OFFSETINFO_NUM_INSNS(offsets->entries[offsets->count - 1]) >= OFFSETINFO_MAX_INSNS) { 95 /* advance by 0 bytes, count one instruction */ 96 uc_vector_push(offsets, OFFSETINFO_ENCODE(0, 1)); 97 } 98 else { 99 uint8_t *prev = uc_vector_last(offsets); 100 101 *prev = OFFSETINFO_ENCODE( 102 OFFSETINFO_NUM_BYTES(*prev), 103 OFFSETINFO_NUM_INSNS(*prev) + 1); 104 } 105 } 106 107 return chunk->count - 1; 108 } 109 110 void 111 uc_chunk_pop(uc_chunk_t *chunk) 112 { 113 uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets; 114 int n_insns; 115 116 assert(chunk->count > 0); 117 118 chunk->count--; 119 120 n_insns = OFFSETINFO_NUM_INSNS(offsets->entries[offsets->count - 1]); 121 122 if (n_insns > 0) { 123 uint8_t *prev = uc_vector_last(offsets); 124 125 *prev = OFFSETINFO_ENCODE(OFFSETINFO_NUM_BYTES(*prev), n_insns - 1); 126 } 127 else { 128 offsets->count--; 129 } 130 } 131 132 size_t 133 uc_chunk_debug_get_srcpos(uc_chunk_t *chunk, size_t off) 134 { 135 uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets; 136 size_t i, inum = 0, lnum = 0; 137 138 if (!offsets->count) 139 return 0; 140 141 for (i = 0; i < offsets->count && inum < off; i++) { 142 lnum += OFFSETINFO_NUM_BYTES(offsets->entries[i]); 143 inum += OFFSETINFO_NUM_INSNS(offsets->entries[i]); 144 } 145 146 return lnum; 147 } 148 149 void 150 uc_chunk_debug_add_variable(uc_chunk_t *chunk, size_t from, size_t to, size_t slot, bool upval, uc_value_t *name) 151 { 152 uc_variables_t *variables = &chunk->debuginfo.variables; 153 uc_value_list_t *varnames = &chunk->debuginfo.varnames; 154 155 assert(slot <= ((size_t)-1 / 2)); 156 157 if (upval) 158 slot += (size_t)-1 / 2; 159 160 uc_vector_push(variables, { 161 .nameidx = uc_vallist_add(varnames, name), 162 .slot = slot, 163 .from = from, 164 .to = to 165 }); 166 } 167 168 uc_value_t * 169 uc_chunk_debug_get_variable(uc_chunk_t *chunk, size_t off, size_t slot, bool upval) 170 { 171 uc_variables_t *variables = &chunk->debuginfo.variables; 172 uc_value_list_t *varnames = &chunk->debuginfo.varnames; 173 uc_value_t *name = NULL; 174 size_t i; 175 176 assert(slot <= ((size_t)-1 / 2)); 177 178 if (upval) 179 slot += (size_t)-1 / 2; 180 181 for (i = 0; i < variables->count; i++) { 182 if (variables->entries[i].slot != slot || 183 variables->entries[i].from > off || 184 variables->entries[i].to < off) 185 continue; 186 187 name = uc_vallist_get(varnames, variables->entries[i].nameidx); 188 } 189 190 return name; 191 } 192
This page was automatically generated by LXR 0.3.1. • OpenWrt