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