/* Chrysalide - Outil d'analyse de fichiers binaires
* demangler.c - décodage des noms d'éléments
*
* Copyright (C) 2009-2017 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* Chrysalide is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Chrysalide 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see .
*/
#include "demangler.h"
#include "demangler-int.h"
/* Initialise la classe des décodeurs de désignations. */
static void g_compiler_demangler_class_init(GCompDemanglerClass *);
/* Initialise une instance de décodeur de désignations. */
static void g_compiler_demangler_init(GCompDemangler *);
/* Supprime toutes les références externes. */
static void g_compiler_demangler_dispose(GCompDemangler *);
/* Procède à la libération totale de la mémoire. */
static void g_compiler_demangler_finalize(GCompDemangler *);
/* Indique le type défini pour un décodeur de désignations. */
G_DEFINE_TYPE(GCompDemangler, g_compiler_demangler, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des décodeurs de désignations. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_compiler_demangler_class_init(GCompDemanglerClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_compiler_demangler_dispose;
object->finalize = (GObjectFinalizeFunc)g_compiler_demangler_finalize;
}
/******************************************************************************
* *
* Paramètres : demangler = instance à initialiser. *
* *
* Description : Initialise une instance de décodeur de désignations. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_compiler_demangler_init(GCompDemangler *demangler)
{
}
/******************************************************************************
* *
* Paramètres : demangler = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_compiler_demangler_dispose(GCompDemangler *demangler)
{
G_OBJECT_CLASS(g_compiler_demangler_parent_class)->dispose(G_OBJECT(demangler));
}
/******************************************************************************
* *
* Paramètres : demangler = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_compiler_demangler_finalize(GCompDemangler *demangler)
{
G_OBJECT_CLASS(g_compiler_demangler_parent_class)->finalize(G_OBJECT(demangler));
}
/******************************************************************************
* *
* Paramètres : demangler = décodeur à solliciter pour l'opération. *
* desc = chaîne de caractères à décoder. *
* *
* Description : Tente de décoder une chaîne de caractères donnée en type. *
* *
* Retour : Instance obtenue ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
GDataType *g_compiler_demangler_decode_type(const GCompDemangler *demangler, const char *desc)
{
GDataType *result; /* Construction à remonter */
GType ctx_type; /* Type de contexte adapté */
GDemanglingContext *context; /* Espace de travail dédié */
ctx_type = G_COMP_DEMANGLER_GET_CLASS(demangler)->context_type;
context = g_object_new(ctx_type, NULL);
result = g_demangling_context_decode_type(context, desc);
g_object_unref(G_OBJECT(context));
return result;
}
/******************************************************************************
* *
* Paramètres : demangler = décodeur à solliciter pour l'opération. *
* desc = chaîne de caractères à décoder. *
* *
* Description : Tente de décoder une chaîne de caractères donnée en routine. *
* *
* Retour : Instance obtenue ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinRoutine *g_compiler_demangler_decode_routine(const GCompDemangler *demangler, const char *desc)
{
GBinRoutine *result; /* Construction à remonter */
GType ctx_type; /* Type de contexte adapté */
GDemanglingContext *context; /* Espace de travail dédié */
ctx_type = G_COMP_DEMANGLER_GET_CLASS(demangler)->context_type;
context = g_object_new(ctx_type, NULL);
result = g_demangling_context_decode_routine(context, desc);
g_object_unref(G_OBJECT(context));
return result;
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
#include
#include
//#include "itanium.h"
#include "java.h"
/* Indique si une chaîne peut être traitée par le décodeur. */
typedef bool (* can_be_demangled_fc) (const char *);
/* Prépare de quoi effectuer un décodage. */
typedef GDemanglingContext * (* create_context_fc) (void);
/* Procède au décodage d'une chaîne de caractères. */
typedef bool (* demangle_fc) (GDemanglingContext *, const char *);
/* Appels liés à un décodeur */
typedef struct _demangling_properties
{
can_be_demangled_fc can_demangle; /* Possibilité de traitement */
create_context_fc create_context; /* Création de contextes */
demangle_fc demangle_routine; /* Décodage d'une routine */
demangle_fc demangle_type; /* Décodage d'un type */
} demangling_properties;
/* Liste des décodeurs */
static demangling_properties demanglers[/*DGT_COUNT*/] = {
/*
[DGT_ITANIUM] = {
.can_demangle = (can_be_demangled_fc)can_be_itanium_demangled,
.create_context = (create_context_fc)g_itanium_dcontext_new,
.demangle_routine = (demangle_fc)demangle_itanium_routine,
.demangle_type = (demangle_fc)NULL
},
*/
/*
[DGT_JAVA] = {
.can_demangle = (can_be_demangled_fc)NULL,
.create_context = (create_context_fc)g_java_dcontext_new,
.demangle_routine = (demangle_fc)NULL,
.demangle_type = (demangle_fc)demangle_java_type
}
*/
};
/******************************************************************************
* *
* Paramètres : desc = chaîne de caractères à décoder. *
* *
* Description : Tente de décoder une chaîne de caractères donnée. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinRoutine *try_to_demangle_routine(const char *desc)
{
GBinRoutine *result; /* Construction à remonter */
result = g_binary_routine_new();
g_binary_routine_set_name(result, strdup(desc));
return result;
#if 0
GBinRoutine *result; /* Construction à remonter */
DemanglerType i; /* Boucle de parcours */
static int counter = 0;
result = NULL;
if (strcmp(desc, "_ZN21IUDFSettingsValidator15IdNotIllegalStdEN13UDFParameters12UDF_STANDARDES1_") == 0
|| strcmp(desc, "_ZSt12partial_sortIN9__gnu_cxx17__normal_iteratorIP28CPR_MAI_ADPTY_SectorSequenceSt6vectorIS2_SaIS2_EEEEEvT_S8_S8_") == 0
|| strcmp(desc, "_ZSt22__merge_without_bufferIN9__gnu_cxx17__normal_iteratorIP15CProfStringListSt6vectorIS2_SaIS2_EEEEiEvT_S8_S8_T0_S9_") == 0
|| strcmp(desc, "_ZSt11__push_heapIN9__gnu_cxx17__normal_iteratorIP8DRIVE_IDSt6vectorIS2_SaIS2_EEEEiS2_EvT_T0_S9_T1_") == 0 // Intéressant
//|| strcmp(desc, "") == 0
)
goto exit;
for (i = 0; i < DGT_COUNT; i++)
{
if (demanglers[i].can_demangle == NULL)
continue;
if (!demanglers[i].can_demangle(desc))
continue;
printf("++ [%d] routine :: %s\n", ++counter, desc);
fflush(NULL);
result = demangle_routine(i, desc);
/* FIXME : à supprimer quand mature */
if (result == NULL)
{
printf("++failed :: %s\n", desc);
if (strcmp(desc, "_ZN21IUDFSettingsValidator15IdNotIllegalStdEN13UDFParameters12UDF_STANDARDES1_") != 0
&& strcmp(desc, "_ZSt12partial_sortIN9__gnu_cxx17__normal_iteratorIP28CPR_MAI_ADPTY_SectorSequenceSt6vectorIS2_SaIS2_EEEEEvT_S8_S8_") != 0
)
exit(-1);
}
else printf(" -->> '%s'\n\n", g_binary_routine_get_name(result));
if (result != NULL) break;
}
exit:
if (result == NULL)
{
result = g_binary_routine_new();
g_binary_routine_set_name(result, strdup(desc));
}
return result;
#endif
return NULL;
}
/******************************************************************************
* *
* Paramètres : type = type de décodeur à utiliser. *
* desc = chaîne de caractères à décoder. *
* *
* Description : Tente de décoder une chaîne de caractères donnée. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinRoutine *demangle_routine(GType type, const char *desc)
{
GBinRoutine *result; /* Construction à remonter */
GDemanglingContext *context; /* Contexte pour le décodage */
context = g_object_new(type, NULL);
result = g_demangling_context_get_decoded_routine(context, desc);
g_object_unref(context);
return result;
}
/******************************************************************************
* *
* Paramètres : type = type de décodeur à utiliser. *
* desc = chaîne de caractères à décoder. *
* *
* Description : Tente de décoder une chaîne de caractères donnée. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
GDataType *demangle_type(GType type, const char *desc)
{
GBinRoutine *result; /* Construction à remonter */
GDemanglingContext *context; /* Contexte pour le décodage */
context = g_object_new(type, NULL);
result = g_demangling_context_get_decoded_type(context, desc);
g_object_unref(context);
return result;
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Procède au test de décodages de chaînes de caractères. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
#if 0
void test_itanium_demangling(void)
{
GBinRoutine *routine;
char *human;
char stop;
#define TEST_ITANIUM_MANGLING(name, ref) \
do \
{ \
printf(" >> %s\n", name); \
routine = demangle_routine(DGT_ITANIUM, name); \
if (routine == NULL) \
{ \
printf("Error with %s\n", name); \
stop = true; \
} \
else \
{ \
human = g_binary_routine_to_string(routine); \
printf(" >> %s\n", human); \
stop = (strcmp(ref, human) != 0); \
printf(" >> ok ? %s\n", (!stop ? "oui" : "non")); \
if (stop) printf(" >> expected '%s'\n", ref); \
free(human); \
} \
if (stop) goto end_of_test; \
else printf("\n"); \
} \
while (0)
//goto last;
/**
* Tests de :
* http://www.codesourcery.com/public/cxx-abi/abi-examples.html#mangling
*/
TEST_ITANIUM_MANGLING("_Z1fv", "??? f(void)");
TEST_ITANIUM_MANGLING("_Z1fi", "??? f(int)");
TEST_ITANIUM_MANGLING("_Z3foo3bar", "??? foo(bar)");
TEST_ITANIUM_MANGLING("_Zrm1XS_", "??? %(X, X)");
TEST_ITANIUM_MANGLING("_ZplR1XS0_", "??? +(X &, X &)");
TEST_ITANIUM_MANGLING("_ZlsRK1XS1_", "??? <<(const X &, const X &)");
TEST_ITANIUM_MANGLING("_Z1fIiEvi", "void f(int)");
TEST_ITANIUM_MANGLING("_Z5firstI3DuoEvS0_", "void first(Duo)");
TEST_ITANIUM_MANGLING("_Z5firstI3DuoEvT_", "void first(Duo)");
TEST_ITANIUM_MANGLING("_Z3fooIiPFidEiEvv", "void foo(void)");
TEST_ITANIUM_MANGLING("_ZN6System5Sound4beepEv", "??? System::Sound::beep(void)");
TEST_ITANIUM_MANGLING("_Z1fI1XE vPV N1AIT_E1TE", "void f(volatile A::T *)");
//// TODO :: TEST_ITANIUM_MANGLING("_ZngILi42EE v N1A I XplT_Li2EE E 1TE", "");
TEST_ITANIUM_MANGLING("_Z4makeI7FactoryiE T_IT0_E v", "Factory make(void)");
TEST_ITANIUM_MANGLING("_ZlsRSoRKSs", "??? <<(std::ostream &, const std::string &)");
//TEST_ITANIUM_MANGLING("", "");
/**
* Tests de :
* http://www.codesourcery.com/public/cxx-abi/abi.html#mangling
*/
TEST_ITANIUM_MANGLING("_ZN1N1TIiiE2mfES0_IddE", "??? N::T::mf(N::T)");
/**
* Tests de :
* (nero.so).
*/
TEST_ITANIUM_MANGLING("_ZNSt6vectorItSaItEE6insertEN9__gnu_cxx17__normal_iteratorIPtS1_EERKt", "??? std::vector>::insert(__gnu_cxx::__normal_iterator>>, const unsigned short &)");
TEST_ITANIUM_MANGLING("_ZSt26__uninitialized_fill_n_auxIP15CProfStringListiS0_ET_S2_T0_RKT1_12__false_type", "CProfStringList *std::__uninitialized_fill_n_aux(CProfStringList *, int, const CProfStringList &, __false_type)");
// TODO TEST_ITANIUM_MANGLING("_ZN21IUDFSettingsValidator15IdNotIllegalStdEN13UDFParameters12UDF_STANDARDES1_", "");
TEST_ITANIUM_MANGLING("_ZNSbI26NeroMediumFeatureSpecifierSt11char_traitsIS_ESaIS_EE4_Rep10_M_destroyERKS2_", "??? std::basic_string, std::allocator>::_Rep::_M_destroy(const std::allocator &)");
last:
/* 80 */
TEST_ITANIUM_MANGLING("_ZNSt6vectorIlSaIlEE6insertEN9__gnu_cxx17__normal_iteratorIPlS1_EERKl", "??? std::vector>::insert(__gnu_cxx::__normal_iterator>>, const long &)");
end_of_test:
;
}
#endif