static void parse_module(module_info *info, const char *pathname) { char *module_image; char *ptr; size_t len; size_t pos; dbg1_error_msg("parse_module('%s')", pathname); /* Read (possibly compressed) module */ len = 64 * 1024 * 1024; /* 64 Mb at most */ module_image = xmalloc_open_zipped_read_close(pathname, &len); //TODO: optimize redundant module body reads /* "alias1 symbol:sym1 alias2 symbol:sym2" */ reset_stringbuf(); pos = 0; while (1) { ptr = find_keyword(module_image + pos, len - pos, "alias="); if (!ptr) { ptr = find_keyword(module_image + pos, len - pos, "__ksymtab_"); if (!ptr) break; /* DOCME: __ksymtab_gpl and __ksymtab_strings occur * in many modules. What do they mean? */ if (strcmp(ptr, "gpl") == 0 || strcmp(ptr, "strings") == 0) goto skip; dbg2_error_msg("alias:'symbol:%s'", ptr); append("symbol:"); } else { dbg2_error_msg("alias:'%s'", ptr); } append(ptr); appendc(' '); skip: pos = (ptr - module_image); } bksp(); /* remove last ' ' */ appendc('\0'); info->aliases = copy_stringbuf(); /* "dependency1 depandency2" */ reset_stringbuf(); ptr = find_keyword(module_image, len, "depends="); if (ptr && *ptr) { replace(ptr, ',', ' '); replace(ptr, '-', '_'); dbg2_error_msg("dep:'%s'", ptr); append(ptr); } appendc('\0'); info->deps = copy_stringbuf(); free(module_image); }
int serialize_kvp_as_json(lua_sandbox* lsb, serialization_data* data, int isHash) { static const char array_start = '[', array_end = ']'; static const char hash_start = '{', hash_end = '}'; int kindex = -2, vindex = -1, result = 0; if (ignore_value_type_json(lsb, vindex)) return 0; if (ignore_key(lsb, kindex)) return 0; if (isHash) { if (serialize_data_as_json(lsb, kindex, &lsb->output)) return 1; if (appendc(&lsb->output, ':')) return 1; } if (lua_type(lsb->lua, vindex) == LUA_TTABLE) { const void* ptr = lua_topointer(lsb->lua, vindex); table_ref* seen = find_table_ref(&data->tables, ptr); if (seen == NULL) { seen = add_table_ref(&data->tables, ptr, 0); if (seen != NULL) { char start, end; lua_rawgeti(lsb->lua, vindex, 1); int hash = lua_isnil(lsb->lua, -1); lua_pop(lsb->lua, 1); // remove the test value if (hash) { start = hash_start; end = hash_end; } else { start = array_start; end = array_end; } if (appendc(&lsb->output, start)) return 1; if (serialize_table_as_json(lsb, data, hash)) return 1; if (appendc(&lsb->output, end)) return 1; } else { snprintf(lsb->error_message, LSB_ERROR_SIZE, "serialize table out of memory"); return 1; } } else { snprintf(lsb->error_message, LSB_ERROR_SIZE, "table contains an internal or circular reference"); return 1; } } else { result = serialize_data_as_json(lsb, vindex, &lsb->output); } return result; }
int serialize_table_as_json(lua_sandbox* lsb, serialization_data* data, int isHash) { int result = 0; lua_checkstack(lsb->lua, 2); lua_pushnil(lsb->lua); int had_output = 0; size_t start = 0; while (result == 0 && lua_next(lsb->lua, -2) != 0) { if (had_output) { if (appendc(&lsb->output, ',')) return 1; } start = lsb->output.pos; result = serialize_kvp_as_json(lsb, data, isHash); lua_pop(lsb->lua, 1); // Remove the value leaving the key on top for // the next interation. if (start != lsb->output.pos) { had_output = 1; } else { had_output = 0; } } if (start != 0 && had_output == 0) { // remove the trailing comma size_t reset_pos = start - 1; if (lsb->output.data[reset_pos] == ',') { lsb->output.data[reset_pos] = 0; lsb->output.pos = reset_pos; } } return result; }
/* * decodes an escape code. These are * shared between strings and characters. * Unknown escape codes are ignored. */ static int decode(char **buf, size_t *len, size_t *sz) { char c, c1, c2; int32_t v; c = next(); /* we've already seen the '\' */ switch (c) { case 'u': v = unichar(); appendc(buf, len, sz, v); return v; case 'x': /* arbitrary hex */ c1 = next(); if (!isxdigit(c1)) lfatal(curloc, "expected hex digit, got %c", c1); c2 = next(); if (!isxdigit(c2)) lfatal(curloc, "expected hex digit, got %c", c1); v = 16*hexval(c1) + hexval(c2); break; case 'n': v = '\n'; break; case 'r': v = '\r'; break; case 't': v = '\t'; break; case 'b': v = '\b'; break; case '"': v = '\"'; break; case '\'': v = '\''; break; case 'v': v = '\v'; break; case '\\': v = '\\'; break; case '0': v = '\0'; break; default: lfatal(curloc, "unknown escape code \\%c", c); } append(buf, len, sz, v); return v; }
char * macro_stringify (const char *str) { struct macro_buffer buffer; int len = strlen (str); init_buffer (&buffer, len); stringify (&buffer, str, len); appendc (&buffer, '\0'); return free_buffer_return_text (&buffer); }
char * macro_expand_next (char **lexptr, macro_lookup_ftype *lookup_func, void *lookup_baton) { struct macro_buffer src, dest, tok; struct cleanup *back_to; /* Set up SRC to refer to the input text, pointed to by *lexptr. */ init_shared_buffer (&src, *lexptr, strlen (*lexptr)); /* Set up DEST to receive the expansion, if there is one. */ init_buffer (&dest, 0); dest.last_token = 0; back_to = make_cleanup (cleanup_macro_buffer, &dest); /* Get the text's first preprocessing token. */ if (! get_token (&tok, &src)) { do_cleanups (back_to); return 0; } /* If it's a macro invocation, expand it. */ if (maybe_expand (&dest, &tok, &src, 0, lookup_func, lookup_baton)) { /* It was a macro invocation! Package up the expansion as a null-terminated string and return it. Set *lexptr to the start of the next token in the input. */ appendc (&dest, '\0'); discard_cleanups (back_to); *lexptr = src.text; return dest.text; } else { /* It wasn't a macro invocation. */ do_cleanups (back_to); return 0; } }
char * macro_expand (const char *source, macro_lookup_ftype *lookup_func, void *lookup_func_baton) { struct macro_buffer src, dest; struct cleanup *back_to; init_shared_buffer (&src, (char *) source, strlen (source)); init_buffer (&dest, 0); dest.last_token = 0; back_to = make_cleanup (cleanup_macro_buffer, &dest); scan (&dest, &src, 0, lookup_func, lookup_func_baton); appendc (&dest, '\0'); discard_cleanups (back_to); return dest.text; }
static void stringify (struct macro_buffer *dest, const char *arg, int len) { /* Trim initial whitespace from ARG. */ while (len > 0 && macro_is_whitespace (*arg)) { ++arg; --len; } /* Trim trailing whitespace from ARG. */ while (len > 0 && macro_is_whitespace (arg[len - 1])) --len; /* Insert the string. */ appendc (dest, '"'); while (len > 0) { /* We could try to handle strange cases here, like control characters, but there doesn't seem to be much point. */ if (macro_is_whitespace (*arg)) { /* Replace a sequence of whitespace with a single space. */ appendc (dest, ' '); while (len > 1 && macro_is_whitespace (arg[1])) { ++arg; --len; } } else if (*arg == '\\' || *arg == '"') { appendc (dest, '\\'); appendc (dest, *arg); } else appendc (dest, *arg); ++arg; --len; } appendc (dest, '"'); dest->last_token = dest->len; }
static void parse_module(module_info *info, const char *pathname) { char *module_image; char *ptr; size_t len; size_t pos; dbg1_error_msg("parse_module('%s')", pathname); /* Read (possibly compressed) module */ len = 64 * 1024 * 1024; /* 64 Mb at most */ module_image = xmalloc_open_zipped_read_close(pathname, &len); /* module_image == NULL is ok here, find_keyword handles it */ //TODO: optimize redundant module body reads /* "alias1 symbol:sym1 alias2 symbol:sym2" */ reset_stringbuf(); pos = 0; while (1) { unsigned start = stringbuf_idx; ptr = find_keyword(module_image + pos, len - pos, "alias="); if (!ptr) { ptr = find_keyword(module_image + pos, len - pos, "__ksymtab_"); if (!ptr) break; /* DOCME: __ksymtab_gpl and __ksymtab_strings occur * in many modules. What do they mean? */ if (strcmp(ptr, "gpl") == 0 || strcmp(ptr, "strings") == 0) goto skip; dbg2_error_msg("alias:'symbol:%s'", ptr); append("symbol:"); } else { dbg2_error_msg("alias:'%s'", ptr); } append(ptr); appendc(' '); /* * Don't add redundant aliases, such as: * libcrc32c.ko symbol:crc32c symbol:crc32c */ if (start) { /* "if we aren't the first alias" */ char *found, *last; stringbuf[stringbuf_idx] = '\0'; last = stringbuf + start; /* * String at last-1 is " symbol:crc32c " * (with both leading and trailing spaces). */ if (strncmp(stringbuf, last, stringbuf_idx - start) == 0) /* First alias matches us */ found = stringbuf; else /* Does any other alias match? */ found = strstr(stringbuf, last-1); if (found < last-1) { /* There is absolutely the same string before us */ dbg2_error_msg("redundant:'%s'", last); stringbuf_idx = start; goto skip; } } skip: pos = (ptr - module_image); } bksp(); /* remove last ' ' */ info->aliases = copy_stringbuf(); replace(info->aliases, '-', '_'); /* "dependency1 depandency2" */ reset_stringbuf(); ptr = find_keyword(module_image, len, "depends="); if (ptr && *ptr) { replace(ptr, ',', ' '); replace(ptr, '-', '_'); dbg2_error_msg("dep:'%s'", ptr); append(ptr); } info->deps = copy_stringbuf(); free(module_image); }
/* Append the macro buffer SRC to the end of DEST, and ensure that doing so doesn't splice the token at the end of SRC with the token at the beginning of DEST. SRC and DEST must have their last_token fields set. Upon return, DEST's last_token field is set correctly. For example: If DEST is "(" and SRC is "y", then we can return with DEST set to "(y" --- we've simply appended the two buffers. However, if DEST is "x" and SRC is "y", then we must not return with DEST set to "xy" --- that would splice the two tokens "x" and "y" together to make a single token "xy". However, it would be fine to return with DEST set to "x y". Similarly, "<" and "<" must yield "< <", not "<<", etc. */ static void append_tokens_without_splicing (struct macro_buffer *dest, struct macro_buffer *src) { int original_dest_len = dest->len; struct macro_buffer dest_tail, new_token; gdb_assert (src->last_token != -1); gdb_assert (dest->last_token != -1); /* First, just try appending the two, and call get_token to see if we got a splice. */ appendmem (dest, src->text, src->len); /* If DEST originally had no token abutting its end, then we can't have spliced anything, so we're done. */ if (dest->last_token == original_dest_len) { dest->last_token = original_dest_len + src->last_token; return; } /* Set DEST_TAIL to point to the last token in DEST, followed by all the stuff we just appended. */ init_shared_buffer (&dest_tail, dest->text + dest->last_token, dest->len - dest->last_token); /* Re-parse DEST's last token. We know that DEST used to contain at least one token, so if it doesn't contain any after the append, then we must have spliced "/" and "*" or "/" and "/" to make a comment start. (Just for the record, I got this right the first time. This is not a bug fix.) */ if (get_token (&new_token, &dest_tail) && (new_token.text + new_token.len == dest->text + original_dest_len)) { /* No splice, so we're done. */ dest->last_token = original_dest_len + src->last_token; return; } /* Okay, a simple append caused a splice. Let's chop dest back to its original length and try again, but separate the texts with a space. */ dest->len = original_dest_len; appendc (dest, ' '); appendmem (dest, src->text, src->len); init_shared_buffer (&dest_tail, dest->text + dest->last_token, dest->len - dest->last_token); /* Try to re-parse DEST's last token, as above. */ if (get_token (&new_token, &dest_tail) && (new_token.text + new_token.len == dest->text + original_dest_len)) { /* No splice, so we're done. */ dest->last_token = original_dest_len + 1 + src->last_token; return; } /* As far as I know, there's no case where inserting a space isn't enough to prevent a splice. */ internal_error (__FILE__, __LINE__, _("unable to avoid splicing tokens during macro expansion")); }
static void append_value(lua_State *L, write_state *state) { char numbuf[NUM_BUF_SIZE]; int ltype = lua_type(L, -1); switch (ltype) { case LUA_TNIL: { appends("null", state); break; } case LUA_TNUMBER: { LTdouble n = lua_tonumber(L, -1); snprintf(numbuf, NUM_BUF_SIZE, "%.14g", n); appends(numbuf, state); break; } case LUA_TBOOLEAN: { int b = lua_toboolean(L, -1); if (b) appends("true", state); else appends("false", state); break; } case LUA_TSTRING: { const char *s = lua_tostring(L, -1); appendc('"', state); while (*s != 0) { switch (*s) { case '\n': appends("\\n", state); break; case '\r': appends("\\r", state); break; case '\t': appends("\\t", state); break; case '\b': appends("\\b", state); break; case '\f': appends("\\f", state); break; case '\\': appends("\\\\", state); break; case '\"': appends("\\\"", state); break; default: appendc(*s, state); break; } s++; } appendc('"', state); break; } case LUA_TTABLE: { int is_array = 1; lua_pushnil(L); if (!lua_next(L, -2)) { // empty table. write out as empty array, since // that seems like it would be the more common case. appends("[]", state); break; } else { if (lua_type(L, -2) == LUA_TSTRING) is_array = 0; lua_pop(L, 2); // pop key and value } if (is_array) { appendc('[', state); int i = 1; lua_rawgeti(L, -1, i++); while (1) { append_value(L, state); lua_rawgeti(L, -1, i++); if (lua_isnil(L, -1)) { lua_pop(L, 1); // pop nil break; } appendc(',', state); } appendc(']', state); } else { appendc('{', state); lua_pushnil(L); lua_next(L, -2); while (1) { if (lua_type(L, -2) != LUA_TSTRING) { // ignore entries without string fields. lua_pop(L, 1); // pop value, leaving key if (!lua_next(L, -2)) break; continue; } lua_pushvalue(L, -2); // push key append_value(L, state); // write key appendc(':', state); append_value(L, state); // write value, key now on top if (!lua_next(L, -2)) break; appendc(',', state); } appendc('}', state); } break; } default: appends("null", state); } lua_pop(L, 1); // pop value }