/* Simple code to turn various tables in an ELF file into alias definitions.
* This deals with kernel datastructures where they should be
* dealt with: in the kernel source.
*
* Copyright 2002-2003 Rusty Russell, IBM Corporation
* 2003 Kai Germaschewski
*
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#include "modpost.h"
#include "devicetable-offsets.h"
/* We use the ELF typedefs for kernel_ulong_t but bite the bullet and
* use either stdint.h or inttypes.h for the rest. */
#if KERNEL_ELFCLASS == ELFCLASS32
typedef Elf32_Addr kernel_ulong_t;
#define BITS_PER_LONG 32
#else
typedef Elf64_Addr kernel_ulong_t;
#define BITS_PER_LONG 64
#endif
#ifdef __sun__
#include <inttypes.h>
#else
#include <stdint.h>
#endif
#include <ctype.h>
#include <stdbool.h>
typedef uint32_t __u32;
typedef uint16_t __u16;
typedef unsigned char __u8;
/* Big exception to the "don't include kernel headers into userspace, which
* even potentially has different endianness and word sizes, since
* we handle those differences explicitly below */
#include "../../include/linux/mod_devicetable.h"
/* This array collects all instances that use the generic do_table */
struct devtable {
const char *device_id; /* name of table, __mod_<name>__*_device_table. */
unsigned long id_size;
void *function;
};
#define ___cat(a,b) a ## b
#define __cat(a,b) ___cat(a,b)
/* we need some special handling for this host tool running eventually on
* Darwin. The Mach-O section handling is a bit different than ELF section
* handling. The differnces in detail are:
* a) we have segments which have sections
* b) we need a API call to get the respective section symbols */
#if defined(__MACH__)
#include <mach-o/getsect.h>
#define INIT_SECTION(name) do { \
unsigned long name ## _len; \
char *__cat(pstart_,name) = getsectdata("__TEXT", \
#name, &__cat(name,_len)); \
char *__cat(pstop_,name) = __cat(pstart_,name) + \
__cat(name, _len); \
__cat(__start_,name) = (void *)__cat(pstart_,name); \
__cat(__stop_,name) = (void *)__cat(pstop_,name); \
} while (0)
#define SECTION(name) __attribute__((section("__TEXT, " #name)))
struct devtable **__start___devtable, **__stop___devtable;
#else
#define INIT_SECTION(name) /* no-op for ELF */
#define SECTION(name) __attribute__((section(#name)))
/* We construct a table of pointers in an ELF section (pointers generally
* go unpadded by gcc). ld creates boundary syms for us. */
extern struct devtable *__start___devtable[], *__stop___devtable[];
#endif /* __MACH__ */
#if !defined(__used)
# if __GNUC__ == 3 && __GNUC_MINOR__ < 3
# define __used __attribute__((__unused__))
# else
# define __used __attribute__((__used__))
# endif
#endif
/* Define a variable f that holds the value of field f of struct devid
* based at address m.
*/
#define DEF_FIELD(m, devid, f) \
typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f))
/* Define a variable f that holds the address of field f of struct devid
* based at address m. Due to the way typeof works, for a field of type
* T[N] the variable has type T(*)[N], _not_ T*.
*/
#define DEF_FIELD_ADDR(m, devid, f) \
typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f)
/* Add a table entry. We test function type matches while we're here. */
#define ADD_TO_DEVTABLE(device_id, type, function) \
static struct devtable __cat(devtable,__LINE__) = { \
device_id + 0*sizeof((function)((const char *)NULL, \
(void *)NULL, \
(char *)NULL)), \
SIZE_##type, (function) }; \
static struct devtable *SECTION(__devtable) __used \
__cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__)
#define ADD(str, sep, cond, field) \
do { \
strcat(str, sep); \
if (cond) \
sprintf(str + strlen(str), \
sizeof(field) == 1 ? "%02X" : \
sizeof(field) == 2 ? "%04X" : \
sizeof(field) == 4 ? "%08X" : "", \
field); \
else \
sprintf(str + strlen(str), "*"); \
} while(0)
/* Always end in a wildcard, for future extension */
static inline void add_wildcard(char *str)
{
int len = strlen(str);
if (str[len - 1] != '*')
strcat(str + len, "*");
}
/**
* Check that sizeof(device_id type) are consistent with size of section
* in .o file. If in-consistent then userspace and kernel does not agree
* on actual size which is a bug.
* Also verify that the final entry in the table is all zeros.
* Ignore both checks if build host differ from target host and size differs.
**/
static void device_id_check(const char *modname, const char *device_id,
unsigned long size, unsigned long id_size,
void *symval)
{
int i