]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/utils/readsoname2.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / utils / readsoname2.c
1 static char *readsonameXX(char *name, FILE *infile, int expected_type, int *type)
2 {
3         ElfW(Ehdr) *epnt;
4         ElfW(Phdr) *ppnt;
5         unsigned int i, j;
6         char *header;
7         ElfW(Addr) dynamic_addr = 0;
8         ElfW(Addr) dynamic_size = 0;
9         unsigned long page_size = getpagesize();
10         ElfW(Addr) strtab_val = 0;
11         ElfW(Addr) needed_val;
12         ElfW(Addr) loadaddr = -1;
13         ElfW(Dyn) *dpnt;
14         struct stat st;
15         char *needed;
16         char *soname = NULL;
17         int multi_libcs = 0;
18
19         if (expected_type == LIB_DLL) {
20                 warn("%s does not match type specified for directory!", name);
21                 expected_type = LIB_ANY;
22         }
23
24         *type = LIB_ELF;
25
26         if (fstat(fileno(infile), &st))
27                 return NULL;
28         header =
29             mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
30                  fileno(infile), 0);
31         if (header == (caddr_t) - 1)
32                 return NULL;
33
34         epnt = (ElfW(Ehdr) *) header;
35         if ((char *)(epnt + 1) > (char *)(header + st.st_size))
36                 goto skip;
37
38         if (UCLIBC_ENDIAN_HOST == UCLIBC_ENDIAN_LITTLE)
39                 byteswap = (epnt->e_ident[5] == ELFDATA2MSB) ? 1 : 0;
40         else if (UCLIBC_ENDIAN_HOST == UCLIBC_ENDIAN_BIG)
41                 byteswap = (epnt->e_ident[5] == ELFDATA2LSB) ? 1 : 0;
42
43         /* Be very lazy, and only byteswap the stuff we use */
44         if (byteswap == 1) {
45                 epnt->e_phoff = bswap_32(epnt->e_phoff);
46                 epnt->e_phnum = bswap_16(epnt->e_phnum);
47         }
48
49         ppnt = (ElfW(Phdr) *) & header[epnt->e_phoff];
50         if ((char *)ppnt < (char *)header ||
51             (char *)(ppnt + epnt->e_phnum) > (char *)(header + st.st_size))
52                 goto skip;
53
54         for (i = 0; i < epnt->e_phnum; i++) {
55                 /* Be very lazy, and only byteswap the stuff we use */
56                 if (byteswap == 1) {
57                         ppnt->p_type = bswap_32(ppnt->p_type);
58                         ppnt->p_vaddr = bswap_32(ppnt->p_vaddr);
59                         ppnt->p_offset = bswap_32(ppnt->p_offset);
60                         ppnt->p_filesz = bswap_32(ppnt->p_filesz);
61                 }
62
63                 if (loadaddr == (ElfW(Addr)) - 1 && ppnt->p_type == PT_LOAD)
64                         loadaddr = (ppnt->p_vaddr & ~(page_size - 1)) -
65                             (ppnt->p_offset & ~(page_size - 1));
66                 if (ppnt->p_type == 2) {
67                         dynamic_addr = ppnt->p_offset;
68                         dynamic_size = ppnt->p_filesz;
69                 };
70                 ppnt++;
71         };
72
73         dpnt = (ElfW(Dyn) *) & header[dynamic_addr];
74         dynamic_size = dynamic_size / sizeof(ElfW(Dyn));
75         if ((char *)dpnt < (char *)header ||
76             (char *)(dpnt + dynamic_size) > (char *)(header + st.st_size))
77                 goto skip;
78
79         if (byteswap == 1) {
80                 dpnt->d_tag = bswap_32(dpnt->d_tag);
81                 dpnt->d_un.d_val = bswap_32(dpnt->d_un.d_val);
82         }
83
84         while (dpnt->d_tag != DT_NULL) {
85                 if (dpnt->d_tag == DT_STRTAB)
86                         strtab_val = dpnt->d_un.d_val;
87                 dpnt++;
88                 if (byteswap == 1) {
89                         dpnt->d_tag = bswap_32(dpnt->d_tag);
90                         dpnt->d_un.d_val = bswap_32(dpnt->d_un.d_val);
91                 }
92         };
93
94         if (!strtab_val)
95                 goto skip;
96
97         dpnt = (ElfW(Dyn) *) & header[dynamic_addr];
98         while (dpnt->d_tag != DT_NULL) {
99                 if (dpnt->d_tag == DT_SONAME || dpnt->d_tag == DT_NEEDED) {
100                         needed_val = dpnt->d_un.d_val;
101                         if (needed_val + strtab_val >= loadaddr ||
102                             needed_val + strtab_val < st.st_size - loadaddr) {
103                                 needed =
104                                     (char *)(header - loadaddr + strtab_val +
105                                              needed_val);
106
107                                 if (dpnt->d_tag == DT_SONAME)
108                                         soname = xstrdup(needed);
109
110                                 for (j = 0; needed_tab[j].soname != NULL; j++) {
111                                         if (strcmp(needed, needed_tab[j].soname)
112                                             == 0) {
113                                                 if (*type != LIB_ELF
114                                                     && *type !=
115                                                     needed_tab[j].type)
116                                                         multi_libcs = 1;
117                                                 *type = needed_tab[j].type;
118                                         }
119                                 }
120                         }
121                 }
122                 dpnt++;
123         };
124
125         if (multi_libcs)
126                 warn("%s appears to be for multiple libc's", name);
127
128         /* If we could not deduce the libc type, and we know what to expect, set the type */
129         if (*type == LIB_ELF && expected_type != LIB_ANY)
130                 *type = expected_type;
131
132         if (expected_type != LIB_ANY && expected_type != LIB_ELF &&
133             expected_type != *type) {
134                 warn("%s does not match type specified for directory!", name);
135         }
136
137       skip:
138         munmap(header, st.st_size);
139
140         return soname;
141 }