|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU Lesser General Public License as published by |
|
7 * the Free Software Foundation, either version 3 of the License, or |
|
8 * (at your option) any later version. |
|
9 * |
|
10 * This program is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 * GNU Lesser General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU Lesser General Public License |
|
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17 */ |
|
18 |
|
19 #include <libelf.h> |
|
20 #include <map> |
|
21 |
|
22 #include "elfsymboltablemanager.h" |
|
23 |
|
24 void ElfFileSymbolFragments::AddSymbolTable(String & aPath, size_t aOffset, size_t aSize, size_t aFirstGlobal){ |
|
25 iPath = aPath; |
|
26 // drop the inital 'undefined' symbol |
|
27 iSymbolTableOffset = aOffset + sizeof(Elf32_Sym); |
|
28 iSymbolTableSize = aSize - sizeof(Elf32_Sym); |
|
29 iFirstGlobal = aFirstGlobal - 1; |
|
30 } |
|
31 |
|
32 void ElfFileSymbolFragments::AddStringTable(String & aPath, size_t aOffset, size_t aSize){ |
|
33 iPath = aPath; |
|
34 // drop the inital "\0" |
|
35 iStringTableOffset = aOffset + 1; |
|
36 iStringTableSize = aSize - 1; |
|
37 } |
|
38 |
|
39 size_t ElfFileSymbolFragments::LookupSection(size_t ndx){ |
|
40 SectionNumberMap::iterator aMapping = iSectionNumberMap.begin(); |
|
41 SectionNumberMap::iterator end = iSectionNumberMap.end(); |
|
42 while (aMapping != end) { |
|
43 if (aMapping->iOld == ndx) |
|
44 return aMapping->iNew; |
|
45 aMapping++; |
|
46 } |
|
47 return ndx; |
|
48 } |
|
49 |
|
50 int ElfFileSymbolFragments::LookupVaddrAddend(size_t ndx){ |
|
51 SectionVaddrAddendMap::iterator aMapping = iSectionVaddrAddendMap.begin(); |
|
52 SectionVaddrAddendMap::iterator end = iSectionVaddrAddendMap.end(); |
|
53 while (aMapping != end) { |
|
54 if (aMapping->iSectionNumber == ndx) |
|
55 return aMapping->iAddend; |
|
56 aMapping++; |
|
57 } |
|
58 return 0; |
|
59 } |
|
60 |
|
61 size_t ElfSymTabStringTable::Size(){ |
|
62 return iElfSymbolTableManager.GetSymTabStringsSectionSize(); |
|
63 } |
|
64 |
|
65 void ElfSymbolTableManager::Finalize(SectionNumberMap & aSectionNumberMap, SectionVaddrAddendMap & aSectionVaddrAddendMap ){ |
|
66 iCurrentFragment.SetSectionNumberMap(aSectionNumberMap); |
|
67 iCurrentFragment.SetSectionVaddrAddendMap(aSectionVaddrAddendMap); |
|
68 iCurrentFragment.Validate(); |
|
69 iSymbolFragments.push_back(iCurrentFragment); |
|
70 iCurrentFragment.Reset(); |
|
71 } |
|
72 |
|
73 // TODO: This could be done more efficiently and with out the use of the ElfStringTable object. |
|
74 void ElfSymbolTableManager::GetFileFragmentData(FileFragmentData & aFileFragmentData ){ |
|
75 size_t symTabSize = GetSymTabSectionSize(); |
|
76 iData = new char[symTabSize]; |
|
77 Elf32_Sym * syms = (Elf32_Sym *)iData; |
|
78 |
|
79 |
|
80 // set up UNDEF symbol |
|
81 syms[0].st_info = 0; |
|
82 syms[0].st_name = 0; |
|
83 syms[0].st_other = 0; |
|
84 syms[0].st_shndx = 0; |
|
85 syms[0].st_size = 0; |
|
86 syms[0].st_value = 0; |
|
87 |
|
88 // set up 'cursors' into final symbol table so we put locals first |
|
89 // and globals at the end |
|
90 Elf32_Sym * lsym = &syms[1]; |
|
91 size_t firstGlobal = GetFirstNonLocalIndex(); |
|
92 Elf32_Sym * gsym = &syms[firstGlobal]; |
|
93 Elf32_Sym * lsymLim = gsym; |
|
94 iStringTable.AllocateInitialNullString(); |
|
95 |
|
96 SymbolFragmentList::iterator aFrag = iSymbolFragments.begin(); |
|
97 SymbolFragmentList::iterator end = iSymbolFragments.end(); |
|
98 while (aFrag != end) { |
|
99 //InputFile aFile((char *)(aFrag->GetPath().c_str())); |
|
100 InputFile aFile(aFrag->GetPath()); |
|
101 aFile.SetOffset(aFrag->GetSymbolTableOffset()); |
|
102 size_t symSize = aFrag->GetSymbolTableSize(); |
|
103 size_t limit = symSize / sizeof(Elf32_Sym); |
|
104 char * symtabData = aFile.GetData(symSize); |
|
105 Elf32_Sym * symtab = (Elf32_Sym *)symtabData; |
|
106 aFile.SetOffset(aFrag->GetStringTableOffset()); |
|
107 char * strtabx = aFile.GetData(aFrag->GetStringTableSize()); |
|
108 // set strtab back one to 'add' "\0" back in so indexs works with addition. |
|
109 char * strtab = strtabx - 1; |
|
110 size_t firstNonLocal = aFrag->GetFirstGlobal(); |
|
111 |
|
112 typedef std::map<size_t, size_t> SymbolNdxMap; |
|
113 SymbolNdxMap symNdxMap; |
|
114 |
|
115 for (size_t i = 0; i < limit; i++){ |
|
116 size_t strndx = symtab[i].st_name; |
|
117 |
|
118 if (strndx != 0) { |
|
119 // see if we've already seen this index |
|
120 SymbolNdxMap::iterator res = symNdxMap.find(strndx); |
|
121 size_t newndx; |
|
122 if (res != symNdxMap.end()){ |
|
123 newndx = res->second; |
|
124 symtab[i].st_name = newndx; |
|
125 } else { |
|
126 char * name = &strtab[strndx]; |
|
127 newndx = iStringTable.AddString(name); |
|
128 symNdxMap[strndx] = symtab[i].st_name = newndx; |
|
129 } |
|
130 } |
|
131 |
|
132 if (!(symtab[i].st_value || symtab[i].st_size)){ |
|
133 symtab[i].st_shndx = SHN_UNDEF; |
|
134 } else { |
|
135 size_t oldNdx = symtab[i].st_shndx; |
|
136 |
|
137 // retrieve new section index |
|
138 size_t newscnndx = aFrag->LookupSection(oldNdx); |
|
139 // retrieve the vaddr adjustment to add to the symbol's value |
|
140 int addend = aFrag->LookupVaddrAddend(oldNdx); |
|
141 symtab[i].st_shndx = newscnndx; |
|
142 symtab[i].st_value += addend; |
|
143 } |
|
144 if (i < firstNonLocal){ |
|
145 assert(lsym < lsymLim); |
|
146 *(lsym++) = symtab[i]; |
|
147 } else { |
|
148 *(gsym++) = symtab[i]; |
|
149 } |
|
150 } |
|
151 |
|
152 delete [] symtabData; |
|
153 delete strtabx; |
|
154 |
|
155 aFrag++; |
|
156 } |
|
157 SetFileFragmentData(aFileFragmentData, symTabSize, reinterpret_cast<char *>(iData)); |
|
158 } |
|
159 |
|
160 |
|
161 size_t ElfSymbolTableManager::Size(){ |
|
162 return GetSymTabSectionSize(); |
|
163 } |
|
164 |
|
165 void ElfSymbolTableManager::DeleteFileFragmentData(){ |
|
166 char * d = iData; |
|
167 iData = NULL; |
|
168 delete [] d; |
|
169 } |
|
170 |
|
171 void ElfSymbolTableManager::AddData(OutputFile & aOutputFile){ |
|
172 const FileFragment & aSectionFrag = iOutputFile.GetFileFragment(this); |
|
173 SetOffset(aSectionFrag.GetOffset()); |
|
174 } |
|
175 |
|
176 void ElfSymbolTableManager::AddSymbolTable(){ |
|
177 // The sym table section needs to record the index of its associated |
|
178 // string table in its link field and record the index of the first non-local |
|
179 // symbol in its info field |
|
180 int symTabSize = GetSymTabSectionSize(); |
|
181 size_t firstNonLocal = GetFirstNonLocalIndex(); |
|
182 size_t nextSectionIndex = iElfSectionManager.NumSections(); |
|
183 |
|
184 ElfSectionElfData * aSymTabSectionData = new ElfSectionElfData(*this); |
|
185 Elf32_Shdr symTabShdr; |
|
186 symTabShdr.sh_name = 0; // for now. |
|
187 symTabShdr.sh_type = SHT_SYMTAB; |
|
188 symTabShdr.sh_flags = 0; |
|
189 symTabShdr.sh_addr = 0; |
|
190 symTabShdr.sh_offset = 0; // for now |
|
191 symTabShdr.sh_size = symTabSize; // for now. |
|
192 // symTabShdr will be @ index nextSectionIndex so the .strtab will |
|
193 // be @ nextSectionIndex +1 |
|
194 symTabShdr.sh_link = nextSectionIndex + 1; |
|
195 symTabShdr.sh_info = firstNonLocal; |
|
196 symTabShdr.sh_addralign = 4; |
|
197 symTabShdr.sh_entsize = sizeof(Elf32_Sym); |
|
198 |
|
199 ElfSection aSymTabSection(aSymTabSectionData, ".symtab", symTabShdr); |
|
200 iElfSectionManager.AddSection(aSymTabSection); |
|
201 |
|
202 |
|
203 ElfSectionElfData * aStringTableSectionData = new ElfSectionElfData(iStringTable); |
|
204 Elf32_Shdr shdr; |
|
205 shdr.sh_name = 0; // for now. |
|
206 shdr.sh_type = SHT_STRTAB; |
|
207 shdr.sh_flags = 0; |
|
208 shdr.sh_addr = 0; |
|
209 shdr.sh_offset = 0; // for now |
|
210 shdr.sh_size = GetSymTabStringsSectionSize(); |
|
211 shdr.sh_link = 0; |
|
212 shdr.sh_info = 0; |
|
213 shdr.sh_addralign = 0; |
|
214 shdr.sh_entsize = 0; |
|
215 ElfSection aStringTableSection(aStringTableSectionData, ".strtab", shdr); |
|
216 iElfSectionManager.AddSection(aStringTableSection); |
|
217 |
|
218 } |
|
219 |
|
220 size_t ElfSymbolTableManager::GetSymTabSectionSize(){ |
|
221 int symTabSize = sizeof(Elf32_Sym); // add the 'undefined' symbols |
|
222 |
|
223 SymbolFragmentList::iterator aFrag = iSymbolFragments.begin(); |
|
224 SymbolFragmentList::iterator end = iSymbolFragments.end(); |
|
225 while (aFrag != end) { |
|
226 symTabSize += aFrag->GetSymbolTableSize(); |
|
227 aFrag++; |
|
228 } |
|
229 return symTabSize; |
|
230 } |
|
231 |
|
232 size_t ElfSymbolTableManager::GetSymTabStringsSectionSize(){ |
|
233 |
|
234 if (iSymbolStringTableSizeValid) |
|
235 return iSymbolStringTableSize; |
|
236 |
|
237 int stringsSize = 1; // add the leading "\0" |
|
238 |
|
239 SymbolFragmentList::iterator aFrag = iSymbolFragments.begin(); |
|
240 SymbolFragmentList::iterator end = iSymbolFragments.end(); |
|
241 while (aFrag != end) { |
|
242 stringsSize += aFrag->GetStringTableSize(); |
|
243 aFrag++; |
|
244 } |
|
245 iSymbolStringTableSizeValid = true; |
|
246 return iSymbolStringTableSize = stringsSize; |
|
247 } |
|
248 |
|
249 size_t ElfSymbolTableManager::GetFirstNonLocalIndex(){ |
|
250 int ndx = 1; // add the 'undefined' symbols |
|
251 |
|
252 SymbolFragmentList::iterator aFrag = iSymbolFragments.begin(); |
|
253 SymbolFragmentList::iterator end = iSymbolFragments.end(); |
|
254 while (aFrag != end) { |
|
255 ndx += aFrag->GetFirstGlobal(); |
|
256 aFrag++; |
|
257 } |
|
258 return ndx; |
|
259 } |