Line | Count | Source (jump to first uncovered line) |
1 | | #include <string.h> |
2 | | #include <mruby.h> |
3 | | #include <mruby/irep.h> |
4 | | #include <mruby/debug.h> |
5 | | |
6 | | static mrb_irep_debug_info_file* |
7 | | get_file(mrb_irep_debug_info *info, uint32_t pc) |
8 | 0 | { |
9 | 0 | mrb_irep_debug_info_file **ret; |
10 | 0 | int32_t count; |
11 | |
|
12 | 0 | if (pc >= info->pc_count) { return NULL; } |
13 | | /* get upper bound */ |
14 | 0 | ret = info->files; |
15 | 0 | count = info->flen; |
16 | 0 | while (count > 0) { |
17 | 0 | int32_t step = count / 2; |
18 | 0 | mrb_irep_debug_info_file **it = ret + step; |
19 | 0 | if (!(pc < (*it)->start_pos)) { |
20 | 0 | ret = it + 1; |
21 | 0 | count -= step + 1; |
22 | 0 | } |
23 | 0 | else { count = step; } |
24 | 0 | } |
25 | |
|
26 | 0 | --ret; |
27 | | |
28 | | /* check returning file exists inside debug info */ |
29 | 0 | mrb_assert(info->files <= ret && ret < (info->files + info->flen)); |
30 | | /* check pc is within the range of returning file */ |
31 | 0 | mrb_assert((*ret)->start_pos <= pc && |
32 | 0 | pc < (((ret + 1 - info->files) < info->flen) |
33 | 0 | ? (*(ret+1))->start_pos : info->pc_count)); |
34 | |
|
35 | 0 | return *ret; |
36 | 0 | } |
37 | | |
38 | | size_t |
39 | | mrb_packed_int_len(uint32_t num) |
40 | 67.7k | { |
41 | 67.7k | size_t llen = 0; |
42 | | |
43 | 67.7k | do { |
44 | 67.7k | llen++; |
45 | 67.7k | } while (num >>= 7); |
46 | 67.7k | return llen; |
47 | 67.7k | } |
48 | | |
49 | | size_t |
50 | | mrb_packed_int_encode(uint32_t num, uint8_t *p) |
51 | 67.7k | { |
52 | 67.7k | size_t llen = 0; |
53 | | |
54 | 67.7k | do { |
55 | 67.7k | uint8_t byte = num & 0x7f; |
56 | 67.7k | num >>= 7; |
57 | 67.7k | if (num != 0) byte |= 0x80; |
58 | 67.7k | *p++ = byte; |
59 | 67.7k | llen++; |
60 | 67.7k | } while (num != 0); |
61 | | |
62 | 67.7k | return llen; |
63 | 67.7k | } |
64 | | |
65 | | uint32_t |
66 | | mrb_packed_int_decode(const uint8_t *p, const uint8_t **newpos) |
67 | 16.8M | { |
68 | 16.8M | size_t i = 0, shift = 0; |
69 | 16.8M | uint32_t n = 0; |
70 | | |
71 | 16.8M | do { |
72 | 16.8M | n |= ((uint32_t)(p[i] & 0x7f)) << shift; |
73 | 16.8M | i++; |
74 | 16.8M | shift += 7; |
75 | 16.8M | } while (shift < sizeof(uint32_t) * 8 && (p[i - 1] & 0x80)); |
76 | 16.8M | if (newpos) *newpos = p + i; |
77 | 16.8M | return n; |
78 | 16.8M | } |
79 | | |
80 | | static char const* |
81 | | debug_get_filename(mrb_state *mrb, mrb_irep_debug_info_file* f) |
82 | 0 | { |
83 | 0 | if (f == NULL) return NULL; |
84 | 0 | return mrb_sym_name_len(mrb, f->filename_sym, NULL); |
85 | 0 | } |
86 | | |
87 | | static int32_t |
88 | | debug_get_line(mrb_state *mrb, mrb_irep_debug_info_file* f, uint32_t pc) |
89 | 0 | { |
90 | 0 | if (f == NULL) return -1; |
91 | 0 | switch (f->line_type) { |
92 | 0 | case mrb_debug_line_ary: |
93 | 0 | case mrb_debug_line_flat_map: |
94 | 0 | default: |
95 | 0 | break; |
96 | | |
97 | 0 | case mrb_debug_line_packed_map: |
98 | 0 | { |
99 | 0 | const uint8_t *p = f->lines.packed_map; |
100 | 0 | const uint8_t *pend = p + f->line_entry_count; |
101 | 0 | uint32_t pos = 0, line = 0, line_diff; |
102 | 0 | while (p < pend) { |
103 | 0 | pos += mrb_packed_int_decode(p, &p); |
104 | 0 | line_diff = mrb_packed_int_decode(p, &p); |
105 | 0 | if (pc < pos) break; |
106 | 0 | line += line_diff; |
107 | 0 | } |
108 | 0 | return line; |
109 | 0 | } |
110 | 0 | } |
111 | 0 | return -1; |
112 | 0 | } |
113 | | |
114 | | MRB_API char const* |
115 | | mrb_debug_get_filename(mrb_state *mrb, const mrb_irep *irep, uint32_t pc) |
116 | 0 | { |
117 | 0 | if (irep && pc < irep->ilen) { |
118 | 0 | if (!irep->debug_info) return NULL; |
119 | 0 | return debug_get_filename(mrb, get_file(irep->debug_info, pc)); |
120 | 0 | } |
121 | 0 | return NULL; |
122 | 0 | } |
123 | | |
124 | | MRB_API int32_t |
125 | | mrb_debug_get_line(mrb_state *mrb, const mrb_irep *irep, uint32_t pc) |
126 | 0 | { |
127 | 0 | if (irep && pc < irep->ilen) { |
128 | 0 | if (!irep->debug_info) return -1; |
129 | 0 | return debug_get_line(mrb, get_file(irep->debug_info, pc), pc); |
130 | 0 | } |
131 | 0 | return -1; |
132 | 0 | } |
133 | | |
134 | | MRB_API mrb_bool |
135 | | mrb_debug_get_position(mrb_state *mrb, const mrb_irep *irep, uint32_t pc, int32_t *lp, const char **fp) |
136 | 0 | { |
137 | 0 | if (irep && pc < irep->ilen && irep->debug_info) { |
138 | 0 | mrb_irep_debug_info_file *f = get_file(irep->debug_info, pc); |
139 | 0 | *lp = debug_get_line(mrb, f, pc); |
140 | 0 | if (*lp > 0) { |
141 | 0 | *fp = debug_get_filename(mrb, f); |
142 | 0 | if (*fp) return TRUE; |
143 | 0 | } |
144 | 0 | } |
145 | 0 | *lp = -1; *fp = NULL; |
146 | 0 | return FALSE; |
147 | 0 | } |
148 | | |
149 | | MRB_API mrb_irep_debug_info* |
150 | | mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep) |
151 | 0 | { |
152 | 0 | static const mrb_irep_debug_info initial = { 0, 0, NULL }; |
153 | 0 | mrb_irep_debug_info *ret; |
154 | |
|
155 | 0 | mrb_assert(!irep->debug_info); |
156 | 0 | ret = (mrb_irep_debug_info*)mrb_malloc(mrb, sizeof(*ret)); |
157 | 0 | *ret = initial; |
158 | 0 | irep->debug_info = ret; |
159 | 0 | return ret; |
160 | 0 | } |
161 | | |
162 | | MRB_API mrb_irep_debug_info_file* |
163 | | mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, |
164 | | const char *filename, uint16_t *lines, |
165 | | uint32_t start_pos, uint32_t end_pos) |
166 | 0 | { |
167 | 0 | mrb_irep_debug_info_file *f; |
168 | 0 | uint32_t file_pc_count; |
169 | 0 | size_t fn_len; |
170 | 0 | uint32_t i; |
171 | |
|
172 | 0 | if (!d) return NULL; |
173 | 0 | if (start_pos == end_pos) return NULL; |
174 | | |
175 | 0 | mrb_assert(filename); |
176 | 0 | mrb_assert(lines); |
177 | |
|
178 | 0 | if (d->flen > 0) { |
179 | 0 | const char *fn = mrb_sym_name_len(mrb, d->files[d->flen - 1]->filename_sym, NULL); |
180 | 0 | if (strcmp(filename, fn) == 0) |
181 | 0 | return NULL; |
182 | 0 | } |
183 | | |
184 | 0 | f = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(*f)); |
185 | 0 | d->files = (mrb_irep_debug_info_file**)mrb_realloc(mrb, d->files, sizeof(mrb_irep_debug_info_file*) * (d->flen + 1)); |
186 | 0 | d->files[d->flen++] = f; |
187 | |
|
188 | 0 | file_pc_count = end_pos - start_pos; |
189 | |
|
190 | 0 | f->start_pos = start_pos; |
191 | 0 | d->pc_count = end_pos; |
192 | |
|
193 | 0 | fn_len = strlen(filename); |
194 | 0 | f->filename_sym = mrb_intern(mrb, filename, fn_len); |
195 | 0 | f->line_type = mrb_debug_line_packed_map; |
196 | 0 | f->lines.ptr = NULL; |
197 | |
|
198 | 0 | uint16_t prev_line = 0; |
199 | 0 | uint32_t prev_pc = 0; |
200 | 0 | size_t packed_size = 0; |
201 | 0 | uint8_t *p; |
202 | |
|
203 | 0 | for (i = 0; i < file_pc_count; i++) { |
204 | 0 | if (lines[start_pos + i] == prev_line) continue; |
205 | 0 | packed_size += mrb_packed_int_len(start_pos+i-prev_pc); |
206 | 0 | prev_pc = start_pos+i; |
207 | 0 | packed_size += mrb_packed_int_len(lines[start_pos+i]-prev_line); |
208 | 0 | prev_line = lines[start_pos + i]; |
209 | 0 | } |
210 | 0 | f->lines.packed_map = p = (uint8_t*)mrb_malloc(mrb, packed_size); |
211 | 0 | prev_line = 0; prev_pc = 0; |
212 | 0 | for (i = 0; i < file_pc_count; i++) { |
213 | 0 | if (lines[start_pos + i] == prev_line) continue; |
214 | 0 | p += mrb_packed_int_encode(start_pos+i-prev_pc, p); |
215 | 0 | prev_pc = start_pos + i; |
216 | 0 | p += mrb_packed_int_encode(lines[start_pos + i]-prev_line, p); |
217 | 0 | prev_line = lines[start_pos + i]; |
218 | 0 | } |
219 | 0 | f->line_entry_count = (uint32_t)packed_size; |
220 | |
|
221 | 0 | return f; |
222 | 0 | } |
223 | | |
224 | | MRB_API void |
225 | | mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d) |
226 | 932 | { |
227 | 932 | uint32_t i; |
228 | | |
229 | 932 | if (!d) { return; } |
230 | | |
231 | 0 | if (d->files) { |
232 | 0 | for (i = 0; i < d->flen; i++) { |
233 | 0 | if (d->files[i]) { |
234 | 0 | mrb_free(mrb, d->files[i]->lines.ptr); |
235 | 0 | mrb_free(mrb, d->files[i]); |
236 | 0 | } |
237 | 0 | } |
238 | 0 | mrb_free(mrb, d->files); |
239 | 0 | } |
240 | 0 | mrb_free(mrb, d); |
241 | 0 | } |