• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
pm_init(const char * file)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 */
pm_report_library_size_in_memory(const char * name,off_t fsize)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 
pm_get_next_link_address(const char * lookup_name)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