X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/37954781d9756ece500551055562183a1e28e943..0c172698f8957c8238cd9915ca09eb8a2b68db97:/sig/parse.cpp?ds=sidebyside diff --git a/sig/parse.cpp b/sig/parse.cpp index 05b3213..7e025f8 100644 --- a/sig/parse.cpp +++ b/sig/parse.cpp @@ -1,64 +1,46 @@ -/* Cycript - Remove Execution Server and Disassembler - * Copyright (C) 2009 Jay Freeman (saurik) +/* Cycript - The Truly Universal Scripting Language + * Copyright (C) 2009-2016 Jay Freeman (saurik) */ -/* Modified BSD License {{{ */ +/* GNU Affero General Public License, Version 3 {{{ */ /* - * Redistribution and use in source and binary - * forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the - * above copyright notice, this list of conditions - * and the following disclaimer. - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions - * and the following disclaimer in the documentation - * and/or other materials provided with the - * distribution. - * 3. The name of the author may not be used to endorse - * or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +**/ /* }}} */ -#include #include "sig/parse.hpp" #include "Error.hpp" #include #include #include +#include namespace sig { -void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos, Callback callback); -struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named, Callback callback); +void Parse_(CYPool &pool, struct Signature *signature, const char **name, char eos, Callback callback); +struct Type *Parse_(CYPool &pool, const char **name, char eos, bool named, Callback callback); /* XXX: I really screwed up this time */ -void *prealloc_(apr_pool_t *pool, void *odata, size_t osize, size_t nsize) { - void *ndata = apr_palloc(pool, nsize); +void *prealloc_(CYPool &pool, void *odata, size_t osize, size_t nsize) { + void *ndata(pool.malloc(nsize)); memcpy(ndata, odata, osize); return ndata; } -void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos, Callback callback) { +void Parse_(CYPool &pool, struct Signature *signature, const char **name, char eos, Callback callback) { _assert(*name != NULL); // XXX: this is just a stupid check :( @@ -81,8 +63,8 @@ void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, ch if (**name != '"') element->name = NULL; else { - char *quote = strchr(++*name, '"'); - element->name = apr_pstrmemdup(pool, *name, quote - *name); + const char *quote = strchr(++*name, '"'); + element->name = pool.strmemdup(*name, quote - *name); *name = quote + 1; } @@ -100,195 +82,365 @@ void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, ch } } -struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named, Callback callback) { - char next = *(*name)++; - if (next == '?') - return NULL; +Type *Parse_(CYPool &pool, const char **encoding, char eos, bool named, Callback callback) { + char next = *(*encoding)++; - struct Type *type = (struct Type *) apr_palloc(pool, sizeof(struct Type)); - _assert(type != NULL); - memset(type, 0, sizeof(struct Type)); + Type *type; + uint8_t flags(0); parse: switch (next) { - case '#': type->primitive = typename_P; break; + case '?': type = new(pool) Unknown(); break; + +#ifdef CY_OBJECTIVEC + case '#': type = new(pool) Meta(); break; +#endif case '(': - if (type->data.signature.count < 2) - type->primitive = struct_P; - else - type->primitive = union_P; + type = new(pool) Aggregate(true); next = ')'; goto aggregate; - case '*': type->primitive = string_P; break; - case ':': type->primitive = selector_P; break; + case '*': type = new(pool) String(); break; - case '@': - if (**name == '"') { - char *quote = strchr(*name + 1, '"'); - if (!named || quote[1] == eos || quote[1] == '"') { - type->name = apr_pstrmemdup(pool, *name + 1, quote - *name - 1); - *name = quote + 1; - } - } +#ifdef CY_OBJECTIVEC + case ':': type = new(pool) Selector(); break; - type->primitive = object_P; - break; + case '@': { + char next(**encoding); - case 'B': type->primitive = boolean_P; break; - case 'C': type->primitive = uchar_P; break; - case 'I': type->primitive = uint_P; break; - case 'L': type->primitive = ulong_P; break; - case 'Q': type->primitive = ulonglong_P; break; - case 'S': type->primitive = ushort_P; break; - - case '[': - type->primitive = array_P; - type->data.data.size = strtoul(*name, (char **) name, 10); - type->data.data.type = Parse_(pool, name, eos, false, callback); - if (**name != ']') { - printf("']' != \"%s\"\n", *name); - _assert(false); + if (next == '?') { + type = new(pool) Block(); + ++*encoding; + } else { + const char *name; + if (next != '"') + name = NULL; + else { + const char *quote = strchr(*encoding + 1, '"'); + if (quote == NULL) + CYThrow("unterminated specific id type {%s}", *encoding - 10); + else if (!named || quote[1] == eos || quote[1] == '"') { + name = pool.strmemdup(*encoding + 1, quote - *encoding - 1); + *encoding = quote + 1; + } else { + name = NULL; + } + } + + type = new(pool) Object(name); } - ++*name; - break; + + } break; +#endif + + case 'B': type = new(pool) Primitive(); break; + case 'C': type = new(pool) Primitive(); break; + case 'I': type = new(pool) Primitive(); break; + case 'L': type = new(pool) Primitive(); break; + case 'Q': type = new(pool) Primitive(); break; + case 'S': type = new(pool) Primitive(); break; + + case '[': { + size_t size(strtoul(*encoding, (char **) encoding, 10)); + type = new(pool) Array(*Parse_(pool, encoding, eos, false, callback), size); + if (**encoding != ']') + CYThrow("']' != \"%s\"", *encoding); + ++*encoding; + } break; case '^': - type->primitive = pointer_P; - if (**name == '"') { - type->data.data.type = NULL; - } else { - type->data.data.type = Parse_(pool, name, eos, named, callback); - sig::Type *&target(type->data.data.type); - if (target != NULL && target->primitive == void_P) - target = NULL; + if (**encoding == '"') + _assert(false); // XXX: why is this here?!? + else { + type = Parse_(pool, encoding, eos, named, callback); +#ifdef CY_OBJECTIVEC + Aggregate *aggregate(dynamic_cast(type)); + if (aggregate != NULL && strcmp(aggregate->name, "_objc_class") == 0) + type = new(pool) Meta(); + else +#endif + type = new(pool) Pointer(*type); } break; case 'b': - type->primitive = bit_P; - type->data.data.size = strtoul(*name, (char **) name, 10); + type = new(pool) Bits(strtoul(*encoding, (char **) encoding, 10)); break; - case 'c': type->primitive = char_P; break; - case 'd': type->primitive = double_P; break; - case 'f': type->primitive = float_P; break; - case 'i': type->primitive = int_P; break; - case 'l': type->primitive = long_P; break; - case 'q': type->primitive = longlong_P; break; - case 's': type->primitive = short_P; break; - case 'v': type->primitive = void_P; break; + case 'c': type = new(pool) Primitive(); break; + case 'D': type = new(pool) Primitive(); break; + case 'd': type = new(pool) Primitive(); break; + case 'f': type = new(pool) Primitive(); break; + case 'i': type = new(pool) Primitive(); break; + case 'l': type = new(pool) Primitive(); break; + case 'q': type = new(pool) Primitive(); break; + case 's': type = new(pool) Primitive(); break; + case 'v': type = new(pool) Void(); break; + +#ifdef __SIZEOF_INT128__ + case 't': type = new(pool) Primitive(); break; + case 'T': type = new(pool) Primitive(); break; +#endif case '{': - type->primitive = struct_P; + type = new(pool) Aggregate(false); next = '}'; goto aggregate; aggregate: { + Aggregate *aggregate(static_cast(type)); + char end = next; - const char *begin = *name; - do next = *(*name)++; - while ( - next != '=' && - next != '}' - ); - size_t length = *name - begin - 1; + const char *begin = *encoding; + do switch (next = *(*encoding)++) { + case '\0': + _assert(false); + case '}': + // XXX: this is actually a type reference + aggregate->signature.count = _not(size_t); + next = '='; // this is a "break". I'm sorry + } while (next != '='); + + size_t length = *encoding - begin - 1; if (strncmp(begin, "?", length) != 0) - type->name = (char *) apr_pstrmemdup(pool, begin, length); + aggregate->name = (char *) pool.strmemdup(begin, length); + + if (aggregate->signature.count == _not(size_t)) + aggregate->signature.elements = NULL; else - type->name = NULL; + Parse_(pool, &aggregate->signature, encoding, end, callback); - // XXX: this types thing is a throwback to JocStrap - - char *types; - if (next != '=') { - types = NULL; - } else { - const char *temp(*name); - Parse_(pool, &type->data.signature, name, end, callback); - types = (char *) apr_pstrmemdup(pool, temp, *name - temp - 1); - } + // XXX: this is a hack to support trivial unions + if (aggregate->signature.count <= 1) + aggregate->overlap = false; if (callback != NULL) - (*callback)(pool, type->name, types, type); + type = (*callback)(pool, aggregate); } break; - case 'N': type->flags |= JOC_TYPE_INOUT; goto next; - case 'n': type->flags |= JOC_TYPE_IN; goto next; - case 'O': type->flags |= JOC_TYPE_BYCOPY; goto next; - case 'o': type->flags |= JOC_TYPE_OUT; goto next; - case 'R': type->flags |= JOC_TYPE_BYREF; goto next; - case 'r': type->flags |= JOC_TYPE_CONST; goto next; - case 'V': type->flags |= JOC_TYPE_ONEWAY; goto next; + case 'r': flags |= JOC_TYPE_CONST; goto next; + + case 'n': flags |= JOC_TYPE_IN; goto next; + case 'N': flags |= JOC_TYPE_INOUT; goto next; + case 'o': flags |= JOC_TYPE_OUT; goto next; + case 'O': flags |= JOC_TYPE_BYCOPY; goto next; + case 'R': flags |= JOC_TYPE_BYREF; goto next; + case 'V': flags |= JOC_TYPE_ONEWAY; goto next; next: - next = *(*name)++; + next = *(*encoding)++; goto parse; break; default: - printf("invalid type character: '%c' {%s}\n", next, *name - 10); - _assert(false); + CYThrow("invalid type character: '%c' {%s}", next, *encoding - 10); } + type->flags = flags; + return type; } -void Parse(apr_pool_t *pool, struct Signature *signature, const char *name, Callback callback) { +void Parse(CYPool &pool, struct Signature *signature, const char *name, Callback callback) { const char *temp = name; Parse_(pool, signature, &temp, '\0', callback); _assert(temp[-1] == '\0'); } -const char *Unparse(apr_pool_t *pool, struct Signature *signature) { +const char *Unparse(CYPool &pool, const struct Signature *signature) { const char *value = ""; size_t offset; for (offset = 0; offset != signature->count; ++offset) { const char *type = Unparse(pool, signature->elements[offset].type); - value = apr_pstrcat(pool, value, type, NULL); + value = pool.strcat(value, type, NULL); } return value; } -const char *Unparse(apr_pool_t *pool, struct Type *type) { - if (type == NULL) - return "?"; - else switch (type->primitive) { - case typename_P: return "#"; - case union_P: return apr_psprintf(pool, "(%s)", Unparse(pool, &type->data.signature)); - case string_P: return "*"; - case selector_P: return ":"; - case object_P: return type->name == NULL ? "@" : apr_psprintf(pool, "@\"%s\"", type->name); - case boolean_P: return "B"; - case uchar_P: return "C"; - case uint_P: return "I"; - case ulong_P: return "L"; - case ulonglong_P: return "Q"; - case ushort_P: return "S"; - - case array_P: { - const char *value = Unparse(pool, type->data.data.type); - return apr_psprintf(pool, "[%lu%s]", type->data.data.size, value); - } break; +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "B"; +} - case pointer_P: return apr_psprintf(pool, "^%s", type->data.data.type == NULL ? "v" : Unparse(pool, type->data.data.type)); - case bit_P: return apr_psprintf(pool, "b%zu", type->data.data.size); - case char_P: return "c"; - case double_P: return "d"; - case float_P: return "f"; - case int_P: return "i"; - case long_P: return "l"; - case longlong_P: return "q"; - case short_P: return "s"; - case void_P: return "v"; - case struct_P: return apr_psprintf(pool, "{%s=%s}", type->name == NULL ? "?" : type->name, Unparse(pool, &type->data.signature)); - } +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "c"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "d"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "f"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "D"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "c"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "i"; +} - _assert(false); - return NULL; +#ifdef __SIZEOF_INT128__ +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "t"; +} +#endif + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "l"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "q"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "s"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "C"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "I"; +} + +#ifdef __SIZEOF_INT128__ +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "T"; +} +#endif + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "L"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "Q"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "S"; +} + +const char *Void::Encode(CYPool &pool) const { + return "v"; +} + +const char *Unknown::Encode(CYPool &pool) const { + return "?"; +} + +const char *String::Encode(CYPool &pool) const { + return "*"; +} + +#ifdef CY_OBJECTIVEC +const char *Meta::Encode(CYPool &pool) const { + return "#"; +} + +const char *Selector::Encode(CYPool &pool) const { + return ":"; +} +#endif + +const char *Bits::Encode(CYPool &pool) const { + return pool.strcat("b", pool.itoa(size), NULL); +} + +const char *Pointer::Encode(CYPool &pool) const { + return pool.strcat("^", type.Encode(pool), NULL); +} + +const char *Array::Encode(CYPool &pool) const { + return pool.strcat("[", pool.itoa(size), type.Encode(pool), "]", NULL); +} + +#ifdef CY_OBJECTIVEC +const char *Object::Encode(CYPool &pool) const { + return name == NULL ? "@" : pool.strcat("@\"", name, "\"", NULL); +} +#endif + +const char *Enum::Encode(CYPool &pool) const { + return type.Encode(pool); +} + +const char *Aggregate::Encode(CYPool &pool) const { + bool reference(signature.count == _not(size_t)); + return pool.strcat(overlap ? "(" : "{", + name == NULL ? "?" : name, + reference ? "" : "=", + reference ? "" : Unparse(pool, &signature), + overlap ? ")" : "}", NULL); +} + +const char *Function::Encode(CYPool &pool) const { + return "?"; +} + +#ifdef CY_OBJECTIVEC +const char *Block::Encode(CYPool &pool) const { + return "@?"; +} +#endif + +const char *Unparse(CYPool &pool, const struct Type *type) { + const char *base(type->Encode(pool)); + if (type->flags == 0) + return base; + + #define iovec_(base, size) \ + (struct iovec) {const_cast(base), size} + + size_t size(strlen(base)); + char buffer[7 + size]; + size_t offset(0); + + if ((type->flags & JOC_TYPE_INOUT) != 0) + buffer[offset++] = 'N'; + if ((type->flags & JOC_TYPE_IN) != 0) + buffer[offset++] = 'n'; + if ((type->flags & JOC_TYPE_BYCOPY) != 0) + buffer[offset++] = 'O'; + if ((type->flags & JOC_TYPE_OUT) != 0) + buffer[offset++] = 'o'; + if ((type->flags & JOC_TYPE_BYREF) != 0) + buffer[offset++] = 'R'; + if ((type->flags & JOC_TYPE_CONST) != 0) + buffer[offset++] = 'r'; + if ((type->flags & JOC_TYPE_ONEWAY) != 0) + buffer[offset++] = 'V'; + + memcpy(buffer + offset, base, size); + return pool.strmemdup(buffer, offset + size); } }