blob: 739c181767cffcd3c9d21351d7f27631f5ea9741 [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
10struct mapentry
11{
12 mapentry *next;
13 unsigned base;
14 char name[0];
15};
16
17static mapentry *maplist = 0;
18
19/* These values limit the address range within which we prelinked libraries
20 reside. The limit is not set in stone, but should be observed in the
21 prelink map, or the prelink step will fail.
22*/
23
24#define PRELINK_MIN 0x90000000
25#define PRELINK_MAX 0xB0000000
26
27void pm_init(const char *file)
28{
29 unsigned line = 0;
30 char buf[256];
31 char *x;
32 unsigned n;
33 FILE *fp;
34 mapentry *me;
35 unsigned last = -1UL;
36
37 fp = fopen(file, "r");
38 FAILIF(fp == NULL, "Error opening file %s: %s (%d)\n",
39 file, strerror(errno), errno);
40
41 while(fgets(buf, 256, fp)){
42 x = buf;
43 line++;
44
45 /* eat leading whitespace */
46 while(isspace(*x)) x++;
47
48 /* comment or blank line? skip! */
49 if(*x == '#') continue;
50 if(*x == 0) continue;
51
52 /* skip name */
53 while(*x && !isspace(*x)) x++;
54
55 if(*x) {
56 *x++ = 0;
57 /* skip space before address */
58 while(*x && isspace(*x)) x++;
59 }
60
61 /* no address? complain. */
62 if(*x == 0) {
63 fprintf(stderr,"warning: %s:%d no base address specified\n",
64 file, line);
65 continue;
66 }
67
68 n = strtoul(x, 0, 16);
69 /* Note that this is not the only bounds check. If a library's size
70 exceeds its slot as defined in the prelink map, the prelinker will
71 exit with an error. See pm_report_library_size_in_memory().
72 */
73 FAILIF((n < PRELINK_MIN) || (n > PRELINK_MAX),
74 "%s:%d base 0x%08x out of range.\n",
75 file, line, n);
76
77 me = malloc(sizeof(mapentry) + strlen(buf) + 1);
78 FAILIF(me == NULL, "Out of memory parsing %s\n", file);
79
80 FAILIF(last <= n, "The prelink map is not in descending order "
81 "at entry %s (%08x)!\n", buf, n);
82 last = n;
83
84 me->base = n;
85 strcpy(me->name, buf);
86 me->next = maplist;
87 maplist = me;
88 }
89
90 fclose(fp);
91}
92
93/* apriori() calls this function when it determine the size of a library
94 in memory. pm_report_library_size_in_memory() makes sure that the library
95 fits in the slot provided by the prelink map.
96*/
97void pm_report_library_size_in_memory(const char *name,
98 off_t fsize)
99{
100 char *x;
101 mapentry *me;
102
103 x = strrchr(name,'/');
104 if(x) name = x+1;
105
106 for(me = maplist; me; me = me->next){
107 if(!strcmp(name, me->name)) {
108 off_t slot = me->next ? me->next->base : PRELINK_MAX;
109 slot -= me->base;
110 FAILIF(fsize > slot,
111 "prelink map error: library %s@0x%08x is too big "
112 "at %lld bytes, it runs %lld bytes into "
113 "library %s@0x%08x!\n",
114 me->name, me->base, fsize, fsize - slot,
115 me->next->name, me->next->base);
116 break;
117 }
118 }
119
120 FAILIF(!me,"library '%s' not in prelink map\n", name);
121}
122
123unsigned pm_get_next_link_address(const char *lookup_name)
124{
125 char *x;
126 mapentry *me;
127
128 x = strrchr(lookup_name,'/');
129 if(x) lookup_name = x+1;
130
131 for(me = maplist; me; me = me->next){
132 if(!strcmp(lookup_name, me->name)) {
133 return me->base;
134 }
135 }
136
137 FAILIF(1==1,"library '%s' not in prelink map\n", lookup_name);
138 return 0;
139}