%{ #include #include #include #include "context-int.h" #include "demangler-int.h" #include "itanium.h" #include "../../common/extstr.h" /** * cf. http://www.codesourcery.com/cxx-abi/abi.html#mangling */ /* --------------------- CONTEXTE POUR LE DECODAGE TYPE ITANIUM --------------------- */ #define G_TYPE_ITANIUM_DCONTEXT g_itanium_dcontext_get_type() #define G_ITANIUM_DCONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_itanium_dcontext_get_type(), GItaniumDContext)) #define G_IS_ITANIUM_DCONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_itanium_dcontext_get_type())) #define G_ITANIUM_DCONTEXT_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_itanium_dcontext_get_type(), GItaniumDContextIface)) #define G_ITANIUM_DCONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ITANIUM_DCONTEXT, GItaniumDContextClass)) /* Contexte de décodage Itanium (instance) */ struct _GItaniumDContext { GDemanglingContext parent; /* A laisser en premier */ char *identifier; /* Identifiant en construction */ size_t id_allocated; /* Taille allouée en mémoire */ size_t id_used; /* Longueur de la chaîne */ bool use_templates; /* Utilisation des gabarits */ GSList *routines; /* Routines en cours de maj */ GSList *substitutions; /* Empilement des types créés */ }; /* Contexte de décodage Itanium (classe) */ struct _GItaniumDContextClass { GDemanglingContextClass parent; /* A laisser en premier */ }; /* Taille du bond pour les allocations */ #define ITANIUM_ALLOC_CLUSTER 10 /* Indique le type défini pour un contexte de décodage. */ static GType g_itanium_dcontext_get_type(void); /* Initialise la classe des contextes de décodage. */ static void g_itanium_dcontext_class_init(GItaniumDContextClass *); /* Initialise une instance de contexte pour décodage. */ static void g_itanium_dcontext_init(GItaniumDContext *); /* Réinitialise le constructeur d'identifiants. */ static void g_itanium_dcontext_reset_identifier(GItaniumDContext *); /* Construit à la volée un identifiant. */ static void g_itanium_dcontext_build_identifier(GItaniumDContext *, char); /* Place sous le feu des projecteurs une nouvelle routine. */ static GBinRoutine *g_itanium_dcontext_push_routine(GItaniumDContext *, GBinRoutine *); /* Remet une ancienne routine sous le feu des projecteurs. */ static GBinRoutine *g_itanium_dcontext_pop_routine(GItaniumDContext *); /* Ajoute un élément dans une liste de substitutions. */ static void g_itanium_dcontext_add_item(GItaniumDContext *, GOpenidaType *); /* Fournit le nième élément d'une liste de substitutions. */ static GOpenidaType *g_itanium_dcontext_get_item(GItaniumDContext *, guint); /* Borne la longueur d'une chaîne à lire. */ extern void set_itanium_text_length(unsigned int); char *strmerge(char *str1, const char *sep, char *str2); char *strmerge(char *str1, const char *sep, char *str2) { char *result; if (str1 == NULL) result = str2; else if (str2 == NULL) result = str1; else { result = (char *)calloc(strlen(str1) + strlen(sep) + strlen(str2) + 1, sizeof(char)); strcpy(result, str1); strcat(result, sep); strcat(result, str2); free(str1); free(str2); } return result; } %} %union { struct { union { char *str; void/*GOpenidaType*/ *type; }; int/*bool*/ is_string; } str_or_type; char car; char *text; unsigned int val; short/*s16_t*/ s16_val; void /*GOpenidaType*/ *type; void /*GTemplateType*/ *templtype; void/*simple_variable*/ *simple; void/*complex_variable*/ *complex; void/*variable*/ *var; int/*VariableQualifier*/ qual; void/*GSList*/ *slist; } %parse-param { GItaniumDContext *context } %parse-param { GBinRoutine *routine } %token ITANIUM_SIGNATURE %token EE NN II FF LL %token C1 C2 C3 D1 D2 D3 %token V W B C A H S T I J L M X Y N O F D E G Z DD DE DF DH DI DS U %token TP TR TO TC TG %token QR QV QK %token ST SA SB SS SI SO SD %token OPER_NEW OPER_NEW_ARRAY OPER_DELETE OPER_DELETE_ARRAY OPER_PLUS_UNARY OPER_NEG_UNARY %token OPER_AND_UNARY OPER_DE_UNARY OPER_COMPL OPER_PLUS OPER_MINUS OPER_MUL OPER_DIV OPER_MOD %token OPER_AND OPER_OR OPER_EXCL_OR OPER_AS OPER_PLUS_EQ OPER_MINUS_EQ OPER_MUL_EQ OPER_DIV_EQ %token OPER_MOD_EQ OPER_AND_EQ OPER_OR_EQ OPER_EXCL_OR_EQ OPER_LEFT_SHIFT OPER_RIGHT_SHIFT %token OPER_LEFT_SHIFT_EQ OPER_RIGHT_SHIFT_EQ OPER_EQUAL OPER_NOT_EQ OPER_LESS OPER_GREATER %token OPER_LESS_EQ OPER_GREATER_EQ OPER_NOT OPER_AND_AND OPER_OR_OR OPER_PLUS_PLUS OPER_MINUS_MINUS %token OPER_COMMA OPER_PRIV_MEMB OPER_POINTER_TO OPER_CLASS OPER_INDEX %token SUBSTI_FIRST SUBSTI_N %token TPARAM_FIRST TPARAM_N %token NUMBER CHAR %token LPART MPART RPART %token POSITION POSITION_ABS IMAGE %token RECT %token O_BRACKET C_BRACKET %token PATH %token DEC_16 %token TEXT %type TEXT PATH %type DEC_16 %type name %type unscoped_name %type nested_name %type unscoped_template_name %type unqualified_name operator_name %type prefix template_prefix source_name %type template_param template_template_param %type function_type type %type qualifiers %type builtin_type %type class_enum_type %type template_args template_arg_list %type template_arg expr_primary %type substitution %type CHAR %type NUMBER SUBSTI_N TPARAM_N %{ /* De lexi.c... */ /*int yylex(YYSTYPE *, YYLTYPE *);*/ void yyrestart(FILE *); typedef struct yy_buffer_state *YY_BUFFER_STATE; extern YY_BUFFER_STATE yy_scan_string(const char *); extern void yy_delete_buffer(YY_BUFFER_STATE); /* Affiche un message d'erreur concernant l'analyse. */ /*int yyerror(const YYLTYPE *, bool, char **, unsigned char *, char *);*/ %} %% input: ITANIUM_SIGNATURE encoding ; encoding: name { $1.is_string ? g_binary_routine_set_name(routine, $1.str) : g_binary_routine_set_name_from_type(routine, $1.type); } bare_function_type { ; } ; name: nested_name { $$.type = $1; $$.is_string = false; } | unscoped_name { $$.str = $1; $$.is_string = true; } | unscoped_template_name template_args { $$.type = $1; $$.is_string = false; g_template_type_add_params($1, $2); } ; unscoped_name: unqualified_name { $$ = $1; } | ST unqualified_name { $$ = strprep($2, "std::"); } ; unscoped_template_name: unscoped_name { $$ = g_template_type_new($1, NULL); g_itanium_dcontext_add_item(context, $$); } | substitution { $$ = NULL;/*g_openida_type_to_string($1)*/; /*printf("unscoped sub name :: %s\n", $$); g_object_unref(G_OBJECT($1));*/ } ; nested_name: NN prefix unqualified_name EE { $$ = ($3 != NULL ? strmerge($2, "::", $3) : $2); $$ = g_class_enum_type_new(CET_UNKNOWN, $$); } | NN template_prefix template_args EE { $$ = g_template_type_new($2, $3); } ; prefix: /* vide */ { $$ = NULL; /*printf("passage E\n")*/; } | prefix unqualified_name { $$ = ($2 != NULL ? strmerge($1, "::", $2) : $1); } | template_prefix template_args { $$ = g_template_type_new($1, $2); $$ = g_openida_type_to_string($$); /* FIXME : retourner un type ! */} | substitution { $$ = g_openida_type_to_string($1); printf("prefix substi :: %s\n", $$); g_object_unref(G_OBJECT($1)); } ; template_prefix: prefix unqualified_name { $$ = ($2 != NULL ? strmerge($1, "::", $2) : $1); } | template_param { $$ = g_openida_type_to_string($1); g_object_unref(G_OBJECT($1)); } ; unqualified_name: operator_name { printf("dup :: '%s'\n", $1); fflush(NULL) ;$$ = strdup($1) ; } | ctor_dtor_name { printf("passage C\n"); $$ = NULL; } | source_name { $$ = $1; } ; source_name: NUMBER { set_itanium_text_length($1); g_itanium_dcontext_reset_identifier(context); } identifier { $$ = strdup(context->identifier); printf("==source name== :: %s\n", $$); } ; identifier: identifier CHAR { g_itanium_dcontext_build_identifier(context, $2); } | CHAR { g_itanium_dcontext_build_identifier(context, $1); } ; operator_name: OPER_NEW { $$ = "new"; } | OPER_NEW_ARRAY { $$ = "new[]"; } | OPER_DELETE { $$ = "delete"; } | OPER_DELETE_ARRAY { $$ = "delete[]"; } | OPER_PLUS_UNARY { $$ = "+"; } | OPER_NEG_UNARY { $$ = "-"; } | OPER_AND_UNARY { $$ = "&"; } | OPER_DE_UNARY { $$ = "*"; } | OPER_COMPL { $$ = "~"; } | OPER_PLUS { $$ = "+"; } | OPER_MINUS { $$ = "-"; } | OPER_MUL { $$ = "*"; } | OPER_DIV { $$ = "/"; } | OPER_MOD { $$ = "%"; } | OPER_AND { $$ = "&"; } | OPER_OR { $$ = "|"; } | OPER_EXCL_OR { $$ = "^"; } | OPER_AS { $$ = "="; } | OPER_PLUS_EQ { $$ = "+="; } | OPER_MINUS_EQ { $$ = "-="; } | OPER_MUL_EQ { $$ = "*="; } | OPER_DIV_EQ { $$ = "/="; } | OPER_MOD_EQ { $$ = "%)"; } | OPER_AND_EQ { $$ = "&="; } | OPER_OR_EQ { $$ = "|="; } | OPER_EXCL_OR_EQ { $$ = "^="; } | OPER_LEFT_SHIFT { $$ = "<<"; } | OPER_RIGHT_SHIFT { $$ = ">>"; } | OPER_LEFT_SHIFT_EQ { $$ = "<<="; } | OPER_RIGHT_SHIFT_EQ { $$ = ">>="; } | OPER_EQUAL { $$ = "=="; } | OPER_NOT_EQ { $$ = "!="; } | OPER_LESS { $$ = "<"; } | OPER_GREATER { $$ = ">"; } | OPER_LESS_EQ { $$ = "<="; } | OPER_GREATER_EQ { $$ = ">="; } | OPER_NOT { $$ = "!"; } | OPER_AND_AND { $$ = "&&"; } | OPER_OR_OR { $$ = "||"; } | OPER_PLUS_PLUS { $$ = "++"; } | OPER_MINUS_MINUS { $$ = "--"; } | OPER_COMMA { $$ = ","; } | OPER_PRIV_MEMB { $$ = "->*"; } | OPER_POINTER_TO { $$ = "->"; } | OPER_CLASS { $$ = "()"; } | OPER_INDEX { $$ = "[]"; } ; ctor_dtor_name: C1 { g_binary_routine_set_type(routine, RTT_CONSTRUCTOR); } | C2 { g_binary_routine_set_type(routine, RTT_CONSTRUCTOR); } | C3 { g_binary_routine_set_type(routine, RTT_CONSTRUCTOR); } | D1 { g_binary_routine_set_type(routine, RTT_DESTRUCTOR); } | D2 { g_binary_routine_set_type(routine, RTT_DESTRUCTOR); } | D3 { g_binary_routine_set_type(routine, RTT_DESTRUCTOR); } ; function_type: FF { routine = g_itanium_dcontext_push_routine(context, routine); } bare_function_type EE { $$ = g_encapsulated_type_new(ECT_ROUTINE, routine); routine = g_itanium_dcontext_pop_routine(context); if (routine == NULL) YYERROR; } ; type: builtin_type { $$ = $1; printf("builtin '%s'\n", g_openida_type_to_string($1)); } | class_enum_type { $$ = $1; g_itanium_dcontext_add_item(context, $1); } | substitution { $$ = $1; } | template_param { $$ = $1; } | template_template_param template_args { $$ = g_template_type_new(g_openida_type_to_string($1), NULL); g_object_unref($1); g_template_type_add_params($$, $2); } | function_type { $$ = $1; } | qualifiers type { $$ = g_openida_type_dup($2); g_openida_type_add_qualifier($$, $1); g_itanium_dcontext_add_item(context, $$); } | TP type { $$ = g_encapsulated_type_new(ECT_POINTER, $2); g_itanium_dcontext_add_item(context, $$); } | TR type { $$ = g_encapsulated_type_new(ECT_REFERENCE, $2); g_itanium_dcontext_add_item(context, $$); } | TO type { $$ = g_encapsulated_type_new(ECT_RVALUE_REF, $2); g_itanium_dcontext_add_item(context, $$); } | TC type { $$ = g_encapsulated_type_new(ECT_COMPLEX, $2); g_itanium_dcontext_add_item(context, $$); } | TG type { $$ = g_encapsulated_type_new(ECT_IMAGINARY, $2); g_itanium_dcontext_add_item(context, $$); } ; qualifiers: QR { $$ = TQF_RESTRICT; } | QV { $$ = TQF_VOLATILE; } | QK { $$ = TQF_CONST; } ; builtin_type: V { $$ = g_basic_type_new(BTP_VOID); } | W { $$ = g_basic_type_new(BTP_WCHAR_T); } | B { $$ = g_basic_type_new(BTP_BOOL); } | C { $$ = g_basic_type_new(BTP_CHAR); } | A { $$ = g_basic_type_new(BTP_SCHAR); } | H { $$ = g_basic_type_new(BTP_UCHAR); } | S { $$ = g_basic_type_new(BTP_SHORT); } | T { $$ = g_basic_type_new(BTP_USHORT); } | I { $$ = g_basic_type_new(BTP_INT); } | J { $$ = g_basic_type_new(BTP_UINT); } | L { $$ = g_basic_type_new(BTP_LONG); } | M { $$ = g_basic_type_new(BTP_ULONG); } | X { $$ = g_basic_type_new(BTP_LONG_LONG); } | Y { $$ = g_basic_type_new(BTP_ULONG_LONG); } | N { $$ = g_basic_type_new(BTP_INT128); } | O { $$ = g_basic_type_new(BTP_UINT128); } | F { $$ = g_basic_type_new(BTP_FLOAT); } | D { $$ = g_basic_type_new(BTP_DOUBLE); } | E { $$ = g_basic_type_new(BTP_LONG_DOUBLE); } | G { $$ = g_basic_type_new(BTP_FLOAT128); } | Z { $$ = g_basic_type_new(BTP_ELLIPSIS); } | DD { $$ = g_basic_type_new(BTP_754R_64); } | DE { $$ = g_basic_type_new(BTP_754R_128); } | DF { $$ = g_basic_type_new(BTP_754R_32); } | DH { $$ = g_basic_type_new(BTP_754R_16); } | DI { $$ = g_basic_type_new(BTP_CHAR32_T); } | DS { $$ = g_basic_type_new(BTP_CHAR16_T); } | U source_name { $$ = g_basic_type_new(BTP_OTHER); /* TODO */ ; free($2); } ; bare_function_type: bare_function_type type { g_binary_routine_add_arg(routine, g_binary_variable_new($2)); } | type { if (context->use_templates) g_binary_routine_set_return_type(routine, $1); else g_binary_routine_add_arg(routine, g_binary_variable_new($1)); } ; class_enum_type: name { $$ = $1.is_string ? g_class_enum_type_new(CET_UNKNOWN, $1.str) : $1.type; } ; template_param: TPARAM_FIRST { const GOpenidaType *type = g_binary_routine_get_type_from_name(routine); if (G_IS_TEMPLATE_TYPE(type)) $$ = g_template_type_get_param(G_TEMPLATE_TYPE(type), 0); else $$ = NULL; if ($$ == NULL) YYERROR; } | TPARAM_N { const GOpenidaType *type = g_binary_routine_get_type_from_name(routine); if (G_IS_TEMPLATE_TYPE(type)) $$ = g_template_type_get_param(G_TEMPLATE_TYPE(type), $1 + 1); else $$ = NULL; if ($$ == NULL) YYERROR; } ; template_template_param: template_param { $$ = $1; } | substitution { $$ = $1; } ; template_args: use_templates template_arg_list EE { $$ = $2; } ; use_templates: II { printf("new template !!!\n"); context->use_templates = true; } ; template_arg_list: template_arg_list template_arg { $$ = g_slist_prepend($1, $2); } | template_arg { $$ = g_slist_prepend(NULL, $1); } | template_args { g_class_enum_type_new(CET_UNKNOWN, "template params"); } ; template_arg: type { $$ = $1; } | expr_primary { $$ = $1; } ; expr_primary: LL type NUMBER EE { $$ = $2; } ; substitution: ST { $$ = g_class_enum_type_new(CET_CLASS, "std"); } | SA { $$ = g_class_enum_type_new(CET_CLASS, "std::allocator"); } | SB { $$ = g_class_enum_type_new(CET_CLASS, "std::basic_string"); } | SS { $$ = g_class_enum_type_new(CET_CLASS, "std::string"); } | SI { $$ = g_class_enum_type_new(CET_CLASS, "std::istream"); } | SO { $$ = g_class_enum_type_new(CET_CLASS, "std::ostream"); } | SD { $$ = g_class_enum_type_new(CET_CLASS, "std::iostream"); } | SUBSTI_FIRST { $$ = g_itanium_dcontext_get_item(context, 0); if ($$ == NULL) YYERROR; } | SUBSTI_N { $$ = g_itanium_dcontext_get_item(context, $1 + 1); if ($$ == NULL) YYERROR; } ; %% /* ---------------------------------------------------------------------------------- */ /* CONTEXTE POUR LE DECODAGE TYPE ITANIUM */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un contexte de décodage. */ G_DEFINE_TYPE(GItaniumDContext, g_itanium_dcontext, G_TYPE_DEMANGLING_CONTEXT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des contextes de décodage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_itanium_dcontext_class_init(GItaniumDContextClass *klass) { } /****************************************************************************** * * * Paramètres : context = instance à initialiser. * * * * Description : Initialise une instance de contexte pour décodage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_itanium_dcontext_init(GItaniumDContext *context) { context->substitutions = g_slist_alloc(); } /****************************************************************************** * * * Paramètres : - * * * * Description : Prépare de quoi effectuer un décodage Itanium. * * * * Retour : Instance du contexte mis en place. * * * * Remarques : - * * * ******************************************************************************/ GDemanglingContext *g_itanium_dcontext_new(void) { GDemanglingContext *result; /* Structure à retourner */ result = g_object_new(G_TYPE_ITANIUM_DCONTEXT, NULL); return result; } /****************************************************************************** * * * Paramètres : context = décodeur à mettre à jour. * * * * Description : Réinitialise le constructeur d'identifiants. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_itanium_dcontext_reset_identifier(GItaniumDContext *context) { context->id_used = 0; } /****************************************************************************** * * * Paramètres : context = décodeur à mettre à jour. * * value = caractère d'identifiant à mémoriser. * * * * Description : Construit à la volée un identifiant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_itanium_dcontext_build_identifier(GItaniumDContext *context, char value) { if ((context->id_used + 2) > context->id_allocated) { context->id_allocated += ITANIUM_ALLOC_CLUSTER; context->identifier = (char *)realloc(context->identifier, context->id_allocated * sizeof(char)); } context->identifier[context->id_used++] = value; context->identifier[context->id_used] = 0; } /****************************************************************************** * * * Paramètres : context = décodeur à mettre à jour. * * previous = routine à sauvegarder. * * * * Description : Place sous le feu des projecteurs une nouvelle routine. * * * * Retour : Nouvelle routine à compléter. * * * * Remarques : - * * * ******************************************************************************/ static GBinRoutine *g_itanium_dcontext_push_routine(GItaniumDContext *context, GBinRoutine *previous) { GBinRoutine *result; /* Routine nouvelle à renvoyer */ result = g_binary_routine_new(); context->routines = g_slist_append(context->routines, previous); return result; } /****************************************************************************** * * * Paramètres : context = décodeur à mettre à jour. * * * * Description : Remet une ancienne routine sous le feu des projecteurs. * * * * Retour : Routine sauvegardée. * * * * Remarques : - * * * ******************************************************************************/ static GBinRoutine *g_itanium_dcontext_pop_routine(GItaniumDContext *context) { GBinRoutine *result; /* Routine nouvelle à renvoyer */ GSList *last; /* Dernier élément */ last = g_slist_last(context->routines); if (last == NULL) result = NULL; else { result = G_BIN_ROUTINE(last->data); context->routines = g_slist_remove(context->routines, result); } return result; } /****************************************************************************** * * * Paramètres : context = décodeur à mettre à jour. * * type = élément à placer dans la liste des substitutions. * * * * Description : Ajoute un élément dans une liste de substitutions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_itanium_dcontext_add_item(GItaniumDContext *context, GOpenidaType *type) { g_object_ref(G_OBJECT(type)); printf("push %p\n", type); context->substitutions = g_slist_append(context->substitutions, type); } /****************************************************************************** * * * Paramètres : context = décodeur à consulter. * * n = indice de l'élément à fournir. * * * * Description : Fournit le nième élément d'une liste de substitutions. * * * * Retour : Type prêt à emploi. * * * * Remarques : - * * * ******************************************************************************/ static GOpenidaType *g_itanium_dcontext_get_item(GItaniumDContext *context, guint n) { printf("get [%u] == %p\n", n, g_slist_nth_data(context->substitutions, n + 1)); return G_OPENIDA_TYPE(g_slist_nth_data(context->substitutions, n + 1)); } /** * Affiche un message d'erreur concernant l'analyse. * @param yyloc informations concernant les coordonnées du soucis. * @param hunt indique le type de passe réalisée. * @param ucode code résultant compilé. * @param index indice de commande à mettre à jour. * @param msg indications humaines sur l'événement. * @return 0. */ int yyerror(/*const YYLTYPE *yyloc, bool hunt, char **ucode, unsigned char *index, */char *msg) { fprintf(stderr, "ERREUR !\n"); fprintf(stderr, "%s\n", msg); return -1; } #if 0 /****************************************************************************** * * * Paramètres : demangler = décodeur à utiliser. * * name = chaîne de caractères à analyser. * * * * Description : Indique si une chaîne peut être traitée par le décodeur. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool can_be_itanium_demangled(itanium_demangler *itanium, const char *name) { return (strncmp(name, "_Z", 2) == 0); } #endif /****************************************************************************** * * * Paramètres : context = contexte de décodage à utiliser. * * desc = chaîne de caractères à décoder. * * * * Description : Procède au décodage d'une chaîne de caractères. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool demangle_itanium_routine(GItaniumDContext *context, const char *desc) { YY_BUFFER_STATE buffer; /* Tampon pour bison */ int ret; /* Bilan de l'appel */ buffer = yy_scan_string(desc); ret = yyparse(context, g_demangling_context_get_decoded_routine(G_DEMANGLING_CONTEXT(context))); yy_delete_buffer(buffer); return (ret == 0); }