mbed I/F binding for mruby

Dependents:   mruby_mbed_web mirb_mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers debug.c Source File

debug.c

00001 #include <string.h>
00002 #include "mruby.h"
00003 #include "mruby/irep.h"
00004 #include "mruby/debug.h"
00005 
00006 static mrb_irep_debug_info_file *
00007 get_file(mrb_irep_debug_info *info, uint32_t pc)
00008 {
00009   mrb_irep_debug_info_file **ret;
00010   int32_t count;
00011 
00012   if (pc >= info->pc_count) { return NULL; }
00013   /* get upper bound */
00014   ret = info->files;
00015   count =  info->flen;
00016   while (count > 0) {
00017     int32_t step = count / 2;
00018     mrb_irep_debug_info_file **it = ret + step;
00019     if (!(pc < (*it)->start_pos)) {
00020       ret = it + 1;
00021       count -= step + 1;
00022     } else { count = step; }
00023   }
00024 
00025   --ret;
00026 
00027   /* check returning file exists inside debug info */
00028   mrb_assert(info->files <= ret && ret < (info->files + info->flen));
00029   /* check pc is within the range of returning file */
00030   mrb_assert((*ret)->start_pos <= pc &&
00031              pc < (((ret + 1 - info->files) < info->flen)
00032                    ? (*(ret+1))->start_pos : info->pc_count));
00033 
00034   return *ret;
00035 }
00036 
00037 static mrb_debug_line_type
00038 select_line_type(const uint16_t *lines, size_t lines_len)
00039 {
00040   size_t line_count = 0;
00041   int prev_line = -1;
00042   size_t i;
00043   for (i = 0; i < lines_len; ++i) {
00044     if (lines[i] != prev_line) {
00045       ++line_count;
00046     }
00047   }
00048   return (sizeof(uint16_t) * lines_len) <= (sizeof(mrb_irep_debug_info_line) * line_count)
00049       ? mrb_debug_line_ary : mrb_debug_line_flat_map;
00050 }
00051 
00052 MRB_API char const*
00053 mrb_debug_get_filename(mrb_irep *irep, uint32_t pc)
00054 {
00055   if (irep && pc < irep->ilen) {
00056     mrb_irep_debug_info_file* f = NULL;
00057     if (!irep->debug_info) { return irep->filename; }
00058     else if ((f = get_file(irep->debug_info, pc))) {
00059       return f->filename;
00060     }
00061   }
00062   return NULL;
00063 }
00064 
00065 MRB_API int32_t
00066 mrb_debug_get_line(mrb_irep *irep, uint32_t pc)
00067 {
00068   if (irep && pc < irep->ilen) {
00069     mrb_irep_debug_info_file* f = NULL;
00070     if (!irep->debug_info) {
00071       return irep->lines? irep->lines[pc] : -1;
00072     }
00073     else if ((f = get_file(irep->debug_info, pc))) {
00074       switch (f->line_type) {
00075         case mrb_debug_line_ary:
00076           mrb_assert(f->start_pos <= pc && pc < (f->start_pos + f->line_entry_count));
00077           return f->lines.ary[pc - f->start_pos];
00078 
00079         case mrb_debug_line_flat_map: {
00080           /* get upper bound */
00081           mrb_irep_debug_info_line *ret = f->lines.flat_map;
00082           uint32_t count = f->line_entry_count;
00083           while (count > 0) {
00084             int32_t step = count / 2;
00085             mrb_irep_debug_info_line *it = ret + step;
00086             if (!(pc < it->start_pos)) {
00087               ret = it + 1;
00088               count -= step + 1;
00089             } else { count = step; }
00090           }
00091 
00092           --ret;
00093 
00094           /* check line entry pointer range */
00095           mrb_assert(f->lines.flat_map <= ret && ret < (f->lines.flat_map + f->line_entry_count));
00096           /* check pc range */
00097           mrb_assert(ret->start_pos <= pc &&
00098                      pc < (((uint32_t)(ret + 1 - f->lines.flat_map) < f->line_entry_count)
00099                            ? (ret+1)->start_pos : irep->debug_info->pc_count));
00100 
00101           return ret->line;
00102         }
00103       }
00104     }
00105   }
00106   return -1;
00107 }
00108 
00109 MRB_API mrb_irep_debug_info *
00110 mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep)
00111 {
00112   static const mrb_irep_debug_info initial = { 0, 0, NULL };
00113   mrb_irep_debug_info *ret;
00114 
00115   mrb_assert(!irep->debug_info);
00116   ret = (mrb_irep_debug_info *)mrb_malloc(mrb, sizeof(*ret));
00117   *ret = initial;
00118   irep->debug_info = ret;
00119   return ret;
00120 }
00121 
00122 MRB_API mrb_irep_debug_info_file *
00123 mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep,
00124                            uint32_t start_pos, uint32_t end_pos)
00125 {
00126   mrb_irep_debug_info *info;
00127   mrb_irep_debug_info_file *ret;
00128   uint32_t file_pc_count;
00129   size_t fn_len;
00130   mrb_int len;
00131   uint32_t i;
00132 
00133   if (!irep->debug_info) { return NULL; }
00134 
00135   mrb_assert(irep->filename);
00136   mrb_assert(irep->lines);
00137 
00138   info = irep->debug_info;
00139 
00140   if (info->flen > 0 && strcmp(irep->filename, info->files[info->flen - 1]->filename) == 0) {
00141     return NULL;
00142   }
00143 
00144   ret = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*ret));
00145   info->files =
00146       (mrb_irep_debug_info_file**)(
00147           info->files
00148           ? mrb_realloc(mrb, info->files, sizeof(mrb_irep_debug_info_file*) * (info->flen + 1))
00149           : mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file*)));
00150   info->files[info->flen++] = ret;
00151 
00152   file_pc_count = end_pos - start_pos;
00153 
00154   ret->start_pos = start_pos;
00155   info->pc_count = end_pos;
00156 
00157   fn_len = strlen(irep->filename);
00158   ret->filename_sym = mrb_intern(mrb, irep->filename, fn_len);
00159   len = 0;
00160   ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len);
00161 
00162   ret->line_type = select_line_type(irep->lines + start_pos, end_pos - start_pos);
00163   ret->lines.ptr = NULL;
00164 
00165   switch (ret->line_type) {
00166     case mrb_debug_line_ary:
00167       ret->line_entry_count = file_pc_count;
00168       ret->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count);
00169       for (i = 0; i < file_pc_count; ++i) {
00170         ret->lines.ary[i] = irep->lines[start_pos + i];
00171       }
00172       break;
00173 
00174     case mrb_debug_line_flat_map: {
00175       uint16_t prev_line = 0;
00176       mrb_irep_debug_info_line m;
00177       ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1);
00178       ret->line_entry_count = 0;
00179       for (i = 0; i < file_pc_count; ++i) {
00180         if (irep->lines[start_pos + i] == prev_line) { continue; }
00181 
00182         ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc(
00183             mrb, ret->lines.flat_map,
00184             sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1));
00185         m.start_pos = start_pos + i;
00186         m.line = irep->lines[start_pos + i];
00187         ret->lines.flat_map[ret->line_entry_count] = m;
00188 
00189         /* update */
00190         ++ret->line_entry_count;
00191         prev_line = irep->lines[start_pos + i];
00192       }
00193     } break;
00194 
00195     default: mrb_assert(0); break;
00196   }
00197 
00198   return ret;
00199 }
00200 
00201 MRB_API void
00202 mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d)
00203 {
00204   uint32_t i;
00205 
00206   if (!d) { return; }
00207 
00208   for (i = 0; i < d->flen; ++i) {
00209     mrb_assert(d->files[i]);
00210     mrb_free(mrb, d->files[i]->lines.ptr);
00211     mrb_free(mrb, d->files[i]);
00212   }
00213   mrb_free(mrb, d->files);
00214   mrb_free(mrb, d);
00215 }
00216