• 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/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