Première version
This commit is contained in:
commit
35becf27e2
218
doc/libver.3
Normal file
218
doc/libver.3
Normal file
@ -0,0 +1,218 @@
|
||||
'\" t
|
||||
'." @(#)LIBVER.3 2.0 00/06/30 SMA;
|
||||
.TH LIBVER 3 "01 Apr 2000"
|
||||
.SH NOM
|
||||
LIBVER (utilitaires divers)
|
||||
.SH SYNOPSIS
|
||||
.LP
|
||||
.B cc [flag ...] file ... -lver [library ...]
|
||||
.LP
|
||||
.BI "#include <ver.h>"
|
||||
.LP
|
||||
.BI "VER_INFO_EXPORT( " Object_Name ", " Version ", " CVS_Tag ", " Src_File ", " Author " )"
|
||||
.LP
|
||||
.BI "VERT_Status VER_Object_Print ( FILE * " Stream ", VERT_Print_Mode " Print_Mode " );"
|
||||
.LP
|
||||
.BI "VERT_Status VER_Info_Next_Get(VERT_Info_Container ** " Container ", VERT_Object * " Object ", VERT_Index * " Index " );"
|
||||
.LP
|
||||
.BI "VERT_Status VER_Info_Print(FILE * " Out ", VERT_Info_Container * " Container ", VERT_Print_Mode " Print_Mode " );"
|
||||
.LP
|
||||
.SH DESCRIPTION
|
||||
.LP
|
||||
La librairie
|
||||
.B LIBVER
|
||||
permet a un objet (programme ou librairie) de partager ses informations concernant :
|
||||
.LP
|
||||
.RS 3
|
||||
- son nom
|
||||
.LP
|
||||
- sa version
|
||||
.LP
|
||||
- son tag CVS
|
||||
.LP
|
||||
- le nom de son fichier source
|
||||
.LP
|
||||
- l'auteur de son fichier source
|
||||
.RS -3¨
|
||||
.LP
|
||||
La librairie fournit aussi des fonctions d'acces aux informations partagees
|
||||
par tous les objets (statiques (.o) ou partages (.so)) dont depend l'objet courant.
|
||||
.LP
|
||||
.SH "FONCTIONS & MACRO"
|
||||
.LP
|
||||
.BI "VER_INFO_EXPORT(" Object_Name ", " Version ", " CVS_Tag ", " Src_File ", " Author " )"
|
||||
.RS 3
|
||||
.LP
|
||||
Cette macro est interpretee par le preprocesseur C.
|
||||
Elle permet de generer une fonction C qui exporte les informations de l'objet courant via les API internes de la librairie.
|
||||
.LP
|
||||
Cette macro doit recevoir les parametres suivants :
|
||||
.LP
|
||||
.RS 3
|
||||
- (In)
|
||||
.I Object_Name
|
||||
: le nom de l'objet (sans guillemets car utilise pour generer le nom de la fonction)
|
||||
.LP
|
||||
- (In)
|
||||
.I Version
|
||||
: la version de l'objet (entre guillemets)
|
||||
.LP
|
||||
- (In)
|
||||
.I CVS_Tag
|
||||
: le tag CVS (entre guillemets)
|
||||
.LP
|
||||
- (In)
|
||||
.I Src_File
|
||||
: le nom du fichier source (entre guillemets)
|
||||
.LP
|
||||
- (In)
|
||||
.I Author
|
||||
: le nom de l'auteur du fichier (entre guillemets)
|
||||
.RS -3
|
||||
.LP
|
||||
.I NB
|
||||
: la macro attend des parametres separes par des virgules.
|
||||
.LP
|
||||
Chaque fichier voulant exporter ses informations doit definir une instruction ressemblant a ce qui suit :
|
||||
.LP
|
||||
.RS 3
|
||||
VER_INFO_EXPORT(terminator, "1.0", "tag-schwartzy-1_0_0-1", "terminator.c", "Sarah Connors")
|
||||
.RS -3
|
||||
.LP
|
||||
L'instruction pourra se baser sur des mots-cle du preprocesseur ou sur ceux de CVS :
|
||||
.LP
|
||||
.RS 3
|
||||
VER_INFO_EXPORT(monobjet, "$ Revision $", "$ Name $", __FILE__, "$ Author $")
|
||||
.RS -3
|
||||
.LP
|
||||
.RS -3
|
||||
.LP
|
||||
.BI "VERT_Status VER_Object_Print ( FILE * " Out ", VERT_Print_Mode " Print_Mode " );"
|
||||
.RS 3
|
||||
.LP
|
||||
Cette fonction permet d'afficher les informations concernant l'objet appelant:
|
||||
.LP
|
||||
Elle doit recevoir les parametres suivants :
|
||||
.LP
|
||||
.RS 3
|
||||
- (In)
|
||||
.I Out
|
||||
: le flux de sortie de l'affichage
|
||||
.LP
|
||||
- (In)
|
||||
.I Print_Mode
|
||||
: le mode d'affichage :
|
||||
.LP
|
||||
.RS 3
|
||||
-
|
||||
.B VERD_MINIMAL
|
||||
: affichage du nom, de la version et du tag CVS de l'objet appelant.
|
||||
.LP
|
||||
-
|
||||
.B VERD_VERBOSE
|
||||
: affichage sous forme de tableau de toutes les informations de l'objet appelant et de tous les objets dont il depend.
|
||||
.LP
|
||||
.RS -3
|
||||
.RS -3
|
||||
.RS -3
|
||||
.LP
|
||||
.BI "VERT_Status VER_Info_Next_Get(VERT_Info_Container ** " Container ", VERT_Object * " Object ", VERT_Index * " Index " );"
|
||||
.RS 3
|
||||
.LP
|
||||
Cette fonction permet de recuperer un conteneur d'informations.
|
||||
.LP
|
||||
Elle doit recevoir les parametres suivants :
|
||||
.LP
|
||||
.RS 3
|
||||
- (Out)
|
||||
.I Container
|
||||
: l'adresse d'un pointeur sur le conteneur a recuperer
|
||||
.LP
|
||||
- (In Out)
|
||||
.I Object
|
||||
: un pointeur sur l'objet a partir duquel on recherche le conteneur
|
||||
.LP
|
||||
- (In Out)
|
||||
.I Index
|
||||
: un pointeur sur l'index a partir duquel on recherche le conteneur
|
||||
.LP
|
||||
.RS -3
|
||||
.LP
|
||||
.I NB
|
||||
: un objet peut avoir plusieurs conteneurs s'il a ete construit a partir de plusieurs objets statiques (.o).
|
||||
.LP
|
||||
L'index permet de distinguer les differents conteneurs d'un meme objet. Il commence a 0.
|
||||
.LP
|
||||
Le premier objet correspond a l'objet appelant (deuxieme parametre valorise a NULL).
|
||||
.LP
|
||||
Les objets suivants sont des objets partages (.so) dont depend l'objet appelant.
|
||||
.LP
|
||||
Si un conteneur a pu etre trouve, l'objet et l'index correspondant a ce conteneur sont alors mis a jour.
|
||||
.LP
|
||||
.RS -3
|
||||
.BI "VERT_Status VER_Info_Print(FILE * " Out ", VERT_Info_Container * " Container ", VERT_Print_Mode " Print_Mode " );"
|
||||
.RS 3
|
||||
.LP
|
||||
Cette fonction permet d'afficher les informations d'un conteneur :
|
||||
.LP
|
||||
Elle doit recevoir les parametres suivants :
|
||||
.LP
|
||||
.RS 3
|
||||
- (In)
|
||||
.I Out
|
||||
: le flux de sortie de l'affichage
|
||||
.LP
|
||||
- (In)
|
||||
.I Container
|
||||
: un pointeur sur le conteneur a afficher
|
||||
.LP
|
||||
- (In)
|
||||
.I Print_Mode
|
||||
: le mode d'affichage :
|
||||
.LP
|
||||
.RS 3
|
||||
-
|
||||
.B VERD_MINIMAL
|
||||
: affichage du nom, de la version et du tag CVS du conteneur
|
||||
.LP
|
||||
-
|
||||
.B VERD_VERBOSE
|
||||
: affichage de toutes les informations du conteneur
|
||||
.LP
|
||||
.RS -3
|
||||
.RS -3
|
||||
.RS -3
|
||||
.SH CODES RETOUR
|
||||
.LP
|
||||
Toutes les fonctions constituant l'API de la librairie LIBVER retournent un code de type
|
||||
.B VERT_Status
|
||||
:
|
||||
.LP
|
||||
.RS 3
|
||||
-
|
||||
.B VERS_OK
|
||||
: la fonction s'est correctement executee et a produit un resultat
|
||||
.LP
|
||||
-
|
||||
.B VERS_KO
|
||||
: la fonction s'est correctement executee mais n'a pas produit de resultat
|
||||
.LP
|
||||
-
|
||||
.B VERS_ERRAPI
|
||||
: la fonction a ete appelee avec des arguments de valeur incorrecte
|
||||
.LP
|
||||
-
|
||||
.B VERS_ERRMEM
|
||||
: la fonction ne s'est pas correctement executee pour un probleme d'allocation memoire
|
||||
.RS -3
|
||||
.LP
|
||||
La macro
|
||||
.B VER_ERROR(rc)
|
||||
permet de tester si un code retour correspond a une erreur.
|
||||
.LP
|
||||
En cas d'erreur, la variable VER_Error_Msg contient un message du type :
|
||||
.LP
|
||||
.RS 3
|
||||
Error <Nom fonction> : <message d'erreur>
|
||||
.RS -3
|
||||
.LP
|
BIN
doc/libver.doc
Normal file
BIN
doc/libver.doc
Normal file
Binary file not shown.
561
lib/libver.c
Normal file
561
lib/libver.c
Normal file
@ -0,0 +1,561 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#ifdef LINUX
|
||||
#else
|
||||
#include <libelf.h>
|
||||
#endif
|
||||
#include <dlfcn.h>
|
||||
#include <ver.h>
|
||||
|
||||
VER_INFO_EXPORT (libver, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $")
|
||||
|
||||
void VER_Error_Print (void);
|
||||
void * VER_Symbol_Next_Find (const char *, VERT_Object *, VERT_Index *);
|
||||
extern char * strdup (const char *);
|
||||
|
||||
#ifdef LINUX
|
||||
extern struct r_scope_elem *_dl_global_scope [2];
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Création d'un conteneur d'informations */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (O) Contanier : adresse d'un pointeur sur le container à créer */
|
||||
/* (I) Object_Name : nom de l'objet */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Init (VERT_Info_Container ** Container, const char * Object_Name)
|
||||
{
|
||||
*Container = (VERT_Info_Container *) malloc (sizeof (VERT_Info_Container));
|
||||
|
||||
if (*Container == NULL)
|
||||
{
|
||||
sprintf (VER_Error_Msg, "Error VER_Info_Init : unable to allocate memory for a container");
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRMEM;
|
||||
}
|
||||
|
||||
if (Object_Name != NULL)
|
||||
(*Container)->name = strdup (Object_Name);
|
||||
else
|
||||
(*Container)->name = NULL;
|
||||
|
||||
(*Container)->version = NULL;
|
||||
(*Container)->tag = NULL;
|
||||
(*Container)->srcfile = NULL;
|
||||
(*Container)->author = NULL;
|
||||
|
||||
return VERS_OK;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Mise à jour d'une information */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Container : pointeur sur le conteneur d'informations */
|
||||
/* (I) Info_Type : type d'information à mettre à jour */
|
||||
/* (I) Value : valeur de l'information */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Set (VERT_Info_Container * Container, VERT_Info Info_Type, const char * Value)
|
||||
{
|
||||
char * tmp;
|
||||
|
||||
if (Container == NULL)
|
||||
{
|
||||
sprintf (VER_Error_Msg, "Error VER_Info_Set : the container is null");
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
if (Value == NULL)
|
||||
{
|
||||
sprintf (VER_Error_Msg, "Error VER_Info_Set : the value is null");
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
switch ((int)Info_Type)
|
||||
{
|
||||
case VERD_VERSION:
|
||||
|
||||
if (!strncmp (Value, "$Revision: ", 11))
|
||||
{
|
||||
char * ptr;
|
||||
|
||||
tmp = strdup (Value + 11);
|
||||
|
||||
if ((ptr = strchr (tmp, ' ')) != NULL) *ptr = '\0';
|
||||
}
|
||||
else
|
||||
tmp = strdup (Value);
|
||||
|
||||
if (!tmp) return VERS_ERRMEM;
|
||||
|
||||
if (Container->version != NULL) free (Container->version);
|
||||
|
||||
Container->version = tmp;
|
||||
|
||||
break;
|
||||
|
||||
case VERD_TAG:
|
||||
|
||||
if (!strncmp (Value, "$Name: ", 7))
|
||||
{
|
||||
char * ptr;
|
||||
|
||||
tmp = strdup (Value + 7);
|
||||
|
||||
if ((ptr = strchr (tmp, ' ')) != NULL) *ptr = '\0';
|
||||
}
|
||||
else
|
||||
tmp = strdup (Value);
|
||||
|
||||
if (!tmp) return VERS_ERRMEM;
|
||||
|
||||
if (Container->tag != NULL) free (Container->tag);
|
||||
|
||||
Container->tag = tmp;
|
||||
|
||||
break;
|
||||
|
||||
case VERD_SRCFILE:
|
||||
|
||||
tmp = strdup (Value);
|
||||
|
||||
if (!tmp) return VERS_ERRMEM;
|
||||
|
||||
if (Container->srcfile != NULL) free (Container->srcfile);
|
||||
|
||||
Container->srcfile = tmp;
|
||||
|
||||
break;
|
||||
|
||||
case VERD_AUTHOR:
|
||||
|
||||
if (!strncmp (Value, "$Author: ", 9))
|
||||
{
|
||||
char * ptr;
|
||||
|
||||
tmp = strdup (Value + 9);
|
||||
|
||||
if (!tmp) return VERS_ERRMEM;
|
||||
|
||||
if ((ptr = strchr (tmp, ' ')) != NULL) *ptr = '\0';
|
||||
}
|
||||
else
|
||||
tmp = strdup (Value);
|
||||
|
||||
if (!tmp) return VERS_ERRMEM;
|
||||
|
||||
if (Container->author != NULL) free (Container->author);
|
||||
|
||||
Container->author = tmp;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
sprintf (VER_Error_Msg, "Error VER_Info_Set : unexpected type %d", (int)Info_Type);
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
return VERS_OK;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Effacement d'une information */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Container : pointeur sur le conteneur d'informations */
|
||||
/* (I) Info_Type : type d'information à effacer */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Clean (VERT_Info_Container * Container, VERT_Info Info_Type)
|
||||
{
|
||||
if (Container == NULL)
|
||||
{
|
||||
sprintf (VER_Error_Msg, "Error VER_Info_Clean : the container is null");
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
switch ((int)Info_Type)
|
||||
{
|
||||
case VERD_VERSION:
|
||||
|
||||
if (Container->version != NULL) free (Container->version);
|
||||
|
||||
break;
|
||||
|
||||
case VERD_TAG:
|
||||
|
||||
if (Container->tag != NULL) free (Container->tag);
|
||||
|
||||
break;
|
||||
|
||||
case VERD_SRCFILE:
|
||||
|
||||
if (Container->srcfile != NULL) free (Container->srcfile);
|
||||
|
||||
break;
|
||||
|
||||
case VERD_AUTHOR:
|
||||
|
||||
if (Container->author != NULL) free (Container->author);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf (VER_Error_Msg, "Error VER_Info_Clean : unexpected type %d", (int)Info_Type);
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Destruction d'un container d'informations */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Container : pointeur sur le conteneur d'informations */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_End (VERT_Info_Container * Container)
|
||||
{
|
||||
if (Container == NULL)
|
||||
{
|
||||
sprintf (VER_Error_Msg, "Error VER_Info_End : the container is null");
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
if (Container->name != NULL) free (Container->name);
|
||||
|
||||
if (Container->version != NULL) free (Container->version);
|
||||
|
||||
if (Container->tag != NULL) free (Container->tag);
|
||||
|
||||
if (Container->srcfile != NULL) free (Container->srcfile);
|
||||
|
||||
if (Container->author != NULL) free (Container->author);
|
||||
|
||||
free (Container);
|
||||
|
||||
return VERS_OK;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Affichage des informations d'un conteneur */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Stream : pointeur sur le flux de sortie */
|
||||
/* (I) Container : pointeur sur le conteneur d'informations */
|
||||
/* (I) Mode : mode d'affichage */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Print (FILE * Stream, VERT_Info_Container * Container, VERT_Print_Mode Mode)
|
||||
{
|
||||
if (Stream == NULL)
|
||||
{
|
||||
sprintf (VER_Error_Msg, "Error VER_Info_Print : the file descriptor is null");
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
if (Container == NULL)
|
||||
{
|
||||
sprintf (VER_Error_Msg, "Error VER_Info_Print : the container is null");
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
if (Mode == VERD_MINIMAL)
|
||||
fprintf (Stream, "%-20s%-20s%-30s\n",
|
||||
Container->name ? Container->name : "???",
|
||||
Container->version ? Container->version : "",
|
||||
Container->tag ? Container->tag : "");
|
||||
else
|
||||
fprintf (Stream, "%-20s%-20s%-30s%-30s%-20s\n",
|
||||
Container->name ? Container->name : "???",
|
||||
Container->version ? Container->version : "",
|
||||
Container->tag ? Container->tag : "",
|
||||
Container->srcfile ? Container->srcfile : "",
|
||||
Container->author ? Container->author : "");
|
||||
|
||||
return VERS_OK;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Récupération d'un conteneur d'informations */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (O) Container : adresse d'un pointeur sur le conteneur d'informations */
|
||||
/* (I) Object : objet dans lequel on effectue la recherche */
|
||||
/* (I) Index : pointeur d'index à partir duquel on effectue la recherche */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Next_Get (VERT_Info_Container ** Container, VERT_Object * Object, VERT_Index * Index)
|
||||
{
|
||||
void * Ptr = VER_Symbol_Next_Find (VER_FCN_NAME, Object, Index);
|
||||
VERT_Fcn * Ptr_Fcn = (VERT_Fcn *)Ptr;
|
||||
|
||||
if (Ptr == NULL) return VERS_KO;
|
||||
|
||||
*Container = (VERT_Info_Container *)(*Ptr_Fcn)();
|
||||
|
||||
if (*Container == NULL) return VERS_ERRMEM;
|
||||
|
||||
return VERS_OK;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Affichage des informations exportées par l'objet courant */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Stream : pointeur sur le flux de sortie */
|
||||
/* (I) Mode : mode d'affichage */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Object_Print (FILE * Stream, VERT_Print_Mode Mode)
|
||||
{
|
||||
VERT_Status Nb_Object = 0;
|
||||
VERT_Info_Container * Container;
|
||||
VERT_Object * Object;
|
||||
char sep [120];
|
||||
VERT_Index Index;
|
||||
void * Handle;
|
||||
|
||||
if (Stream == NULL)
|
||||
{
|
||||
sprintf (VER_Error_Msg, "Error VER_Object_Print : the file descriptor is null");
|
||||
VER_Error_Print ();
|
||||
return VERS_ERRAPI;
|
||||
}
|
||||
|
||||
/* Affichage sous forme de tableau en option 'verbose' */
|
||||
|
||||
if (Mode == VERD_VERBOSE)
|
||||
{
|
||||
memset (sep, '-', sizeof (sep));
|
||||
sep [sizeof (sep) -1] = '\0';
|
||||
fprintf (stdout, "%-20s%-20s%-30s%-30s%-20s\n%s\n", "OBJECT NAME", "VERSION", "TAG", "SOURCE FILE", "AUTHOR", sep);
|
||||
}
|
||||
|
||||
/* Info : on distingue deus types d'objets :
|
||||
|
||||
- un premier objet (objet principal) qui correspond à ce qui est chargé par le loader
|
||||
au lancement du programme : programme principal + objets statiques (.o)
|
||||
|
||||
- autant d'objets qui ont chargés dynamiquement par le linker (.so)
|
||||
*/
|
||||
|
||||
/* On commence par récupèrer l'objet principal */
|
||||
|
||||
Handle = dlopen (NULL, RTLD_LAZY);
|
||||
|
||||
#ifdef LINUX
|
||||
/*
|
||||
Sous LINUX, le linker définit une variable globale bien pratique qui référence
|
||||
la liste des objets linkés dynamiquement.
|
||||
*/
|
||||
|
||||
Object = ((struct r_scope_elem *)(_dl_global_scope [0]))->r_list [0];
|
||||
#else
|
||||
/*
|
||||
Sous SOLARIS, on doit faire appel à la fonction dlinfo() pour obtenir
|
||||
les informations de link pour l'objet principal.
|
||||
|
||||
NB : cette fonction n'existe pas sous LINUX.
|
||||
*/
|
||||
|
||||
Object = (VERT_Object *)malloc (sizeof (VERT_Object));
|
||||
dlinfo (Handle, RTLD_DI_LINKMAP, &Object);
|
||||
#endif
|
||||
|
||||
/* Recherche d'informations dans tous les objets linkés */
|
||||
|
||||
Index = 0;
|
||||
|
||||
while (Object != NULL)
|
||||
{
|
||||
if (VER_Info_Next_Get (&Container, Object, &Index) == VERS_OK)
|
||||
{
|
||||
Nb_Object++;
|
||||
|
||||
/*
|
||||
Définition du nom de l'objet : on ajoute '.o' ou '.so'
|
||||
selon qu'il s'agit du premier objet chargé ou non.
|
||||
*/
|
||||
|
||||
if (Container->name)
|
||||
{
|
||||
if (Object->l_prev != NULL)
|
||||
{
|
||||
if ((Container->name = (char *)realloc (Container->name, strlen (Container->name) + 4)) != NULL)
|
||||
sprintf (Container->name, "%s.so", Container->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Container->name = (char *)realloc (Container->name, strlen (Container->name) + 3)) != NULL)
|
||||
sprintf (Container->name, "%s.o", Container->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Affichage complet des informations récupérées */
|
||||
|
||||
VER_Info_Print (Stream, Container, Mode);
|
||||
|
||||
/* Désallocation des informations */
|
||||
|
||||
VER_Info_End (Container);
|
||||
|
||||
/* Recherche du symbole suivant dans le même objet */
|
||||
|
||||
Index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* En mode affichage minimal, on s'arrête après l'objet principal */
|
||||
|
||||
if (Object->l_prev == NULL && Mode == VERD_MINIMAL)
|
||||
Object = NULL;
|
||||
else
|
||||
{
|
||||
/* Recherche dans l'objet suivant */
|
||||
|
||||
Object = Object->l_next;
|
||||
Index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Nb_Object;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Fonctions privées */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/*------------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Recherche d'un symbole dans les tables de symboles des objets linkés : */
|
||||
/* */
|
||||
/* (I) Symbol_Name : nom de symbole à rechercher */
|
||||
/* (O) Object : objet dans lequel on recherche le symbole */
|
||||
/* (I) Index : pointeur sur l'index à partir duquel on recherche */
|
||||
/* */
|
||||
/* Retourne la référence du symbole trouvé, NULL si non trouvé. */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
void * VER_Symbol_Next_Find (const char * Symbol_Name, VERT_Object * Object, VERT_Index * Index)
|
||||
{
|
||||
unsigned long Offset;
|
||||
|
||||
/* Recherche dans l'objet passé en paramètre */
|
||||
|
||||
if (Object != NULL)
|
||||
{
|
||||
VERT_Index * Hash_Table, Nb_Symbol;
|
||||
Elf32_Sym * Symbol_Table;
|
||||
char * String_Table;
|
||||
Elf32_Sym * Symbol;
|
||||
int i, Found;
|
||||
|
||||
/* Définition de l'offset pour interpréter les adresses virtuelles */
|
||||
|
||||
/*
|
||||
Les adresses données dans les sections sont virtuelles : on doit leur ajouter
|
||||
un offset défini dans l'entête de l'objet. Ceci n'est toutefois pas vrai pour l'objet principal.
|
||||
*/
|
||||
|
||||
if (Object->l_prev == NULL)
|
||||
Offset = 0; /* Pas d'offset pour l'objet principal */
|
||||
else
|
||||
Offset = Object->l_addr; /* Offset non nul pour les objets partagés */
|
||||
|
||||
/* Recherche des sections relatives aux symboles */
|
||||
|
||||
#ifdef LINUX
|
||||
/* Sous LINUX, les sections sont directement accessibles par le champs <l_info> de l'entête de l'objet */
|
||||
|
||||
Symbol_Table = (Elf32_Sym *)(Object->l_info [DT_SYMTAB]->d_un.d_ptr);
|
||||
|
||||
String_Table = (char *)(Object->l_info [DT_STRTAB]->d_un.d_ptr);
|
||||
|
||||
/*
|
||||
Le nombre de symboles peut lui-aussi être retrouvé à partir de l'entête de l'objet.
|
||||
En effet, l'entête contient un champ <l_buckets> qui pointe sur la donnée <bucket> de la section HASH.
|
||||
Connaissant la structure de l'entête de la section HASH, on retrouve facilement la donnée <nchain>.
|
||||
*/
|
||||
|
||||
Nb_Symbol = *(VERT_Index *)((size_t)(Object->l_buckets) - sizeof (VERT_Index));
|
||||
#else
|
||||
/*
|
||||
Sous SOLARIS, le champs <l_info> n'existe pas.
|
||||
Il faut donc parcourir toutes les sections pour trouver celles qui nous intéressent.
|
||||
*/
|
||||
|
||||
i = 0;
|
||||
Found = 0;
|
||||
while (Found < 3)
|
||||
{
|
||||
switch ((int)Object->l_ld [i].d_tag)
|
||||
{
|
||||
case DT_HASH:
|
||||
|
||||
/* La section HASH nous intéressent car elle contient le nombre de symboles */
|
||||
|
||||
Hash_Table = (VERT_Index *)(Object->l_ld [i].d_un.d_ptr + Offset);
|
||||
Nb_Symbol = Hash_Table [1]; /* Donnée <nchain> */
|
||||
Found++;
|
||||
break;
|
||||
|
||||
case DT_SYMTAB:
|
||||
|
||||
/* La section SYMTAB référence les symboles de l'objet courant */
|
||||
|
||||
Symbol_Table = (Elf32_Sym *)(Object->l_ld [i].d_un.d_ptr + Offset);
|
||||
Found++;
|
||||
break;
|
||||
|
||||
case DT_STRTAB:
|
||||
|
||||
/*
|
||||
La section STRTAB contient les chaînes de caractères qui sont référencées
|
||||
par les autres sections (notamment les noms de symboles).
|
||||
*/
|
||||
|
||||
String_Table = (char *)(Object->l_ld [i].d_un.d_ptr + Offset);
|
||||
Found++;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Les autres sections ne nous intéressent pas */
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Recherche dans la table des symboles à partir de l'index passé en paramètre */
|
||||
|
||||
while ((*Index) < Nb_Symbol)
|
||||
{
|
||||
Symbol = &Symbol_Table [*Index];
|
||||
|
||||
/* On recherche une fonction qui correspond au nom passé en paramètre */
|
||||
|
||||
if (Symbol->st_value != 0 && ELF32_ST_TYPE (Symbol->st_info) <= STT_FUNC && !strncmp (String_Table + Symbol->st_name, Symbol_Name, strlen (Symbol_Name)))
|
||||
return (void *)(Symbol->st_value + Offset);
|
||||
|
||||
(*Index)++;
|
||||
}
|
||||
|
||||
/* Aucun symbole n'a été trouvé */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Routine d'affichage d'un message d'erreur */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
void VER_Error_Print (void)
|
||||
{
|
||||
fprintf (stderr, VER_Error_Msg);
|
||||
}
|
||||
|
134
lib/ver.h
Normal file
134
lib/ver.h
Normal file
@ -0,0 +1,134 @@
|
||||
#ifndef _LIBVER
|
||||
#define _LIBVER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef LINUX
|
||||
#include <link.h>
|
||||
#else
|
||||
#include <sys/link.h>
|
||||
#endif
|
||||
|
||||
typedef int VERT_Info;
|
||||
|
||||
#define VERD_VERSION 1
|
||||
#define VERD_TAG 2
|
||||
#define VERD_SRCFILE 3
|
||||
#define VERD_AUTHOR 4
|
||||
|
||||
typedef int VERT_Print_Mode;
|
||||
|
||||
#define VERD_VERBOSE 1
|
||||
#define VERD_MINIMAL 2
|
||||
|
||||
typedef int VERT_Status;
|
||||
|
||||
#define VER_ERROR(s) (s < 0) /* Tous les codes retour négatifs correspondent à des erreurs */
|
||||
|
||||
#define VERS_OK 1
|
||||
#define VERS_KO 0
|
||||
#define VERS_ERRMEM -1 /* Problème d'allocation mémoire */
|
||||
#define VERS_ERRAPI -2 /* Utilisation incorrecte des API */
|
||||
|
||||
typedef struct {
|
||||
char * name;
|
||||
char * version;
|
||||
char * tag;
|
||||
char * srcfile;
|
||||
char * author;
|
||||
} VERT_Info_Container;
|
||||
|
||||
typedef VERT_Info_Container * VERT_Fcn (void);
|
||||
|
||||
typedef struct link_map VERT_Object;
|
||||
|
||||
typedef unsigned int VERT_Index;
|
||||
|
||||
#define VER_FCN_NAME "VER_Info_Export"
|
||||
|
||||
#define INIT(x) VERT_Info_Container * Container; VER_Info_Init (&Container, x);
|
||||
#define VERSION(x) if (Container) VER_Info_Set(Container,VERD_VERSION, x);
|
||||
#define TAG(x) if (Container) VER_Info_Set(Container,VERD_TAG, x);
|
||||
#define SRCFILE(x) if (Container) VER_Info_Set(Container,VERD_SRCFILE, x);
|
||||
#define AUTHOR(x) if (Container) VER_Info_Set(Container,VERD_AUTHOR, x);
|
||||
#define VER_INFO_EXPORT(obj,ver,tag,file,author) \
|
||||
VERT_Info_Container * VER_Info_Export_##obj (void); \
|
||||
VERT_Info_Container * VER_Info_Export_##obj (void) \
|
||||
{ \
|
||||
INIT(#obj) \
|
||||
VERSION(ver) \
|
||||
TAG(tag) \
|
||||
SRCFILE(file) \
|
||||
AUTHOR(author) \
|
||||
return (Container); \
|
||||
}
|
||||
|
||||
char VER_Error_Msg [256];
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Affichage des informations exportées par l'objet courant */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Stream : pointeur sur le flux de sortie */
|
||||
/* (I) Mode : mode d'affichage */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Object_Print (FILE * Stream, VERT_Print_Mode Mode);
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Récupération d'un conteneur d'informations */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (O) Container : adresse d'un pointeur sur le conteneur d'informations */
|
||||
/* (I) Object : objet dans lequel on effectue la recherche */
|
||||
/* (I) Index : pointeur d'index à partir duquel on effectue la recherche */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Next_Get (VERT_Info_Container ** Container, VERT_Object * Object, VERT_Index * Index);
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Affichage des informations d'un conteneur */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Stream : pointeur sur le flux de sortie */
|
||||
/* (I) Container : pointeur sur le conteneur d'informations */
|
||||
/* (I) Mode : mode d'affichage */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Print (FILE * Stream, VERT_Info_Container * Container, VERT_Print_Mode Mode);
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Création d'un conteneur d'informations */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (O) Contanier : adresse d'un pointeur sur le container à créer */
|
||||
/* (I) Object_Name : nom de l'objet */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Init (VERT_Info_Container ** Container, const char * Object_Name);
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Mise à jour d'une information */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Container : pointeur sur le conteneur d'informations */
|
||||
/* (I) Info_Type : type d'information à mettre à jour */
|
||||
/* (I) Value : valeur de l'information */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Set (VERT_Info_Container * Container, VERT_Info Info_Type, const char * Value);
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Effacement d'une information */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Container : pointeur sur le conteneur d'informations */
|
||||
/* (I) Info_Type : type d'information à effacer */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_Clean (VERT_Info_Container * Container, VERT_Info Info_Type);
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* Destruction d'un container d'informations */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
/* (I) Container : pointeur sur le conteneur d'informations */
|
||||
/*------------------------------------------------------------------------------*/
|
||||
VERT_Status VER_Info_End (VERT_Info_Container * Container);
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user