Home | History | Annotate | Download | only in apriori
      1 #include <prelinkmap.h>
      2 #include <debug.h>
      3 #include <errno.h>
      4 #include <string.h>
      5 #include <libgen.h>
      6 #include <ctype.h>
      7 
      8 typedef struct mapentry mapentry;
      9 
     10 #define MAX_ALIASES 10
     11 
     12 struct mapentry
     13 {
     14     mapentry *next;
     15     unsigned base;
     16     char *names[MAX_ALIASES];
     17     int num_names;
     18 };
     19 
     20 static mapentry *maplist = 0;
     21 
     22 /* These values limit the address range within which we prelinked libraries
     23    reside.  The limit is not set in stone, but should be observed in the
     24    prelink map, or the prelink step will fail.
     25 */
     26 
     27 #define PRELINK_MIN 0x90000000
     28 #define PRELINK_MAX 0xBFFFFFFF
     29 
     30 void pm_init(const char *file)
     31 {
     32     unsigned line = 0;
     33     char buf[256];
     34     char *x;
     35     FILE *fp;
     36     mapentry *me;
     37     unsigned last = -1UL;
     38 
     39     fp = fopen(file, "r");
     40     FAILIF(fp == NULL, "Error opening file %s: %s (%d)\n",
     41            file, strerror(errno), errno);
     42 
     43     while(fgets(buf, 256, fp)){
     44         x = buf;
     45         line++;
     46 
     47         /* eat leading whitespace */
     48         while(isspace(*x)) x++;
     49 
     50         /* comment or blank line? skip! */
     51         if(*x == '#') continue;
     52         if(*x == 0) continue;
     53 
     54         /* skip name */
     55         while(*x && !isspace(*x)) x++;
     56 
     57         if(*x) {
     58             *x++ = 0;
     59             /* skip space before address */
     60             while(*x && isspace(*x)) x++;
     61         }
     62 
     63         /* no address? complain. */
     64         if(*x == 0) {
     65             fprintf(stderr,"warning: %s:%d no base address specified\n",
     66                     file, line);
     67             continue;
     68         }
     69 
     70         if (isalpha(*x)) {
     71             /* Assume that this is an alias, and look through the list of
     72                already-installed libraries.
     73             */
     74             me = maplist;
     75             while(me) {
     76                 /* The strlen() call ignores the newline at the end of x */
     77                 if (!strncmp(me->names[0], x, strlen(me->names[0]))) {
     78                     PRINT("Aliasing library %s to %s at %08x\n",
     79                           buf, x, me->base);
     80                     break;
     81                 }
     82                 me = me->next;
     83             }
     84             FAILIF(!me, "Nonexistent alias %s -> %s\n", buf, x);
     85         }
     86         else {
     87             unsigned n = strtoul(x, 0, 16);
     88             /* Note that this is not the only bounds check.  If a library's
     89                size exceeds its slot as defined in the prelink map, the
     90                prelinker will exit with an error.  See
     91                pm_report_library_size_in_memory().
     92             */
     93             FAILIF((n < PRELINK_MIN) || (n > PRELINK_MAX),
     94                    "%s:%d base 0x%08x out of range.\n",
     95                    file, line, n);
     96 
     97             me = malloc(sizeof(mapentry));
     98             FAILIF(me == NULL, "Out of memory parsing %s\n", file);
     99 
    100             FAILIF(last <= n, "The prelink map is not in descending order "
    101                    "at entry %s (%08x)!\n", buf, n);
    102             last = n;
    103 
    104             me->base = n;
    105             me->next = maplist;
    106             me->num_names = 0;
    107             maplist = me;
    108         }
    109 
    110         FAILIF(me->num_names >= MAX_ALIASES,
    111                "Too many aliases for library %s, maximum is %d.\n",
    112                me->names[0],
    113                MAX_ALIASES);
    114         me->names[me->num_names] = strdup(buf);
    115         me->num_names++;
    116     }
    117 
    118     fclose(fp);
    119 }
    120 
    121 /* apriori() calls this function when it determine the size of a library
    122    in memory.  pm_report_library_size_in_memory() makes sure that the library
    123    fits in the slot provided by the prelink map.
    124 */
    125 void pm_report_library_size_in_memory(const char *name,
    126                                       off_t fsize)
    127 {
    128     char *x;
    129     mapentry *me;
    130     int n;
    131 
    132     x = strrchr(name,'/');
    133     if(x) name = x+1;
    134 
    135     for(me = maplist; me; me = me->next){
    136         for (n = 0; n < me->num_names; n++) {
    137             if(!strcmp(name, me->names[n])) {
    138                 off_t slot = me->next ? me->next->base : PRELINK_MAX;
    139                 slot -= me->base;
    140                 FAILIF(fsize > slot,
    141                        "prelink map error: library %s@0x%08x is too big "
    142                        "at %lld bytes, it runs %lld bytes into "
    143                        "library %s@0x%08x!\n",
    144                        me->names[0], me->base, fsize, fsize - slot,
    145                        me->next->names[0], me->next->base);
    146                 return;
    147             }
    148         }
    149     }
    150 
    151     FAILIF(1, "library '%s' not in prelink map\n", name);
    152 }
    153 
    154 unsigned pm_get_next_link_address(const char *lookup_name)
    155 {
    156     char *x;
    157     mapentry *me;
    158     int n;
    159 
    160     x = strrchr(lookup_name,'/');
    161     if(x) lookup_name = x+1;
    162 
    163     for(me = maplist; me; me = me->next)
    164         for (n = 0; n < me->num_names; n++)
    165             if(!strcmp(lookup_name, me->names[n]))
    166                 return me->base;
    167 
    168     FAILIF(1, "library '%s' not in prelink map\n", lookup_name);
    169     return 0;
    170 }
    171