section: introspect sections without linker extensions. Fixes #91
This commit is contained in:
parent
8882c7d9cc
commit
a3df2ab9a4
12 changed files with 407 additions and 164 deletions
|
@ -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)
|
||||
|
|
4
po/de.po
4
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: <a1lu@arcor.de>\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 "
|
||||
|
|
4
po/fr.po
4
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: <franklinmathieu@gmail.com>\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 "
|
||||
|
|
167
src/compat/section-elf.c
Normal file
167
src/compat/section-elf.c
Normal file
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright © 2016 Franklin "Snaipe" Mathieu <http://snai.pe/>
|
||||
*
|
||||
* 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 <string.h>
|
||||
# include <sys/mman.h>
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
104
src/compat/section-mach-o.c
Normal file
104
src/compat/section-mach-o.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright © 2016 Franklin "Snaipe" Mathieu <http://snai.pe/>
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/getsect.h>
|
||||
#include <mach-o/loader.h>
|
||||
|
||||
#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;
|
||||
}
|
58
src/compat/section-pe.c
Normal file
58
src/compat/section-pe.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright © 2016 Franklin "Snaipe" Mathieu <http://snai.pe/>
|
||||
*
|
||||
* 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 <windows.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -21,69 +21,13 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#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 <mach-o/getsect.h>
|
||||
# include <mach-o/dyld.h>
|
||||
|
||||
# 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
|
||||
|
||||
|
|
|
@ -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 <link.h>
|
||||
|
||||
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 <windows.h>
|
||||
# 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_ */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
Loading…
Add table
Reference in a new issue