diff options
| -rw-r--r-- | scripts/recordmcount.c | 548 | ||||
| -rw-r--r-- | scripts/recordmcount.h | 366 |
2 files changed, 370 insertions, 544 deletions
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 34f32be17090..7f7f7180fe24 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c | |||
| @@ -212,550 +212,10 @@ is_mcounted_section_name(char const *const txtname) | |||
| 212 | 0 == strcmp(".text.unlikely", txtname); | 212 | 0 == strcmp(".text.unlikely", txtname); |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | /* Append the new shstrtab, Elf32_Shdr[], __mcount_loc and its relocations. */ | 215 | /* 32 bit and 64 bit are very similar */ |
| 216 | static void append32(Elf32_Ehdr *const ehdr, | 216 | #include "recordmcount.h" |
| 217 | Elf32_Shdr *const shstr, | 217 | #define RECORD_MCOUNT_64 |
| 218 | uint32_t const *const mloc0, | 218 | #include "recordmcount.h" |
| 219 | uint32_t const *const mlocp, | ||
| 220 | Elf32_Rel const *const mrel0, | ||
| 221 | Elf32_Rel const *const mrelp, | ||
| 222 | unsigned int const rel_entsize, | ||
| 223 | unsigned int const symsec_sh_link) | ||
| 224 | { | ||
| 225 | /* Begin constructing output file */ | ||
| 226 | Elf32_Shdr mcsec; | ||
| 227 | char const *mc_name = (sizeof(Elf32_Rela) == rel_entsize) | ||
| 228 | ? ".rela__mcount_loc" | ||
| 229 | : ".rel__mcount_loc"; | ||
| 230 | unsigned const old_shnum = w2(ehdr->e_shnum); | ||
| 231 | uint32_t const old_shoff = w(ehdr->e_shoff); | ||
| 232 | uint32_t const old_shstr_sh_size = w(shstr->sh_size); | ||
| 233 | uint32_t const old_shstr_sh_offset = w(shstr->sh_offset); | ||
| 234 | uint32_t t = 1 + strlen(mc_name) + w(shstr->sh_size); | ||
| 235 | uint32_t new_e_shoff; | ||
| 236 | |||
| 237 | shstr->sh_size = w(t); | ||
| 238 | shstr->sh_offset = w(sb.st_size); | ||
| 239 | t += sb.st_size; | ||
| 240 | t += (3u & -t); /* 4-byte align */ | ||
| 241 | new_e_shoff = t; | ||
| 242 | |||
| 243 | /* body for new shstrtab */ | ||
| 244 | ulseek(fd_map, sb.st_size, SEEK_SET); | ||
| 245 | uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size); | ||
| 246 | uwrite(fd_map, mc_name, 1 + strlen(mc_name)); | ||
| 247 | |||
| 248 | /* old(modified) Elf32_Shdr table, 4-byte aligned */ | ||
| 249 | ulseek(fd_map, t, SEEK_SET); | ||
| 250 | t += sizeof(Elf32_Shdr) * old_shnum; | ||
| 251 | uwrite(fd_map, old_shoff + (void *)ehdr, | ||
| 252 | sizeof(Elf32_Shdr) * old_shnum); | ||
| 253 | |||
| 254 | /* new sections __mcount_loc and .rel__mcount_loc */ | ||
| 255 | t += 2*sizeof(mcsec); | ||
| 256 | mcsec.sh_name = w((sizeof(Elf32_Rela) == rel_entsize) + strlen(".rel") | ||
| 257 | + old_shstr_sh_size); | ||
| 258 | mcsec.sh_type = w(SHT_PROGBITS); | ||
| 259 | mcsec.sh_flags = w(SHF_ALLOC); | ||
| 260 | mcsec.sh_addr = 0; | ||
| 261 | mcsec.sh_offset = w(t); | ||
| 262 | mcsec.sh_size = w((void *)mlocp - (void *)mloc0); | ||
| 263 | mcsec.sh_link = 0; | ||
| 264 | mcsec.sh_info = 0; | ||
| 265 | mcsec.sh_addralign = w(4); | ||
| 266 | mcsec.sh_entsize = w(4); | ||
| 267 | uwrite(fd_map, &mcsec, sizeof(mcsec)); | ||
| 268 | |||
| 269 | mcsec.sh_name = w(old_shstr_sh_size); | ||
| 270 | mcsec.sh_type = (sizeof(Elf32_Rela) == rel_entsize) | ||
| 271 | ? w(SHT_RELA) | ||
| 272 | : w(SHT_REL); | ||
| 273 | mcsec.sh_flags = 0; | ||
| 274 | mcsec.sh_addr = 0; | ||
| 275 | mcsec.sh_offset = w((void *)mlocp - (void *)mloc0 + t); | ||
| 276 | mcsec.sh_size = w((void *)mrelp - (void *)mrel0); | ||
| 277 | mcsec.sh_link = w(symsec_sh_link); | ||
| 278 | mcsec.sh_info = w(old_shnum); | ||
| 279 | mcsec.sh_addralign = w(4); | ||
| 280 | mcsec.sh_entsize = w(rel_entsize); | ||
| 281 | uwrite(fd_map, &mcsec, sizeof(mcsec)); | ||
| 282 | |||
| 283 | uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0); | ||
| 284 | uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0); | ||
| 285 | |||
| 286 | ehdr->e_shoff = w(new_e_shoff); | ||
| 287 | ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */ | ||
| 288 | ulseek(fd_map, 0, SEEK_SET); | ||
| 289 | uwrite(fd_map, ehdr, sizeof(*ehdr)); | ||
| 290 | } | ||
| 291 | |||
| 292 | /* | ||
| 293 | * append64 and append32 (and other analogous pairs) could be templated | ||
| 294 | * using C++, but the complexity is high. (For an example, look at p_elf.h | ||
| 295 | * in the source for UPX, http://upx.sourceforge.net) So: remember to make | ||
| 296 | * the corresponding change in the routine for the other size. | ||
| 297 | */ | ||
| 298 | static void append64(Elf64_Ehdr *const ehdr, | ||
| 299 | Elf64_Shdr *const shstr, | ||
| 300 | uint64_t const *const mloc0, | ||
| 301 | uint64_t const *const mlocp, | ||
| 302 | Elf64_Rel const *const mrel0, | ||
| 303 | Elf64_Rel const *const mrelp, | ||
| 304 | unsigned int const rel_entsize, | ||
| 305 | unsigned int const symsec_sh_link) | ||
| 306 | { | ||
| 307 | /* Begin constructing output file */ | ||
| 308 | Elf64_Shdr mcsec; | ||
| 309 | char const *mc_name = (sizeof(Elf64_Rela) == rel_entsize) | ||
| 310 | ? ".rela__mcount_loc" | ||
| 311 | : ".rel__mcount_loc"; | ||
| 312 | unsigned const old_shnum = w2(ehdr->e_shnum); | ||
| 313 | uint64_t const old_shoff = w8(ehdr->e_shoff); | ||
| 314 | uint64_t const old_shstr_sh_size = w8(shstr->sh_size); | ||
| 315 | uint64_t const old_shstr_sh_offset = w8(shstr->sh_offset); | ||
| 316 | uint64_t t = 1 + strlen(mc_name) + w8(shstr->sh_size); | ||
| 317 | uint64_t new_e_shoff; | ||
| 318 | |||
| 319 | shstr->sh_size = w8(t); | ||
| 320 | shstr->sh_offset = w8(sb.st_size); | ||
| 321 | t += sb.st_size; | ||
| 322 | t += (7u & -t); /* 8-byte align */ | ||
| 323 | new_e_shoff = t; | ||
| 324 | |||
| 325 | /* body for new shstrtab */ | ||
| 326 | ulseek(fd_map, sb.st_size, SEEK_SET); | ||
| 327 | uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size); | ||
| 328 | uwrite(fd_map, mc_name, 1 + strlen(mc_name)); | ||
| 329 | |||
| 330 | /* old(modified) Elf64_Shdr table, 8-byte aligned */ | ||
| 331 | ulseek(fd_map, t, SEEK_SET); | ||
| 332 | t += sizeof(Elf64_Shdr) * old_shnum; | ||
| 333 | uwrite(fd_map, old_shoff + (void *)ehdr, | ||
| 334 | sizeof(Elf64_Shdr) * old_shnum); | ||
| 335 | |||
| 336 | /* new sections __mcount_loc and .rel__mcount_loc */ | ||
| 337 | t += 2*sizeof(mcsec); | ||
| 338 | mcsec.sh_name = w((sizeof(Elf64_Rela) == rel_entsize) + strlen(".rel") | ||
| 339 | + old_shstr_sh_size); | ||
| 340 | mcsec.sh_type = w(SHT_PROGBITS); | ||
| 341 | mcsec.sh_flags = w8(SHF_ALLOC); | ||
| 342 | mcsec.sh_addr = 0; | ||
| 343 | mcsec.sh_offset = w8(t); | ||
| 344 | mcsec.sh_size = w8((void *)mlocp - (void *)mloc0); | ||
| 345 | mcsec.sh_link = 0; | ||
| 346 | mcsec.sh_info = 0; | ||
| 347 | mcsec.sh_addralign = w8(8); | ||
| 348 | mcsec.sh_entsize = w8(8); | ||
| 349 | uwrite(fd_map, &mcsec, sizeof(mcsec)); | ||
| 350 | |||
| 351 | mcsec.sh_name = w(old_shstr_sh_size); | ||
| 352 | mcsec.sh_type = (sizeof(Elf64_Rela) == rel_entsize) | ||
| 353 | ? w(SHT_RELA) | ||
| 354 | : w(SHT_REL); | ||
| 355 | mcsec.sh_flags = 0; | ||
| 356 | mcsec.sh_addr = 0; | ||
| 357 | mcsec.sh_offset = w8((void *)mlocp - (void *)mloc0 + t); | ||
| 358 | mcsec.sh_size = w8((void *)mrelp - (void *)mrel0); | ||
| 359 | mcsec.sh_link = w(symsec_sh_link); | ||
| 360 | mcsec.sh_info = w(old_shnum); | ||
| 361 | mcsec.sh_addralign = w8(8); | ||
| 362 | mcsec.sh_entsize = w8(rel_entsize); | ||
| 363 | uwrite(fd_map, &mcsec, sizeof(mcsec)); | ||
| 364 | |||
| 365 | uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0); | ||
| 366 | uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0); | ||
| 367 | |||
| 368 | ehdr->e_shoff = w8(new_e_shoff); | ||
| 369 | ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */ | ||
| 370 | ulseek(fd_map, 0, SEEK_SET); | ||
| 371 | uwrite(fd_map, ehdr, sizeof(*ehdr)); | ||
| 372 | } | ||
| 373 | |||
| 374 | /* | ||
| 375 | * Look at the relocations in order to find the calls to mcount. | ||
| 376 | * Accumulate the section offsets that are found, and their relocation info, | ||
| 377 | * onto the end of the existing arrays. | ||
| 378 | */ | ||
| 379 | static uint32_t *sift32_rel_mcount(uint32_t *mlocp, | ||
| 380 | unsigned const offbase, | ||
| 381 | Elf32_Rel **const mrelpp, | ||
| 382 | Elf32_Shdr const *const relhdr, | ||
| 383 | Elf32_Ehdr const *const ehdr, | ||
| 384 | unsigned const recsym, | ||
| 385 | uint32_t const recval, | ||
| 386 | unsigned const reltype) | ||
| 387 | { | ||
| 388 | uint32_t *const mloc0 = mlocp; | ||
| 389 | Elf32_Rel *mrelp = *mrelpp; | ||
| 390 | Elf32_Shdr *const shdr0 = (Elf32_Shdr *)(w(ehdr->e_shoff) | ||
| 391 | + (void *)ehdr); | ||
| 392 | unsigned const symsec_sh_link = w(relhdr->sh_link); | ||
| 393 | Elf32_Shdr const *const symsec = &shdr0[symsec_sh_link]; | ||
| 394 | Elf32_Sym const *const sym0 = (Elf32_Sym const *)(w(symsec->sh_offset) | ||
| 395 | + (void *)ehdr); | ||
| 396 | |||
| 397 | Elf32_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; | ||
| 398 | char const *const str0 = (char const *)(w(strsec->sh_offset) | ||
| 399 | + (void *)ehdr); | ||
