blob: 9fb00e4ad0d20311724864dd5f76e63e8b743a45 [file] [log] [blame]
The Android Open Source Project88b60792009-03-03 19:28:42 -08001#include <prelinkmap.h>
2#include <debug.h>
3#include <errno.h>
4#include <string.h>
5#include <libgen.h>
6#include <ctype.h>
7
8typedef struct mapentry mapentry;
9
Iliyan Malchevc87cb752009-03-25 18:09:52 -070010#define MAX_ALIASES 10
11
The Android Open Source Project88b60792009-03-03 19:28:42 -080012struct mapentry
13{
14 mapentry *next;
15 unsigned base;
Iliyan Malchevc87cb752009-03-25 18:09:52 -070016 char *names[MAX_ALIASES];
17 int num_names;
The Android Open Source Project88b60792009-03-03 19:28:42 -080018};
19
20static 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
Iliyan Malchevc87cb752009-03-25 18:09:52 -070028#define PRELINK_MAX 0xBFFFFFFF
The Android Open Source Project88b60792009-03-03 19:28:42 -080029
30void pm_init(const char *file)
31{
32 unsigned line = 0;
33 char buf[256];
34 char *x;
The Android Open Source Project88b60792009-03-03 19:28:42 -080035 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
Iliyan Malchevc87cb752009-03-25 18:09:52 -070070 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);
The Android Open Source Project88b60792009-03-03 19:28:42 -080096
Iliyan Malchevc87cb752009-03-25 18:09:52 -070097 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++;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800116 }
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*/
125void pm_report_library_size_in_memory(const char *name,
126 off_t fsize)
127{
128 char *x;
129 mapentry *me;
Iliyan Malchevc87cb752009-03-25 18:09:52 -0700130 int n;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800131
132 x = strrchr(name,'/');
133 if(x) name = x+1;
134
135 for(me = maplist; me; me = me->next){
Iliyan Malchevc87cb752009-03-25 18:09:52 -0700136 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 }
The Android Open Source Project88b60792009-03-03 19:28:42 -0800148 }
149 }
150
Iliyan Malchevc87cb752009-03-25 18:09:52 -0700151 FAILIF(1, "library '%s' not in prelink map\n", name);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800152}
153
154unsigned pm_get_next_link_address(const char *lookup_name)
155{
156 char *x;
157 mapentry *me;
Iliyan Malchevc87cb752009-03-25 18:09:52 -0700158 int n;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800159
160 x = strrchr(lookup_name,'/');
161 if(x) lookup_name = x+1;
162
Iliyan Malchevc87cb752009-03-25 18:09:52 -0700163 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);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800169 return 0;
170}