diff options
author | Stefan Bucur <stefanb@zytor.com> | 2008-06-09 17:55:57 +0300 |
---|---|---|
committer | Stefan Bucur <stefanb@zytor.com> | 2008-06-09 17:55:57 +0300 |
commit | e4642a4d0fac67f22e2e63cbcaea915c507e241e (patch) | |
tree | 7457b6fd2d29401b73d4780497fb0a45a5ac3954 /elf | |
parent | 80a1747d4b8c5149af0c6101fa5110dcda85d2fe (diff) | |
download | syslinux-elf-e4642a4d0fac67f22e2e63cbcaea915c507e241e.tar.gz syslinux-elf-e4642a4d0fac67f22e2e63cbcaea915c507e241e.tar.xz syslinux-elf-e4642a4d0fac67f22e2e63cbcaea915c507e241e.zip |
Created the basic module infrastructure.
Diffstat (limited to 'elf')
-rw-r--r-- | elf/Makefile | 29 | ||||
-rw-r--r-- | elf/elf_module.c | 211 | ||||
-rw-r--r-- | elf/elf_module.h | 58 | ||||
-rw-r--r-- | elf/elftest.c | 88 | ||||
-rw-r--r-- | elf/hello.c | 13 | ||||
-rw-r--r-- | elf/linux_list.h | 450 |
6 files changed, 785 insertions, 64 deletions
diff --git a/elf/Makefile b/elf/Makefile index 3c793d65..0cab8eab 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -1,37 +1,52 @@ ## License would go here +######## # Tools CC = gcc RM = rm -f - +################ # Build options -CFLAGS = -Wall +CFLAGS = -Wall -DELF_USERSPACE_TEST LDFLAGS = - +################## # Generated files # Test executable name TESTPROG = elftest +# Test module name +TESTMODULE = hello.so +############### # Make targets -.PHONY: all test clean +.PHONY: all test-prog test-module clean + +all: test-prog test-module -all: test -test: $(TESTPROG) +# The testing user-space application +test-prog: $(TESTPROG) -$(TESTPROG): elftest.o +$(TESTPROG): elftest.o elf_module.o $(CC) -o $@ $^ + +# The shared module to test on +test-module: $(TESTMODULE) + +$(TESTMODULE): hello.o + $(CC) -shared -o $@ $^ + +# Cleanup target clean: -$(RM) *.o -$(RM) $(TESTPROG) + -$(RM) $(TESTMODULE) diff --git a/elf/elf_module.c b/elf/elf_module.c new file mode 100644 index 00000000..de5a311a --- /dev/null +++ b/elf/elf_module.c @@ -0,0 +1,211 @@ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <elf.h> + +#ifdef ELF_USERSPACE_TEST + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> + +#endif //ELF_USERSPACE_TEST + +#include "linux_list.h" +#include "elf_module.h" + + +// The list of loaded modules +static LIST_HEAD(modules); + + +// User-space debugging routines +#ifdef ELF_USERSPACE_TEST +static void print_elf_ehdr(Elf32_Ehdr *ehdr) { + int i; + + printf("Identification:\t"); + for (i=0; i < EI_NIDENT; i++) { + printf("%d ", ehdr->e_ident[i]); + } + printf("\n"); + printf("Type:\t\t%u\n", ehdr->e_type); + printf("Machine:\t%u\n", ehdr->e_machine); + printf("Version:\t%u\n", ehdr->e_version); + printf("Entry:\t\t0x%08x\n", ehdr->e_entry); + printf("PHT Offset:\t0x%08x\n", ehdr->e_phoff); + printf("SHT Offset:\t0x%08x\n", ehdr->e_shoff); + printf("Flags:\t\t%u\n", ehdr->e_flags); + printf("Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize, + sizeof(Elf32_Ehdr)); +} +#endif //ELF_USERSPACE_TEST + +#ifdef ELF_USERSPACE_TEST +static int load_image(struct elf_module *module) { + char file_name[MODULE_NAME_SIZE+3]; // Include the extension + struct stat elf_stat; + + strcpy(file_name, module->name); + strcat(file_name, ".so"); + + module->file_fd = open(file_name, O_RDONLY); + + if (module->file_fd < 0) { + perror("Could not open object file"); + goto error; + } + + if (fstat(module->file_fd, &elf_stat) < 0) { + perror("Could not get file information"); + goto error; + } + + module->file_size = elf_stat.st_size; + + module->file_image = mmap(NULL, module->file_size, PROT_READ, MAP_PRIVATE, + module->file_fd, 0); + + if (module->file_image == NULL) { + perror("Could not map the file into memory"); + goto error; + } + + return 0; + +error: + if (module->file_image != NULL) { + munmap(module->file_image, module->file_size); + module->file_image = NULL; + } + + if (module->file_fd > 0) { + close(module->file_fd); + module->file_fd = 0; + } + return -1; +} + + +static int unload_image(struct elf_module *module) { + munmap(module->file_image, module->file_size); + module->file_image = NULL; + + close(module->file_fd); + module->file_fd = 0; + + return 0; +} + + +#else +static int load_image(struct elf_module *module) { + // TODO: Implement SYSLINUX specific code here + return 0; +} + +static int unload_image(struct elf_module *module) { + // TODO: Implement SYSLINUX specific code here + return 0; +} +#endif //ELF_USERSPACE_TEST + + +// Initialization of the module subsystem +int modules_init() { + return 0; +} + +// Termination of the module subsystem +void modules_term() { + +} + +// Allocates the structure for a new module +struct elf_module *module_alloc(const char *name) { + struct elf_module *result = malloc(sizeof(struct elf_module)); + + memset(result, 0, sizeof(struct elf_module)); + + strncpy(result->name, name, MODULE_NAME_SIZE); + + return result; +} + +static int check_header(Elf32_Ehdr *elf_hdr) { + + // Check the header magic + if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 || + elf_hdr->e_ident[EI_MAG1] != ELFMAG1 || + elf_hdr->e_ident[EI_MAG2] != ELFMAG2 || + elf_hdr->e_ident[EI_MAG3] != ELFMAG3) { + + fprintf(stderr, "Invalid ELF magic\n"); + return -1; + } + + if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) { + fprintf(stderr, "Invalid ELF class code\n"); + return -1; + } + + if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) { + fprintf(stderr, "Invalid ELF data encoding\n"); + return -1; + } + + if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION) { + fprintf(stderr, "Invalid ELF file version\n"); + return -1; + } + + return 0; +} + +// Loads the module into the system +int module_load(struct elf_module *module) { + int res; + Elf32_Ehdr *elf_hdr; + + INIT_LIST_HEAD(&module->list); + INIT_LIST_HEAD(&module->deps); + + res = load_image(module); + + if (res < 0) { + return res; + } + + elf_hdr = (Elf32_Ehdr*)module->file_image; + + res = check_header(elf_hdr); + + if (res < 0) { + goto error; + } + + print_elf_ehdr(elf_hdr); + + res = unload_image(module); + + if (res < 0) { + return res; + } + + return 0; + +error: + unload_image(module); + + return res; +} + +// Unloads the module from the system and releases all the associated memory +int module_unload(struct elf_module *module) { + + free(module); + + return 0; +} diff --git a/elf/elf_module.h b/elf/elf_module.h new file mode 100644 index 00000000..fd0e15c5 --- /dev/null +++ b/elf/elf_module.h @@ -0,0 +1,58 @@ +#ifndef ELF_MODULE_H_ +#define ELF_MODULE_H_ + +#include <elf.h> +#include <stdint.h> +#include "linux_list.h" + +#define MODULE_NAME_SIZE 64 + +#define MODULE_ELF_CLASS ELFCLASS32 +#define MODULE_ELF_DATA ELFDATA2LSB +#define MODULE_ELF_VERSION EV_CURRENT + + +typedef int (*module_init_func)(); +typedef void (*module_exit_func)(); + +// Structure encapsulating a module loaded in memory +struct elf_module { + char name[MODULE_NAME_SIZE]; // The module name + + struct list_head deps; // Head of module dependency list + struct list_head list; // The list entry in the module list + + module_init_func init_func; // The initialization entry point + module_exit_func exit_func; // The module finalization code + + void *file_image; // The image of the module file in memory + uint32_t file_size; // The size of the module file + + // Information for modules loaded in user space +#ifdef ELF_USERSPACE_TEST + int file_fd; // The file descriptor of the open file +#endif +}; + +// Structure encapsulating a module dependency need +struct module_dep { + struct list_head list; // The list entry in the dependency list + + char name[MODULE_NAME_SIZE]; // The name of the module +}; + +// Initialization of the module subsystem +extern int modules_init(); +// Termination of the module subsystem +extern void modules_term(); + +// Allocates the structure for a new module +extern struct elf_module *module_alloc(const char *name); + +// Loads the module into the system +extern int module_load(struct elf_module *module); + +// Unloads the module from the system and releases all the associated memory +extern int module_unload(struct elf_module *module); + +#endif /*ELF_MODULE_H_*/ diff --git a/elf/elftest.c b/elf/elftest.c index 5436b40e..6462ad6a 100644 --- a/elf/elftest.c +++ b/elf/elftest.c @@ -7,84 +7,58 @@ #include <fcntl.h> #include <unistd.h> -#include <elf.h> +#include "elf_module.h" void print_usage() { fprintf(stderr, "Usage:\n"); fprintf(stderr, "\telftest objfile\n"); } -void print_elf_info(const char *file_name) { - int elf_fd = open(file_name, O_RDONLY); - void *elf_addr = NULL; - Elf32_Ehdr *elf_header; - struct stat elf_stat; - int i; +int main(int argc, char **argv) { + int res; + struct elf_module *module; + const char *module_name = NULL; - if (elf_fd < 0) { - perror("Could not open object file"); - goto error; + // Skip program name + argc--; + argv++; + + if (argc != 1) { + print_usage(); + return 1; } - if (fstat(elf_fd, &elf_stat) < 0) { - perror("Could not get file information"); - goto error; + module_name = argv[0]; + + res = modules_init(); + + if (res < 0) { + fprintf(stderr, "Could not initialize module subsystem\n"); + exit(1); } - elf_addr = mmap(NULL, elf_stat.st_size, PROT_READ, MAP_PRIVATE, elf_fd, 0); + module = module_alloc(module_name); - if (elf_addr == NULL) { - perror("Could not map the file into memory"); + if (module == NULL) { + fprintf(stderr, "Could not allocate the module\n"); goto error; } - elf_header = (Elf32_Ehdr*)elf_addr; + res = module_load(module); - printf("Identification:\t"); - for (i=0; i < EI_NIDENT; i++) { - printf("%d ", elf_header->e_ident[i]); + if (res < 0) { + fprintf(stderr, "Could not load the module\n"); + goto error; } - printf("\n"); - printf("Type:\t\t%u\n", elf_header->e_type); - printf("Machine:\t%u\n", elf_header->e_machine); - printf("Version:\t%u\n", elf_header->e_version); - printf("Entry:\t\t0x%08x\n", elf_header->e_entry); - printf("PHT Offset:\t0x%08x\n", elf_header->e_phoff); - printf("SHT Offset:\t0x%08x\n", elf_header->e_shoff); - printf("Flags:\t\t%u\n", elf_header->e_flags); - printf("Header size:\t%u (Structure size: %u)\n", elf_header->e_ehsize, - sizeof(Elf32_Ehdr)); + module_unload(module); - munmap(elf_addr, elf_stat.st_size); - close(elf_fd); + modules_term(); - return; + return 0; error: - if (elf_addr != NULL) - munmap(elf_addr, elf_stat.st_size); - - if (elf_fd >= 0) - close(elf_fd); - exit(2); -} - -int main(int argc, char **argv) { - const char *file_name = NULL; - - // Skip program name - argc--; - argv++; + modules_term(); - if (argc != 1) { - print_usage(); - return 1; - } - - file_name = argv[0]; - - print_elf_info(file_name); - - return 0; + return 1; } diff --git a/elf/hello.c b/elf/hello.c new file mode 100644 index 00000000..d7b46c04 --- /dev/null +++ b/elf/hello.c @@ -0,0 +1,13 @@ +// A simple Hello World ELF module + +// TODO: Define some macros that would put the initialization and termination +// functions in a separate section (suggestion: .init and .fini) + +int hello_init() { + // Do nothing + return 0; +} + +void hello_exit() { + // Do nothing +} diff --git a/elf/linux_list.h b/elf/linux_list.h new file mode 100644 index 00000000..73c56869 --- /dev/null +++ b/elf/linux_list.h @@ -0,0 +1,450 @@ +// This list structure implementation is adapted from the list implementation +// on the Linux kernel. + +// Original source: +// http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.25.y.git;a=blob_plain;f=include/linux/list.h;hb=HEAD + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#include <stdlib.h> + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = NULL; + entry->prev = NULL; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + prefetch(pos->prev), pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + + +#endif |