diff options
Diffstat (limited to 'scripts/recordmcount.c')
-rw-r--r-- | scripts/recordmcount.c | 137 |
1 files changed, 113 insertions, 24 deletions
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 698768bdc581..301d70b0174f 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c | |||
@@ -48,12 +48,17 @@ | |||
48 | 48 | ||
49 | static int fd_map; /* File descriptor for file being modified. */ | 49 | static int fd_map; /* File descriptor for file being modified. */ |
50 | static int mmap_failed; /* Boolean flag. */ | 50 | static int mmap_failed; /* Boolean flag. */ |
51 | static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ | ||
52 | static char gpfx; /* prefix for global symbol name (sometimes '_') */ | 51 | static char gpfx; /* prefix for global symbol name (sometimes '_') */ |
53 | static struct stat sb; /* Remember .st_size, etc. */ | 52 | static struct stat sb; /* Remember .st_size, etc. */ |
54 | static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ | 53 | static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ |
55 | static const char *altmcount; /* alternate mcount symbol name */ | 54 | static const char *altmcount; /* alternate mcount symbol name */ |
56 | static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ | 55 | static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ |
56 | static void *file_map; /* pointer of the mapped file */ | ||
57 | static void *file_end; /* pointer to the end of the mapped file */ | ||
58 | static int file_updated; /* flag to state file was changed */ | ||
59 | static void *file_ptr; /* current file pointer location */ | ||
60 | static void *file_append; /* added to the end of the file */ | ||
61 | static size_t file_append_size; /* how much is added to end of file */ | ||
57 | 62 | ||
58 | /* setjmp() return values */ | 63 | /* setjmp() return values */ |
59 | enum { | 64 | enum { |
@@ -67,10 +72,14 @@ static void | |||
67 | cleanup(void) | 72 | cleanup(void) |
68 | { | 73 | { |
69 | if (!mmap_failed) | 74 | if (!mmap_failed) |
70 | munmap(ehdr_curr, sb.st_size); | 75 | munmap(file_map, sb.st_size); |
71 | else | 76 | else |
72 | free(ehdr_curr); | 77 | free(file_map); |
73 | close(fd_map); | 78 | file_map = NULL; |
79 | free(file_append); | ||
80 | file_append = NULL; | ||
81 | file_append_size = 0; | ||
82 | file_updated = 0; | ||
74 | } | 83 | } |
75 | 84 | ||
76 | static void __attribute__((noreturn)) | 85 | static void __attribute__((noreturn)) |
@@ -92,12 +101,22 @@ succeed_file(void) | |||
92 | static off_t | 101 | static off_t |
93 | ulseek(int const fd, off_t const offset, int const whence) | 102 | ulseek(int const fd, off_t const offset, int const whence) |
94 | { | 103 | { |
95 | off_t const w = lseek(fd, offset, whence); | 104 | switch (whence) { |
96 | if (w == (off_t)-1) { | 105 | case SEEK_SET: |
97 | perror("lseek"); | 106 | file_ptr = file_map + offset; |
107 | break; | ||
108 | case SEEK_CUR: | ||
109 | file_ptr += offset; | ||
110 | break; | ||
111 | case SEEK_END: | ||
112 | file_ptr = file_map + (sb.st_size - offset); | ||
113 | break; | ||
114 | } | ||
115 | if (file_ptr < file_map) { | ||
116 | fprintf(stderr, "lseek: seek before file\n"); | ||
98 | fail_file(); | 117 | fail_file(); |
99 | } | 118 | } |
100 | return w; | 119 | return file_ptr - file_map; |
101 | } | 120 | } |
102 | 121 | ||
103 | static size_t | 122 | static size_t |
@@ -114,12 +133,38 @@ uread(int const fd, void *const buf, size_t const count) | |||
114 | static size_t | 133 | static size_t |
115 | uwrite(int const fd, void const *const buf, size_t const count) | 134 | uwrite(int const fd, void const *const buf, size_t const count) |
116 | { | 135 | { |
117 | size_t const n = write(fd, buf, count); | 136 | size_t cnt = count; |
118 | if (n != count) { | 137 | off_t idx = 0; |
119 | perror("write"); | 138 | |
120 | fail_file(); | 139 | file_updated = 1; |
140 | |||
141 | if (file_ptr + count >= file_end) { | ||
142 | off_t aoffset = (file_ptr + count) - file_end; | ||
143 | |||
144 | if (aoffset > file_append_size) { | ||
145 | file_append = realloc(file_append, aoffset); | ||
146 | file_append_size = aoffset; | ||
147 | } | ||
148 | if (!file_append) { | ||
149 | perror("write"); | ||
150 | fail_file(); | ||
151 | } | ||
152 | if (file_ptr < file_end) { | ||
153 | cnt = file_end - file_ptr; | ||
154 | } else { | ||
155 | cnt = 0; | ||
156 | idx = aoffset - count; | ||
157 | } | ||
121 | } | 158 | } |
122 | return n; | 159 | |
160 | if (cnt) | ||
161 | memcpy(file_ptr, buf, cnt); | ||
162 | |||
163 | if (cnt < count) | ||
164 | memcpy(file_append + idx, buf + cnt, count - cnt); | ||
165 | |||
166 | file_ptr += count; | ||
167 | return count; | ||
123 | } | 168 | } |
124 | 169 | ||
125 | static void * | 170 | static void * |
@@ -192,9 +237,7 @@ static int make_nop_arm64(void *map, size_t const offset) | |||
192 | */ | 237 | */ |
193 | static void *mmap_file(char const *fname) | 238 | static void *mmap_file(char const *fname) |
194 | { | 239 | { |
195 | void *addr; | 240 | fd_map = open(fname, O_RDONLY); |
196 | |||
197 | fd_map = open(fname, O_RDWR); | ||
198 | if (fd_map < 0 || fstat(fd_map, &sb) < 0) { | 241 | if (fd_map < 0 || fstat(fd_map, &sb) < 0) { |
199 | perror(fname); | 242 | perror(fname); |
200 | fail_file(); | 243 | fail_file(); |
@@ -203,15 +246,58 @@ static void *mmap_file(char const *fname) | |||
203 | fprintf(stderr, "not a regular file: %s\n", fname); | 246 | fprintf(stderr, "not a regular file: %s\n", fname); |
204 | fail_file(); | 247 | fail_file(); |
205 | } | 248 | } |
206 | addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, | 249 | file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, |
207 | fd_map, 0); | 250 | fd_map, 0); |
208 | mmap_failed = 0; | 251 | mmap_failed = 0; |
209 | if (addr == MAP_FAILED) { | 252 | if (file_map == MAP_FAILED) { |
210 | mmap_failed = 1; | 253 | mmap_failed = 1; |
211 | addr = umalloc(sb.st_size); | 254 | file_map = umalloc(sb.st_size); |
212 | uread(fd_map, addr, sb.st_size); | 255 | uread(fd_map, file_map, sb.st_size); |
256 | } | ||
257 | close(fd_map); | ||
258 | |||
259 | file_end = file_map + sb.st_size; | ||
260 | |||
261 | return file_map; | ||
262 | } | ||
263 | |||
264 | static void write_file(const char *fname) | ||
265 | { | ||
266 | char tmp_file[strlen(fname) + 4]; | ||
267 | size_t n; | ||
268 | |||
269 | if (!file_updated) | ||
270 | return; | ||
271 | |||
272 | sprintf(tmp_file, "%s.rc", fname); | ||
273 | |||
274 | /* | ||
275 | * After reading the entire file into memory, delete it | ||
276 | * and write it back, to prevent weird side effects of modifying | ||
277 | * an object file in place. | ||
278 | */ | ||
279 | fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode); | ||
280 | if (fd_map < 0) { | ||
281 | perror(fname); | ||
282 | fail_file(); | ||
283 | } | ||
284 | n = write(fd_map, file_map, sb.st_size); | ||
285 | if (n != sb.st_size) { | ||
286 | perror("write"); | ||
287 | fail_file(); | ||
288 | } | ||
289 | if (file_append_size) { | ||
290 | n = write(fd_map, file_append, file_append_size); | ||
291 | if (n != file_append_size) { | ||
292 | perror("write"); | ||
293 | fail_file(); | ||
294 | } | ||
295 | } | ||
296 | close(fd_map); | ||
297 | if (rename(tmp_file, fname) < 0) { | ||
298 | perror(fname); | ||
299 | fail_file(); | ||
213 | } | 300 | } |
214 | return addr; | ||
215 | } | 301 | } |
216 | 302 | ||
217 | /* w8rev, w8nat, ...: Handle endianness. */ | 303 | /* w8rev, w8nat, ...: Handle endianness. */ |
@@ -318,7 +404,6 @@ do_file(char const *const fname) | |||
318 | Elf32_Ehdr *const ehdr = mmap_file(fname); | 404 | Elf32_Ehdr *const ehdr = mmap_file(fname); |
319 | unsigned int reltype = 0; | 405 | unsigned int reltype = 0; |
320 | 406 | ||
321 | ehdr_curr = ehdr; | ||
322 | w = w4nat; | 407 | w = w4nat; |
323 | w2 = w2nat; | 408 | w2 = w2nat; |
324 | w8 = w8nat; | 409 | w8 = w8nat; |
@@ -441,6 +526,7 @@ do_file(char const *const fname) | |||
441 | } | 526 | } |
442 | } /* end switch */ | 527 | } /* end switch */ |
443 | 528 | ||
529 | write_file(fname); | ||
444 | cleanup(); | 530 | cleanup(); |
445 | } | 531 | } |
446 | 532 | ||
@@ -493,11 +579,14 @@ main(int argc, char *argv[]) | |||
493 | case SJ_SETJMP: /* normal sequence */ | 579 | case SJ_SETJMP: /* normal sequence */ |
494 | /* Avoid problems if early cleanup() */ | 580 | /* Avoid problems if early cleanup() */ |
495 | fd_map = -1; | 581 | fd_map = -1; |
496 | ehdr_curr = NULL; | ||
497 | mmap_failed = 1; | 582 | mmap_failed = 1; |
583 | file_map = NULL; | ||
584 | file_ptr = NULL; | ||
585 | file_updated = 0; | ||
498 | do_file(file); | 586 | do_file(file); |
499 | break; | 587 | break; |
500 | case SJ_FAIL: /* error in do_file or below */ | 588 | case SJ_FAIL: /* error in do_file or below */ |
589 | sprintf("%s: failed\n", file); | ||
501 | ++n_error; | 590 | ++n_error; |
502 | break; | 591 | break; |
503 | case SJ_SUCCEED: /* premature success */ | 592 | case SJ_SUCCEED: /* premature success */ |