objectFile.c

Go to the documentation of this file.
00001 /***************************************************************************/
00007 #include "objectFile.h"
00008 #include "hashmap.h"
00009 #include "graph.h"
00010 
00011 #include <stdlib.h>
00012 #include <string.h>
00013 #include <ctype.h>
00014 
00015 /* *************************************************************** structures */
00016 
00017 #define SO_FOUNDNAME     1
00018 #define SO_FOUNDSECTION  2
00019 
00020 #define SO_PREFIX_COUNT (sizeof(prefix)/sizeof(char*))
00021 #define SO_WEAK_COUNT  (sizeof(weak)/sizeof(char*))
00022 
00023 static const char* prefix[] =
00024     { ".text$", ".rdata$", ".data$" };
00025 static const char* weak[] =
00026     { ".rdata" };
00027 
00028 static hashmap* sectionMap = 0;
00029 static list* unknownSection = 0;
00030 
00033 struct s_objectFile
00034 {
00035     const char* name; 
00036     list* sects; 
00037 };
00038 
00039 /* ******************************************************** private functions */
00040 
00045 static char* trim(char* src)
00046 {
00047     while (isspace(*src))
00048         ++src;
00049     return src;
00050 }
00051 
00055 static void upper(char* src)
00056 {
00057     while (*src)
00058     {
00059         *src = toupper(*src);
00060         ++src;
00061     }
00062 }
00063 
00068 static void parseRelocSection(graph* src, FILE* file)
00069 {
00070     static char buffer[256];
00071     char *ptr, *token;
00072     
00073     while (!feof(file))
00074     {
00075         fgets(buffer, sizeof(buffer), file);
00076         ptr = trim(buffer);
00077         
00078         
00079         /* a blank line quits the table */
00080         if (!*ptr)
00081             return;
00082         
00083         /* skip OFFSET */
00084         token = strtok(ptr, " ");
00085         /* skip TYPE */
00086         token = strtok(0, " ");
00087         
00088         
00089         /* process VALUE */
00090         token = strtok(0, " ");
00091         
00092         if (token)
00093         {
00094             graph* dest;
00095             
00096             
00097             /* trim front-end */
00098             if (*token == '_')
00099                 ++token;
00100             /* FASTCALL convention */
00101             else if (*token == '@')
00102             {
00103                 ++token;
00104                 token = strtok(token, "@");
00105             }
00106             /* check for various prefixes */
00107             else
00108             {
00109                 int i = SO_PREFIX_COUNT;
00110                 
00111                 while (i--)
00112                     if (!strncmp(token, prefix[i], strlen(prefix[i])))
00113                     {
00114                         token += strlen(prefix[i]);
00115                         break;
00116                     }
00117             }
00118             
00119             /* trim back-end */
00120             {
00121                 char* i = token + strlen(token);
00122                 while (isspace(*--i));
00123                 
00124                 i[1] = 0;
00125                 
00126                 
00127                 /* watchout for STDCALL convention */
00128                 while (isdigit(*--i));
00129                 
00130                 if (*i == '@')
00131                     *i = 0;
00132             }
00133             
00134             dest = (graph*) hashmapGet(sectionMap, token);
00135             
00136             if (dest)
00137             {
00138                 /* normal dependency spotted - link engaged */
00139                 if (src)
00140                     graphConnect(src, dest);
00141                 
00142                 /* dependency with unknown section spotted; we need to calculate its
00143                  * dependencies as well, because this section will survive for sure
00144                  */
00145                 else
00146                     listAdd(unknownSection, dest);
00147             }
00148         }
00149     }
00150 }
00151 
00156 static void colorizeGraph(graph* seed, unsigned long color)
00157 {
00158     unsigned long c = graphGetColorNode(seed);
00159     if ((c | color) != c)
00160     {
00161         list* depends = graphGetConnections(seed);
00162         graphColorNode(seed, c | color);
00163         
00164         listStart(depends);
00165         while (listNext(depends))
00166             colorizeGraph((graph*) listGet(depends), color);
00167     }
00168 }
00169 
00170 /* ******************************************************* exported functions */
00171 
00172 objectFile* objectFileCreate(const char* name)
00173 {
00174     objectFile* res = (objectFile*) malloc(sizeof(objectFile));
00175     
00176     res->name = name;
00177     res->sects = newList();
00178     
00179     return res;
00180 }
00181 
00182 void objectFileCollect(objectFile* src, FILE* file)
00183 {
00184     unsigned long progress = 0;
00185     char buffer[256], *ptr, *token;
00186     
00187     while (!feof(file))
00188     {
00189         fgets(buffer, sizeof(buffer), file);
00190         ptr = trim(buffer);
00191         
00192         if (*ptr)
00193         {
00194             switch (progress)
00195             {
00196             case 0: /* search for the filename */
00197                 token = strtok(ptr, ":");
00198                 if (token && !strcmp(token, src->name))
00199                     progress = SO_FOUNDNAME;
00200                 break;
00201                 
00202                 
00203             case SO_FOUNDNAME: /* search for the section keyword */
00204                 token = strtok(ptr, ":");
00205                 if (token)
00206                 {
00207                     upper(token);
00208                     if (!strcmp(token, "SECTIONS"))
00209                     {
00210                         fgets(buffer, sizeof(buffer), file);
00211                         progress = SO_FOUNDSECTION;
00212                     }
00213                 }
00214                 break;
00215                 
00216                 
00217             case SO_FOUNDSECTION: /* march through the section table */
00218                 token = strtok(ptr, " ");
00219                 
00220                 if (token)
00221                 {
00222                     token = strtok(0, " ");
00223                     if (token)
00224                     {
00225                         int i = SO_PREFIX_COUNT;
00226                         
00227                         
00228                         /* lookout for various prefixes */
00229                         while (i--)
00230                             if (!strncmp(token, prefix[i], strlen(prefix[i])))
00231                             {
00232                                 listAdd(src->sects, strdup(token));
00233                                 break;
00234                             }
00235                     }
00236                 }
00237             }
00238         }
00239         /* a blank line indicates the end of the section table */
00240         else if (progress == SO_FOUNDSECTION)
00241             return;
00242     }
00243 }
00244 
00245 void objectFileCompute(list* oFiles, FILE* file)
00246 {
00247     objectFile* cFile;
00248     
00249     /* check for older runs... just to be clean */
00250     if (sectionMap)
00251         deleteHashmap(sectionMap);
00252     if (unknownSection)
00253         deleteList(unknownSection);
00254     
00255     sectionMap = newHashmap(8);
00256     unknownSection = newList();
00257     
00258     
00259     /* insert all functions and data */
00260     listStart(oFiles);
00261     while (listNext(oFiles))
00262     {
00263         cFile = (objectFile*) listGet(oFiles);
00264         if (!listIsEmpty(cFile->sects))
00265         {
00266             listStart(cFile->sects);
00267             while (listNext(cFile->sects))
00268             {
00269                 char *token, *ptr;
00270                 int i = SO_PREFIX_COUNT;
00271                 ptr = token = (char*) listGet(cFile->sects);
00272                 
00273                 /* skip the prefix for key generation
00274                  (needed when reading the relocation table)*/
00275                 while (i--)
00276                     if (!strncmp(token, prefix[i], strlen(prefix[i])))
00277                     {
00278                         ptr += strlen(prefix[i]);
00279                         listSet(cFile->sects, ptr);
00280                         break;
00281                     }
00282                 
00283                 /* test if the entry already exists */
00284                 if (!hashmapGet(sectionMap, ptr))
00285                     hashmapSet(sectionMap, newGraph(token), ptr);
00286             }
00287         }
00288     }
00289     
00290     /* parse the file */
00291     {
00292         char buffer[256], *ptr, *token;
00293         graph* cGraph;
00294         
00295         while (!feof(file))
00296         {
00297             ParseLoop: fgets(buffer, sizeof(buffer), file);
00298             ptr = trim(buffer);
00299             
00300             if (*ptr)
00301             {
00302                 token = strtok(ptr, ":");
00303                 if (token)
00304                 {
00305                     /* look for the relocation keyword */
00306                     if (!strncmp(token, "RELOCATION", sizeof("RELOCATION") - 1))
00307                     {
00308                         int i;
00309                         
00310                         /* get the name */
00311                         token += sizeof("RELOCATION");
00312                         while (*token && *token++ != '[');
00313                         
00314                         /* just to be sure */
00315                         if (!*token)
00316                         {
00317                             fprintf(stderr, "ERROR: file with relocation table "
00318                                 "has invalid format!\n");
00319                             return;
00320                         }
00321                         
00322                         /* we could easily search for the '$', but that would create
00323                          more dependencies to the compilers naming conventions */
00324                         i = SO_PREFIX_COUNT;
00325                         while (i--)
00326                             if (!strncmp(token, prefix[i], strlen(prefix[i])))
00327                             {
00328                                 token += strlen(prefix[i]);
00329                                 break;
00330                             }
00331                         
00332                         token = strtok(token, "]");
00333                         
00334                         
00335                         /* just to be sure */
00336                         if (!token)
00337                         {
00338                             fprintf(stderr, "ERROR: file with relocation table "
00339                                     "has invalid format!\n");
00340                             return;
00341                         }
00342                         
00343                         cGraph = (graph*) hashmapGet(sectionMap, token);
00344                         
00345                         if (!cGraph)
00346                         {
00347                             /* test for weak sections */
00348                             i = SO_WEAK_COUNT;
00349                             while (i--)
00350                                 if (!strcmp(token, weak[i]))
00351                                     goto ParseLoop;
00352                         }
00353                         
00354                         /* skip the tables caption */
00355                         fgets(buffer, sizeof(buffer), file);
00356                         
00357                         parseRelocSection(cGraph, file);
00358                     }
00359                 }
00360             }
00361         }
00362     }
00363     
00364     /* colorize the unknown section dependencies */
00365     
00366     /* this part may be optimized a bit by calculating their dependencies
00367      * as well, but I'm unsure if that wouldn't be too aggressive, removing
00368      * sections that may be needed somehow (when the linker adds code to the
00369      * final exe for example), so I left them in to be sure
00370      */
00371     listStart(unknownSection);
00372     while (listNext(unknownSection))
00373         colorizeGraph((graph*) listGet(unknownSection), 0x80000000);
00374 }
00375 
00376 void objectFileColorize(const char* seed, unsigned long color)
00377 {
00378     graph* start = (graph*) hashmapGet(sectionMap, seed);
00379     
00380     if (start)
00381         colorizeGraph(start, color);
00382 }
00383 
00384 list* objectFileGetUsed(objectFile* src)
00385 {
00386     list* res = newList();
00387     
00388     listStart(src->sects);
00389     while (listNext(src->sects))
00390     {
00391         char* name = (char*) listGet(src->sects);
00392         graph* curr = (graph*) hashmapGet(sectionMap, name);
00393         
00394         if (graphGetColorNode(curr))
00395             listAdd(res, graphGetNameNode(curr));
00396     }
00397     
00398     return res;
00399 }
00400 
00401 list* objectFileGetUnused(objectFile* src)
00402 {
00403     list* res = newList();
00404     
00405     listStart(src->sects);
00406     while (listNext(src->sects))
00407     {
00408         char* name = (char*) listGet(src->sects);
00409         graph* curr = (graph*) hashmapGet(sectionMap, name);
00410         
00411         if (!graphGetColorNode(curr))
00412             listAdd(res, graphGetNameNode(curr));
00413     }
00414     
00415     return res;
00416 }
00417 
00418 const char* objectFileGetName(objectFile* src)
00419 {
00420     return src->name;
00421 }
00422 
00423 void objectFileDumpMap(list* oFiles)
00424 {
00425     /* yay ^_^, what a loop */
00426     printf("\n<MAP>\n");
00427     listStart(oFiles);
00428     while (listNext(oFiles))
00429     {
00430         objectFile* oFile = (objectFile*) listGet(oFiles);
00431         printf("\t<FILE name=\"%s\">\n", oFile->name);
00432         fflush(stdout);
00433         
00434         listStart(oFile->sects);
00435         while (listNext(oFile->sects))
00436         {
00437             char* name = (char*) listGet(oFile->sects);
00438             graph* sect = (graph*) hashmapGet(sectionMap, name);
00439             list* depend = graphGetConnections(sect);
00440             
00441             printf("\t\t<SECTION name=\"%s\" color=%lu>\n",
00442                    (char*) graphGetNameNode(sect), graphGetColorNode(sect));
00443             fflush(stdout);
00444             
00445             listStart(depend);
00446             while (listNext(depend))
00447             {
00448                 graph* d = (graph*) listGet(depend);
00449                 printf("\t\t\t<DEPENDS>%s</DEPENDS>\n", (char*) graphGetNameNode(d));
00450                 fflush(stdout);
00451             }
00452             
00453             printf("\t\t</SECTION>\n");
00454             fflush(stdout);
00455         }
00456         printf("\t</FILE>\n");
00457         fflush(stdout);
00458     }
00459     printf("\n</MAP>\n");
00460     fflush(stdout);
00461 }
00462 
00463 void objectFileDumpUsed(list* oFiles)
00464 {
00465     printf("\n<USED>\n");
00466     
00467     listStart(oFiles);
00468     while (listNext(oFiles))
00469     {
00470         objectFile* obj = (objectFile*) listGet(oFiles);
00471         list* curr = objectFileGetUsed(obj);
00472         
00473         printf("\t<FILE name=\"%s\">\n", obj->name);
00474         
00475         listStart(curr);
00476         while (listNext(curr))
00477             printf("\t\t<SECTION>%s</SECTION>\n", (char*) listGet(curr));
00478         
00479         deleteList(curr);
00480         
00481         printf("\t</FILE>\n");
00482     }
00483     printf("</USED>\n");
00484 }
00485 
00486 void objectFileDumpUnused(list* oFiles)
00487 {
00488     printf("\n<UNUSED>\n");
00489     
00490     listStart(oFiles);
00491     while (listNext(oFiles))
00492     {
00493         objectFile* obj = (objectFile*) listGet(oFiles);
00494         list* curr = objectFileGetUnused(obj);
00495         
00496         printf("\t<FILE name=\"%s\">\n", obj->name);
00497         
00498         listStart(curr);
00499         while (listNext(curr))
00500             printf("\t\t<SECTION>%s</SECTION>\n", (char*) listGet(curr));
00501         
00502         deleteList(curr);
00503         
00504         printf("\t</FILE>\n");
00505     }
00506     printf("</UNUSED>\n");
00507 }

Generated on Fri Jun 5 15:31:57 2009 for DeadStrip Utility by  doxygen 1.5.8