• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/chunk.c

  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