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/internal/chunk.h" 20 21 #define OFFSETINFO_MAX_BYTES 127 22 #define OFFSETINFO_MAX_INSNS 127 23 #define OFFSETINFO_NUM_BYTES(o) ((o)->bytes & OFFSETINFO_MAX_BYTES) 24 #define OFFSETINFO_NUM_INSNS(o) ((o)->insns & OFFSETINFO_MAX_INSNS) 25 #define OFFSETINFO_IS_END(o) ((o)->insns & 0x80) 26 27 28 void 29 uc_chunk_init(uc_chunk_t *chunk) 30 { 31 chunk->count = 0; 32 chunk->entries = NULL; 33 34 chunk->ehranges.count = 0; 35 chunk->ehranges.entries = NULL; 36 37 chunk->debuginfo.offsets.count = 0; 38 chunk->debuginfo.offsets.entries = NULL; 39 40 chunk->debuginfo.variables.count = 0; 41 chunk->debuginfo.variables.entries = NULL; 42 43 uc_vallist_init(&chunk->debuginfo.varnames); 44 } 45 46 void 47 uc_chunk_free(uc_chunk_t *chunk) 48 { 49 uc_vector_clear(chunk); 50 uc_vector_clear(&chunk->ehranges); 51 52 uc_vector_clear(&chunk->debuginfo.offsets); 53 uc_vector_clear(&chunk->debuginfo.variables); 54 uc_vallist_free(&chunk->debuginfo.varnames); 55 56 uc_chunk_init(chunk); 57 } 58 59 size_t 60 uc_chunk_add(uc_chunk_t *chunk, uint8_t byte, size_t offset) 61 { 62 uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets; 63 size_t i; 64 65 uc_vector_push(chunk, byte); 66 67 /* Offset info is encoded in byte pairs, the first byte specifies the number 68 * of source text bytes to advance since the last entry and the second byte 69 * specifies the amount of instructions belonging to the source text offset. 70 * Byte and instruction count values are limited to 7 bits (0x00..0x7f), 71 * the most significant bit in each byte is reserved as flag value; if the 72 * bit is set in the first byte, it signals the begin of a logical statement 73 * while a set bit in the second byte denotes the end of the statement. */ 74 if (offset > 0 || offsets->count == 0) { 75 /* If this offset is farther than 127 (2 ** 7 - 1) bytes apart from 76 * the last one, we need to emit intermediate "jump" bytes with zero 77 * instructions each */ 78 for (i = offset; i > OFFSETINFO_MAX_BYTES; i -= OFFSETINFO_MAX_BYTES) { 79 /* advance by 127 bytes */ 80 uc_vector_push(offsets, { OFFSETINFO_MAX_BYTES, 0 }); 81 } 82 83 /* advance by `i` bytes, count one instruction */ 84 uc_vector_push(offsets, { i, 1 }); 85 } 86 87 /* update instruction count at current offset entry */ 88 else { 89 uc_offset_t *o = uc_vector_last(offsets); 90 91 /* since we encode the per-offset instruction count in seven bits, we 92 * can only count up to 127 instructions. If we exceed that limit, 93 * emit another offset entry with the byte offset set to zero */ 94 if (OFFSETINFO_NUM_INSNS(o) >= OFFSETINFO_MAX_INSNS) { 95 /* advance by 0 bytes, count one instruction */ 96 uc_vector_push(offsets, { 0, 1 }); 97 } 98 else { 99 o->insns++; 100 } 101 } 102 103 return chunk->count - 1; 104 } 105 106 void 107 uc_chunk_stmt_start(uc_chunk_t *chunk, size_t offset) 108 { 109 uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets; 110 size_t i; 111 112 for (i = offset; i > OFFSETINFO_MAX_BYTES; i -= OFFSETINFO_MAX_BYTES) { 113 /* advance by 127 bytes */ 114 uc_vector_push(offsets, { OFFSETINFO_MAX_BYTES, 0 }); 115 } 116 117 /* advance by `i` bytes, set start of statement flag */ 118 uc_vector_push(offsets, { i | 0x80, 0 }); 119 } 120 121 void 122 uc_chunk_stmt_end(uc_chunk_t *chunk, size_t offset) 123 { 124 uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets; 125 uc_offset_t *o = offsets->count ? uc_vector_last(offsets) : NULL; 126 size_t i; 127 128 for (i = offset; i > OFFSETINFO_MAX_BYTES; i -= OFFSETINFO_MAX_BYTES) { 129 /* advance by 127 bytes */ 130 uc_vector_push(offsets, { OFFSETINFO_MAX_BYTES, 0 }); 131 } 132 133 if (i > 0 || o == NULL || OFFSETINFO_IS_END(o)) { 134 /* advance by `i` bytes, set start of statement flag */ 135 uc_vector_push(offsets, { i, 0x80 }); 136 } 137 else { 138 /* set end flag on last offset entry */ 139 o->insns |= 0x80; 140 } 141 } 142 143 void 144 uc_chunk_pop(uc_chunk_t *chunk) 145 { 146 assert(chunk->count > 0); 147 148 chunk->count--; 149 150 for (size_t i = chunk->debuginfo.offsets.count; i > 0; i--) { 151 uc_offset_t *o = &chunk->debuginfo.offsets.entries[i - 1]; 152 153 if (o->insns & 127) { 154 o->insns = ((o->insns & 127) - 1) | (o->insns & 128); 155 break; 156 } 157 } 158 } 159 160 size_t 161 uc_chunk_debug_get_srcpos(uc_chunk_t *chunk, size_t off) 162 { 163 uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets; 164 size_t i, inum = 0, bnum = 0; 165 166 if (!offsets->count) 167 return 0; 168 169 for (i = 0; i < offsets->count && inum < off; i++) { 170 bnum += OFFSETINFO_NUM_BYTES(&offsets->entries[i]); 171 inum += OFFSETINFO_NUM_INSNS(&offsets->entries[i]); 172 } 173 174 return bnum; 175 } 176 177 void 178 uc_chunk_debug_add_variable(uc_chunk_t *chunk, size_t from, size_t to, size_t slot, bool upval, uc_value_t *name) 179 { 180 uc_variables_t *variables = &chunk->debuginfo.variables; 181 uc_value_list_t *varnames = &chunk->debuginfo.varnames; 182 183 assert(slot <= ((size_t)-1 / 2)); 184 185 if (upval) 186 slot += (size_t)-1 / 2; 187 188 uc_vector_push(variables, { 189 .nameidx = uc_vallist_add(varnames, name), 190 .slot = slot, 191 .from = from, 192 .to = to 193 }); 194 } 195 196 uc_value_t * 197 uc_chunk_debug_get_variable(uc_chunk_t *chunk, size_t off, size_t slot, bool upval) 198 { 199 uc_variables_t *variables = &chunk->debuginfo.variables; 200 uc_value_list_t *varnames = &chunk->debuginfo.varnames; 201 uc_value_t *name = NULL; 202 size_t i; 203 204 assert(slot <= ((size_t)-1 / 2)); 205 206 if (upval) 207 slot += (size_t)-1 / 2; 208 209 for (i = 0; i < variables->count; i++) { 210 if (variables->entries[i].slot != slot || 211 variables->entries[i].from > off || 212 variables->entries[i].to < off) 213 continue; 214 215 name = uc_vallist_get(varnames, variables->entries[i].nameidx); 216 } 217 218 return name; 219 } 220
This page was automatically generated by LXR 0.3.1. • OpenWrt