From a3df2ab9a4152a4bb4f356267391a94e3cea7a2a Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sat, 3 Sep 2016 20:25:32 +0200 Subject: [PATCH] section: introspect sections without linker extensions. Fixes #91 --- include/criterion/internal/common.h | 21 ---- po/de.po | 4 +- po/fr.po | 4 +- src/compat/section-elf.c | 167 ++++++++++++++++++++++++++++ src/compat/section-mach-o.c | 104 +++++++++++++++++ src/compat/section-pe.c | 58 ++++++++++ src/compat/section.c | 72 ++---------- src/compat/section.h | 47 +++++--- src/core/report.c | 50 +++------ src/core/report.h | 1 - src/core/runner.c | 28 ++--- src/core/runner.h | 15 +-- 12 files changed, 407 insertions(+), 164 deletions(-) create mode 100644 src/compat/section-elf.c create mode 100644 src/compat/section-mach-o.c create mode 100644 src/compat/section-pe.c diff --git a/include/criterion/internal/common.h b/include/criterion/internal/common.h index fef1735..5c573f3 100644 --- a/include/criterion/internal/common.h +++ b/include/criterion/internal/common.h @@ -56,15 +56,11 @@ # endif # ifdef __APPLE__ -# define CR_SECTION_START_PREFIX __first -# define CR_SECTION_END_PREFIX __last # define CR_SECTION_START_SUFFIX(Name) __asm("section$start$__DATA$" Name) # define CR_SECTION_END_SUFFIX(Name) __asm("section$end$__DATA$" Name) # define CR_SECTION_(Name) CR_ATTRIBUTE(section("__DATA," Name)) # define CR_SECTION_SUFFIX_ # elif CR_IS_MSVC -# define CR_SECTION_START_PREFIX __start -# define CR_SECTION_END_PREFIX __stop # define CR_SECTION_START_SUFFIX(Name) # define CR_SECTION_END_SUFFIX(Name) # define CR_SECTION_(Name) \ @@ -74,8 +70,6 @@ # define CR_SECTION_SUFFIX_ \ __pragma(data_seg(pop)) # else -# define CR_SECTION_START_PREFIX __start -# define CR_SECTION_END_PREFIX __stop # define CR_SECTION_START_SUFFIX(Name) # define CR_SECTION_END_SUFFIX(Name) # define CR_SECTION_(Name) CR_ATTRIBUTE(section(Name)) @@ -85,21 +79,6 @@ # define CR_MAKE_IDENTIFIER_(Prefix, Id) CR_MAKE_IDENTIFIER__(Prefix, Id) # define CR_MAKE_IDENTIFIER__(Prefix, Id) Prefix ## _ ## Id -# define CR_SECTION_START_(Name) CR_MAKE_IDENTIFIER_(CR_SECTION_START_PREFIX, Name) -# define CR_SECTION_END_(Name) CR_MAKE_IDENTIFIER_(CR_SECTION_END_PREFIX, Name) - -# define CR_SECTION_START(Name) g_ ## Name ## _section_start -# define CR_SECTION_END(Name) g_ ## Name ## _section_end - -# define CR_DECL_SECTION_LIMITS(Type, Name) CR_DECL_SECTION_LIMITS_(Type, Name) -# define CR_DECL_SECTION_LIMITS_(Type, Name) \ - extern Type CR_SECTION_START_(Name) CR_SECTION_START_SUFFIX(#Name); \ - extern Type CR_SECTION_END_(Name) CR_SECTION_END_SUFFIX(#Name) - -# define CR_IMPL_SECTION_LIMITS(Type, Name) \ - Type *const CR_SECTION_START(Name) = &CR_SECTION_START_(Name); \ - Type *const CR_SECTION_END(Name) = &CR_SECTION_END_(Name) - # ifdef __GNUC__ # define CR_UNUSED CR_ATTRIBUTE(unused) # define CR_NORETURN CR_ATTRIBUTE(noreturn) diff --git a/po/de.po b/po/de.po index dfabe17..195194c 100644 --- a/po/de.po +++ b/po/de.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Criterion \n" "Report-Msgid-Bugs-To: franklinmathieu+criterion@gmail.com\n" -"POT-Creation-Date: 2016-08-08 15:38+0200\n" +"POT-Creation-Date: 2016-09-03 20:06+0200\n" "PO-Revision-Date: 2016-02-12 11:12+0100\n" "Last-Translator: \n" "Language-Team: German\n" @@ -181,7 +181,7 @@ msgstr "Die Anweisung `%1$s` hat eine Instanz der Ausname `%2$s` geworfen." msgid "The statement `%1$s` did not throw an instance of the `%2$s` exception." msgstr "Die Anweisung `%1$s` hat keine Instanz der Ausname `%2$s` geworfen." -#: src/core/runner.c:62 +#: src/core/runner.c:68 #, c-format msgid "" "%1$sWarning! Criterion has detected that it is running under valgrind, but " diff --git a/po/fr.po b/po/fr.po index 1958818..f501e09 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: criterion 2.0.0\n" "Report-Msgid-Bugs-To: franklinmathieu+criterion@gmail.com\n" -"POT-Creation-Date: 2016-08-08 15:38+0200\n" +"POT-Creation-Date: 2016-09-03 20:06+0200\n" "PO-Revision-Date: 2015-04-03 17:58+0200\n" "Last-Translator: \n" "Language-Team: French\n" @@ -183,7 +183,7 @@ msgstr "L'instruction `%1$s` a levé une instance de l'exception `%2$s`." msgid "The statement `%1$s` did not throw an instance of the `%2$s` exception." msgstr "L'instruction `%1$s` n'a pas levé d'instance de l'exception `%2$s`." -#: src/core/runner.c:62 +#: src/core/runner.c:68 #, c-format msgid "" "%1$sWarning! Criterion has detected that it is running under valgrind, but " diff --git a/src/compat/section-elf.c b/src/compat/section-elf.c new file mode 100644 index 0000000..5152796 --- /dev/null +++ b/src/compat/section-elf.c @@ -0,0 +1,167 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2016 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +# include "section.h" + +# include +# include +# include +# include + +static int open_self(void) { +#if defined __linux__ + return open("/proc/self/exe", O_RDONLY); +#elif defined __NetBSD__ + return open("/proc/curproc/exe", O_RDONLY) +#elif defined __FreeBSD__ + int fd = open("/proc/curproc/file", O_RDONLY); + /* Fallback */ + if (fd == -1 && errno == ENOENT) { + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + char path[PATH_MAX]; + size_t cb = sizeof (path); + sysctl(mib, sizeof (mib) / sizeof (int), path, &cb, NULL, 0); + fd = open(path, O_RDONLY); + } + return fd; +#elif defined __OpenBSD__ || defined __DragonFly__ + return open("/proc/curproc/file", O_RDONLY) +#else + return -1; +#endif +} + +static int open_module_map(mod_handle *mod) +{ + /* Load the ELF header and the section header table */ + const ElfW(Ehdr) *elf = mmap(NULL, sizeof (ElfW(Ehdr)), + PROT_READ, MAP_PRIVATE, mod->fd, 0); + const void *oldm = elf; + + if (elf == MAP_FAILED) + goto fail; + + if (memcmp(elf->e_ident, (char [4]) { 0x7f, 'E', 'L', 'F' }, 4)) + goto fail; + + size_t new_map_len = elf->e_shoff + elf->e_shnum * elf->e_shentsize; + +#ifdef HAVE_MREMAP + elf = mremap((void*) elf, sizeof (ElfW(Ehdr)), new_map_len, MREMAP_MAYMOVE); +#else + elf = mmap(NULL, new_map_len, PROT_READ, MAP_PRIVATE, mod->fd, 0); +#endif + + if (elf == MAP_FAILED) + goto fail; + +#ifndef HAVE_MREMAP + munmap((void *) oldm, sizeof (ElfW(Ehdr))); +#else + (void) oldm; +#endif + + mod->len = new_map_len; + mod->map = elf; + return 1; + +fail: + munmap((void *) elf, sizeof (ElfW(Ehdr))); + return 0; +} + +static void close_module_map(mod_handle *mod) +{ + munmap((void *) mod->map, mod->len); +} + +int open_module_self(mod_handle *mod) +{ + int fd = open_self(); + if (fd == -1) + return 0; + + mod->fd = fd; + return open_module_map(mod); +} + +void close_module(mod_handle *mod) +{ + close_module_map(mod); + close(mod->fd); +} + +static const void *map_shdr(int fd, const ElfW(Shdr) *shdr, struct section_mapping *out) +{ + size_t shdr_map_off = shdr->sh_offset & ~0xfffllu; + size_t shdr_map_len = shdr->sh_size + (shdr->sh_offset - shdr_map_off); + + const uint8_t *shdr_map = mmap(NULL, shdr_map_len, + PROT_READ, MAP_PRIVATE, fd, shdr_map_off); + + if (shdr_map == MAP_FAILED) + return NULL; + + *out = (struct section_mapping) { + .map = shdr_map, + .len = shdr_map_len + }; + + return shdr_map + (shdr->sh_offset - shdr_map_off); +} + +static void unmap_shdr(struct section_mapping *map) +{ + munmap((void*) map->map, map->len); +} + +void *map_section_data(mod_handle *mod, const char *name, + struct section_mapping *map) +{ + const ElfW(Shdr) *shdr = (void *) ((char *) mod->map + mod->map->e_shoff); + const ElfW(Shdr) *shstr_shdr = shdr + mod->map->e_shstrndx; + + struct section_mapping shstr_map; + const char *shstr = map_shdr(mod->fd, shstr_shdr, &shstr_map); + + const void *ptr = NULL; + for (size_t i = 0; i < mod->map->e_shnum; i++) { + const char *section_name = shstr + shdr[i].sh_name; + if (!strcmp(section_name, name)) { + const ElfW(Shdr) *hdr = shdr + i; + ptr = map_shdr(mod->fd, hdr, map); + map->sec_len = hdr->sh_size; + break; + } + } + + unmap_shdr(&shstr_map); + return (void *)ptr; +} + +void unmap_section_data(struct section_mapping *map) +{ + unmap_shdr(map); +} + + diff --git a/src/compat/section-mach-o.c b/src/compat/section-mach-o.c new file mode 100644 index 0000000..3350384 --- /dev/null +++ b/src/compat/section-mach-o.c @@ -0,0 +1,104 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2016 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include + +#include "section.h" + +#ifdef __LP64__ +typedef struct mach_header_64 mach_hdr; +typedef struct section_64 section; +#else +typedef struct mach_header mach_hdr; +typedef struct section section; +#endif + +static inline void *get_real_address(int lib, void *addr) { + if (!addr) + return NULL; + + // We need to slide the section address to get a valid pointer + // because ASLR will shift the image by a random offset + return addr + _dyld_get_image_vmaddr_slide(lib); +} + +static inline void *ptr_add(const void *ptr, size_t off) +{ + return (char *) ptr + off; +} + +int open_module_self(mod_handle *mod) +{ + *mod = 0; + return 1; +} + +void close_module(mod_handle *mod) +{ + (void) mod; +} + +void *map_section_data(mod_handle *mod, const char *name, + struct section_mapping *map) +{ + (void) map; + + const struct mach_header *hdr = _dyld_get_image_header(*mod); + const struct load_command *lc = ptr_add(hdr, sizeof (mach_hdr)); + for (size_t i = 0; i < hdr->ncmds; ++i, lc = ptr_add(lc, lc->cmdsize)) { + if (lc->cmd == LC_SEGMENT) { + const struct segment_command *sc = (void *) lc; + if (strncmp("__DATA", sc->segname, 16)) + continue; + const struct section *s = ptr_add(sc, sizeof (*sc)); + for (size_t j = 0; j < sc->nsects; ++j, ++s) { + if (strncmp(name, s->sectname, 16)) + continue; + + map->sec_len = s->size; + return get_real_address(*mod, (void *)(uintptr_t) s->addr); + } + } else if (lc->cmd == LC_SEGMENT_64) { + const struct segment_command_64 *sc = (void *) lc; + if (strncmp("__DATA", sc->segname, 16)) + continue; + const struct section_64 *s = ptr_add(sc, sizeof (*sc)); + for (size_t j = 0; j < sc->nsects; ++j, ++s) { + if (strncmp(name, s->sectname, 16)) + continue; + + map->sec_len = s->size; + return get_real_address(*mod, (void *)(uintptr_t) s->addr); + } + } + } + return NULL; +} + +void unmap_section_data(struct section_mapping *map) +{ + (void) map; +} diff --git a/src/compat/section-pe.c b/src/compat/section-pe.c new file mode 100644 index 0000000..0344d2c --- /dev/null +++ b/src/compat/section-pe.c @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2016 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "section.h" +#include + +int open_module_self(mod_handle *mod) +{ + *mod = GetModuleHandle(NULL); + return 1; +} + +void close_module(mod_handle *mod) +{ + (void) mod; +} + +void *map_section_data(mod_handle *mod, const char *name, + struct section_mapping *map) +{ + PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER) *mod; + PIMAGE_NT_HEADERS nt_hdr = (PIMAGE_NT_HEADERS) ((uintptr_t) dos_hdr + + dos_hdr->e_lfanew); + + PIMAGE_SECTION_HEADER sec_hdr = IMAGE_FIRST_SECTION(nt_hdr); + for(int i = 0; i < nt_hdr->FileHeader.NumberOfSections; i++, sec_hdr++) { + if (!strncmp((char *) sec_hdr->Name, name, IMAGE_SIZEOF_SHORT_NAME)) { + map->sec_len = sec_hdr->SizeOfRawData; + return (char *) dos_hdr + sec_hdr->VirtualAddress; + } + } + return NULL; +} + +void unmap_section_data(struct section_mapping *map) +{ + (void) map; +} diff --git a/src/compat/section.c b/src/compat/section.c index 9323a42..047ad7e 100644 --- a/src/compat/section.c +++ b/src/compat/section.c @@ -21,69 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include "section.h" -#include "internal.h" -#ifdef _WIN32 -void *get_win_section_start(const char *section) { - PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL); - PIMAGE_NT_HEADERS ntHeader = ntHeader = (PIMAGE_NT_HEADERS) ((uintptr_t)(dosHeader) + (dosHeader->e_lfanew)); - - assert(dosHeader->e_magic == IMAGE_DOS_SIGNATURE); - assert(ntHeader->Signature == IMAGE_NT_SIGNATURE); - - PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader); - for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) { - if (!strncmp((char*) pSecHeader->Name, section, 8)) { - return (char*) dosHeader + pSecHeader->VirtualAddress; - } - } - return NULL; -} - -void *get_win_section_end(const char *section) { - PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL); - PIMAGE_NT_HEADERS ntHeader = ntHeader = (PIMAGE_NT_HEADERS) ((uintptr_t)(dosHeader) + (dosHeader->e_lfanew)); - - assert(dosHeader->e_magic == IMAGE_DOS_SIGNATURE); - assert(ntHeader->Signature == IMAGE_NT_SIGNATURE); - - PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(ntHeader); - for(int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++, pSecHeader++) { - if (!strncmp((char*) pSecHeader->Name, section, 8)) { - return (char*) dosHeader + (size_t) pSecHeader->VirtualAddress + pSecHeader->SizeOfRawData; - } - } - return NULL; -} +#if defined (__ELF__) +# include "section-elf.c" +#elif defined (__APPLE__) +# include "section-mach-o.c" +#elif defined (_WIN32) +# include "section-pe.c" +#else +# error Unsupported executable format #endif - -#ifdef __APPLE__ -# include -# include - -# define BASE_IMAGE_INDEX 0 - -static inline void *get_real_address(void *addr) { - if (!addr) - return NULL; - - // We need to slide the section address to get a valid pointer - // because ASLR will shift the image by a random offset - return addr + _dyld_get_image_vmaddr_slide(BASE_IMAGE_INDEX); -} - -void *get_osx_section_start(const char *section) { - unsigned long secsize; - return get_real_address(getsectdata("__DATA", section, &secsize)); -} - -void *get_osx_section_end(const char *section) { - unsigned long secsize; - char *section_start = getsectdata("__DATA", section, &secsize); - return get_real_address(section_start) + secsize; -} -#endif - diff --git a/src/compat/section.h b/src/compat/section.h index 37666b6..bdb13ce 100644 --- a/src/compat/section.h +++ b/src/compat/section.h @@ -24,25 +24,36 @@ #ifndef SECTION_H_ # define SECTION_H_ -# include "criterion/internal/common.h" +# include "config.h" -# ifdef _WIN32 -void *get_win_section_start(const char *section); -void *get_win_section_end(const char *section); -# define CR_STRINGIFY_(Param) #Param -# define CR_STRINGIFY(Param) CR_STRINGIFY_(Param) -# define GET_SECTION_START(Name) get_win_section_start(CR_STRINGIFY(Name)) -# define GET_SECTION_END(Name) get_win_section_end(CR_STRINGIFY(Name)) -# elif defined(__APPLE__) -void *get_osx_section_start(const char *section); -void *get_osx_section_end(const char *section); -# define CR_STRINGIFY_(Param) #Param -# define CR_STRINGIFY(Param) CR_STRINGIFY_(Param) -# define GET_SECTION_START(Name) get_osx_section_start(CR_STRINGIFY(Name)) -# define GET_SECTION_END(Name) get_osx_section_end(CR_STRINGIFY(Name)) -# else -# define GET_SECTION_START(Name) CR_SECTION_START(Name) -# define GET_SECTION_END(Name) CR_SECTION_END(Name) +# if defined (__ELF__) +# define MODULE_INVALID NULL +# include + +typedef struct mod_handle { + int fd; + const ElfW(Ehdr) *map; + size_t len; +} mod_handle; +# elif defined (__APPLE__) +# define MODULE_INVALID -1 +typedef int mod_handle; +# elif defined (_WIN32) +# include +# define MODULE_INVALID NULL +typedef HMODULE mod_handle; # endif +struct section_mapping { + const void *map; + size_t len; + size_t sec_len; +}; + +int open_module_self(mod_handle *mod); +void close_module(mod_handle *mod); +void *map_section_data(mod_handle *mod, const char *name, + struct section_mapping *map); +void unmap_section_data(struct section_mapping *map); + #endif /* !SECTION_H_ */ diff --git a/src/core/report.c b/src/core/report.c index fc4bdba..e07ce42 100644 --- a/src/core/report.c +++ b/src/core/report.c @@ -33,42 +33,24 @@ #include "config.h" #include "compat/posix.h" -#define IMPL_CALL_REPORT_HOOKS(Kind) \ - CR_IMPL_SECTION_LIMITS(f_report_hook, CR_HOOK_SECTION(Kind)); \ - void call_report_hooks_##Kind(void *data) { \ - for (f_report_hook *hook = GET_SECTION_START(CR_HOOK_SECTION(Kind)); \ - hook < (f_report_hook*) GET_SECTION_END(CR_HOOK_SECTION(Kind)); \ - ++hook) { \ - (*hook ? *hook : nothing)(data); \ - } \ +#define CR_HSEC_STR(Kind) CR_HSEC_STR_(CR_HOOK_SECTION(Kind)) +#define CR_HSEC_STR_(S) CR_HSEC_STR__(S) +#define CR_HSEC_STR__(S) #S + +#define IMPL_CALL_REPORT_HOOKS(Kind) \ + void call_report_hooks_##Kind(void *data) { \ + mod_handle self; \ + struct section_mapping sect; \ + if (!open_module_self(&self)) \ + abort(); \ + void *start = map_section_data(&self, CR_HSEC_STR(Kind), §); \ + if (!start) \ + return; \ + void *end = (char *)start + sect.sec_len; \ + for (f_report_hook *hook = start; hook < (f_report_hook*) end; ++hook) \ + (*hook ? *hook : nothing)(data); \ } -#ifdef _MSC_VER -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(PRE_ALL)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(PRE_SUITE)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(PRE_INIT)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(PRE_TEST)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(ASSERT)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(THEORY_FAIL)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(TEST_CRASH)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(POST_TEST)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(POST_FINI)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(POST_SUITE)); -f_report_hook CR_SECTION_START_(CR_HOOK_SECTION(POST_ALL)); - -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(PRE_ALL)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(PRE_SUITE)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(PRE_INIT)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(PRE_TEST)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(ASSERT)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(THEORY_FAIL)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(TEST_CRASH)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(POST_TEST)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(POST_FINI)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(POST_SUITE)); -f_report_hook CR_SECTION_END_(CR_HOOK_SECTION(POST_ALL)); -#endif - IMPL_CALL_REPORT_HOOKS(PRE_ALL) IMPL_CALL_REPORT_HOOKS(PRE_SUITE) IMPL_CALL_REPORT_HOOKS(PRE_INIT) diff --git a/src/core/report.h b/src/core/report.h index 68fa19a..f573e13 100644 --- a/src/core/report.h +++ b/src/core/report.h @@ -31,7 +31,6 @@ # define report_(Kind, Data) call_report_hooks_##Kind(Data) # define DECL_CALL_REPORT_HOOKS(Kind) \ - CR_DECL_SECTION_LIMITS(f_report_hook, CR_HOOK_SECTION(Kind)); \ void call_report_hooks_##Kind(void *data) DECL_CALL_REPORT_HOOKS(PRE_ALL); diff --git a/src/core/runner.c b/src/core/runner.c index 2946655..ec57afd 100644 --- a/src/core/runner.c +++ b/src/core/runner.c @@ -74,17 +74,6 @@ static msg_t msg_valgrind_jobs = "%sWarning! Criterion has detected " "explicitely set. Reports might appear confusing!%s\n"; #endif - -#ifdef _MSC_VER -struct criterion_test *CR_SECTION_START_(cr_tst); -struct criterion_suite *CR_SECTION_START_(cr_sts); -struct criterion_test *CR_SECTION_END_(cr_tst); -struct criterion_suite *CR_SECTION_END_(cr_sts); -#endif - -CR_IMPL_SECTION_LIMITS(struct criterion_test*, cr_tst); -CR_IMPL_SECTION_LIMITS(struct criterion_suite*, cr_sts); - // This is here to make the test suite & test sections non-empty CR_SECTION_("cr_sts") struct criterion_suite *dummy_suite = NULL; CR_SECTION_("cr_tst") struct criterion_test *dummy_test = NULL; @@ -131,7 +120,16 @@ CR_API void criterion_register_test(struct criterion_test_set *set, struct criterion_test_set *criterion_init(void) { struct criterion_ordered_set *suites = new_ordered_set(cmp_suite, dtor_suite_set); - FOREACH_SUITE_SEC(s) { + mod_handle self; + + if (!open_module_self(&self)) + cr_panic("Could not open self executable file"); + + struct section_mapping suite_sect = { .sec_len = 0 }; + void *suite_start = map_section_data(&self, "cr_sts", &suite_sect); + void *suite_end = (char *) suite_start + suite_sect.sec_len; + + FOREACH_SUITE_SEC(s, suite_start, suite_end) { if (!*s || !*(*s)->name) continue; @@ -151,7 +149,11 @@ struct criterion_test_set *criterion_init(void) { 0, }; - FOREACH_TEST_SEC(test) { + struct section_mapping test_sect = { .sec_len = 0 }; + void *test_start = map_section_data(&self, "cr_tst", &test_sect); + void *test_end = (char *) test_start + test_sect.sec_len; + + FOREACH_TEST_SEC(test, test_start, test_end) { if (!*test) continue; diff --git a/src/core/runner.h b/src/core/runner.h index fca8a70..c479641 100644 --- a/src/core/runner.h +++ b/src/core/runner.h @@ -27,19 +27,16 @@ # include "criterion/types.h" # include "compat/pipe.h" -CR_DECL_SECTION_LIMITS(struct criterion_test*, cr_tst); -CR_DECL_SECTION_LIMITS(struct criterion_suite*, cr_sts); - struct criterion_test_set *criterion_init(void); -# define FOREACH_TEST_SEC(Test) \ - for (struct criterion_test **Test = GET_SECTION_START(cr_tst); \ - Test < (struct criterion_test**) GET_SECTION_END(cr_tst); \ +# define FOREACH_TEST_SEC(Test, Start, End) \ + for (struct criterion_test **Test = Start; \ + Test < (struct criterion_test**) End; \ ++Test) -# define FOREACH_SUITE_SEC(Suite) \ - for (struct criterion_suite **Suite = GET_SECTION_START(cr_sts); \ - Suite < (struct criterion_suite**) GET_SECTION_END(cr_sts); \ +# define FOREACH_SUITE_SEC(Suite, Start, End) \ + for (struct criterion_suite **Suite = Start; \ + Suite < (struct criterion_suite**) End; \ ++Suite) #endif /* !CRITERION_RUNNER_H_ */