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_grow(chunk); 71 72 chunk->entries[chunk->count] = byte; 73 74 /* offset info is encoded in bytes, for each byte, the first three bits 75 * specify the number of source text bytes to advance since the last entry 76 * and the remaining five bits specify the amount of instructions belonging 77 * to any given source text offset */ 78 if (offset > 0 || offsets->count == 0) { 79 /* if this offset is farther than seven (2 ** 3 - 1) bytes apart from 80 * the last one, we need to emit intermediate "jump" bytes with zero 81 * instructions each */ 82 for (i = offset; i > OFFSETINFO_MAX_BYTES; i -= OFFSETINFO_MAX_BYTES) { 83 /* advance by 7 bytes */ 84 uc_vector_grow(offsets); 85 offsets->entries[offsets->count++] = OFFSETINFO_ENCODE(OFFSETINFO_MAX_BYTES, 0); 86 } 87 88 /* advance by `i` bytes, count one instruction */ 89 uc_vector_grow(offsets); 90 offsets->entries[offsets->count++] = OFFSETINFO_ENCODE(i, 1); 91 } 92 93 /* update instruction count at current offset entry */ 94 else { 95 /* since we encode the per-offset instruction count in five bits, we 96 * can only count up to 31 instructions. If we exceed that limit, 97 * emit another offset entry with the initial three bits set to zero */ 98 if (OFFSETINFO_NUM_INSNS(offsets->entries[offsets->count - 1]) >= OFFSETINFO_MAX_INSNS) { 99 /* advance by 0 bytes, count one instruction */ 100 uc_vector_grow(offsets); 101 offsets->entries[offsets->count++] = OFFSETINFO_ENCODE(0, 1); 102 } 103 else { 104 offsets->entries[offsets->count - 1] = OFFSETINFO_ENCODE( 105 OFFSETINFO_NUM_BYTES(offsets->entries[offsets->count - 1]), 106 OFFSETINFO_NUM_INSNS(offsets->entries[offsets->count - 1]) + 1 107 ); 108 } 109 } 110 111 return chunk->count++; 112 } 113 114 void 115 uc_chunk_pop(uc_chunk_t *chunk) 116 { 117 uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets; 118 int n_insns; 119 120 assert(chunk->count > 0); 121 122 chunk->count--; 123 124 n_insns = OFFSETINFO_NUM_INSNS(offsets->entries[offsets->count - 1]); 125 126 if (n_insns > 0) { 127 offsets->entries[offsets->count - 1] = OFFSETINFO_ENCODE( 128 OFFSETINFO_NUM_BYTES(offsets->entries[offsets->count - 1]), 129 n_insns - 1 130 ); 131 } 132 else { 133 offsets->count--; 134 } 135 } 136 137 size_t 138 uc_chunk_debug_get_srcpos(uc_chunk_t *chunk, size_t off) 139 { 140 uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets; 141 size_t i, inum = 0, lnum = 0; 142 143 if (!offsets->count) 144 return 0; 145 146 for (i = 0; i < offsets->count && inum < off; i++) { 147 lnum += OFFSETINFO_NUM_BYTES(offsets->entries[i]); 148 inum += OFFSETINFO_NUM_INSNS(offsets->entries[i]); 149 } 150 151 return lnum; 152 } 153 154 void 155 uc_chunk_debug_add_variable(uc_chunk_t *chunk, size_t from, size_t to, size_t slot, bool upval, uc_value_t *name) 156 { 157 uc_variables_t *variables = &chunk->debuginfo.variables; 158 uc_value_list_t *varnames = &chunk->debuginfo.varnames; 159 160 assert(slot <= ((size_t)-1 / 2)); 161 162 if (upval) 163 slot += (size_t)-1 / 2; 164 165 uc_vector_grow(variables); 166 167 variables->entries[variables->count].nameidx = uc_vallist_add(varnames, name); 168 variables->entries[variables->count].slot = slot; 169 variables->entries[variables->count].from = from; 170 variables->entries[variables->count].to = to; 171 172 variables->count++; 173 } 174 175 uc_value_t * 176 uc_chunk_debug_get_variable(uc_chunk_t *chunk, size_t off, size_t slot, bool upval) 177 { 178 uc_variables_t *variables = &chunk->debuginfo.variables; 179 uc_value_list_t *varnames = &chunk->debuginfo.varnames; 180 uc_value_t *name = NULL; 181 size_t i; 182 183 assert(slot <= ((size_t)-1 / 2)); 184 185 if (upval) 186 slot += (size_t)-1 / 2; 187 188 for (i = 0; i < variables->count; i++) { 189 if (variables->entries[i].slot != slot || 190 variables->entries[i].from > off || 191 variables->entries[i].to < off) 192 continue; 193 194 name = uc_vallist_get(varnames, variables->entries[i].nameidx); 195 } 196 197 return name; 198 } 199
This page was automatically generated by LXR 0.3.1. • OpenWrt