Hi,

This patch add a new tool grub-symdb to manage symbol database and
update module dependence as required. The build process is greatly
simplified, moddep.lst, def-*.lst, und-*.lst are not generated
anymore. grub-symdb will read the module files and update modsym.lst
and moddep.lst automatically.

-- 
Bean
diff --git a/Makefile.in b/Makefile.in
index b24ee2e..06478af 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -139,11 +139,9 @@ include $(srcdir)/conf/$(target_cpu)-$(platform).mk
 ### General targets.
 
 CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA)
-pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst handler.lst
-moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep.awk
-	cat $(DEFSYMFILES) /dev/null \
-	  | $(AWK) -f $(srcdir)/genmoddep.awk $(UNDSYMFILES) > $@ \
-	  || (rm -f $@; exit 1)
+pkglib_DATA += modsym.lst command.lst fs.lst partmap.lst handler.lst
+modsym.lst: $(MODFILES) grub-symdb
+	./grub-symdb -d . update $?
 
 command.lst: $(COMMANDFILES)
 	cat $^ /dev/null | sort > $@
diff --git a/conf/common.rmk b/conf/common.rmk
index 0e63da6..20a1b89 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -23,6 +23,10 @@ grub_probe_SOURCES = util/grub-probe.c	\
 	kern/fs.c kern/env.c fs/fshelp.c			\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
 
+# For grub-symdb
+bin_UTILITIES += grub-symdb
+grub_symdb_SOURCES = util/grub-symdb.c util/misc.c util/resolve.c
+
 ifeq ($(enable_grub_fstest), yes)
 bin_UTILITIES += grub-fstest
 endif
diff --git a/genmk.rb b/genmk.rb
index b619421..c119fad 100644
--- a/genmk.rb
+++ b/genmk.rb
@@ -99,18 +99,10 @@ class PModule
     pre_obj = 'pre-' + @name.suffix('o')
     mod_src = 'mod-' + @name.suffix('c')
     mod_obj = mod_src.suffix('o')
-    defsym = 'def-' + @name.suffix('lst')
-    undsym = 'und-' + @name.suffix('lst')
     mod_name = File.basename(@name, '.mod')
     symbolic_name = mod_name.sub(/\.[^\.]*$/, '')
     
-    "CLEANFILES += #...@name} #{mod_obj} #{mod_src} #{pre_obj} #{objs_str} #{undsym}
-ifneq ($(#{prefix}_EXPORTS),no)
-CLEANFILES += #{defsym}
-DEFSYMFILES += #{defsym}
-endif
-MOSTLYCLEANFILES += #{deps_str}
-UNDSYMFILES += #{undsym}
+    "CLEANFILES += #...@name} #{mod_obj} #{mod_src} #{pre_obj} #{objs_str} 
 
 #...@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF)
 	-rm -f $@
@@ -125,17 +117,10 @@ UNDSYMFILES += #{undsym}
 #{mod_obj}: #{mod_src}
 	$(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(#{prefix}_CFLAGS) -c -o $@ $<
 
-#{mod_src}: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
-	sh $(srcdir)/genmodsrc.sh '#{mod_name}' $< > $@ || (rm -f $@; exit 1)
-
-ifneq ($(#{prefix}_EXPORTS),no)
-#{defsym}: #{pre_obj}
-	$(NM) -g --defined-only -P -p $< | sed 's/^\\([^ ]*\\).*/\\1 #{mod_name}/' > $@
-endif
+#{mod_src}: $(srcdir)/genmodsrc.sh
+	sh $(srcdir)/genmodsrc.sh '#{mod_name}' > $@ || (rm -f $@; exit 1)
 
-#{undsym}: #{pre_obj}
-	echo '#{mod_name}' > $@
-	$(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+MODFILES += #...@name}
 
 " + objs.collect_with_index do |obj, i|
       src = sources[i]
diff --git a/genmodsrc.sh b/genmodsrc.sh
index 2d42055..b334c7e 100644
--- a/genmodsrc.sh
+++ b/genmodsrc.sh
@@ -41,7 +41,4 @@ cat <<EOF
 EOF
 
 echo "GRUB_MOD_NAME(${mod_name});"
-
-for mod in `grep "^${mod_name}:" ${deps} | sed 's/^[^:]*://'`; do
-  echo "GRUB_MOD_DEP(${mod});"
-done
+echo 'GRUB_MOD_DEP("");'
diff --git a/include/grub/util/resolve.h b/include/grub/util/resolve.h
index f42df32..80e69e5 100644
--- a/include/grub/util/resolve.h
+++ b/include/grub/util/resolve.h
@@ -32,4 +32,7 @@ grub_util_resolve_dependencies (const char *prefix,
 				const char *dep_list_file,
 				char *modules[]);
 
+char * grub_util_get_module_name (const char *str);
+char * grub_util_get_module_path (const char *prefix, const char *str);
+
 #endif /* ! GRUB_UTIL_RESOLVE_HEADER */
diff --git a/util/grub-symdb.c b/util/grub-symdb.c
new file mode 100644
index 0000000..2d9b0e7
--- /dev/null
+++ b/util/grub-symdb.c
@@ -0,0 +1,1050 @@
+/* grub-symdb.c - manage symbol database  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <grub/types.h>
+#include <grub/elf.h>
+#include <grub/util/misc.h>
+#include <grub/util/resolve.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#define _GNU_SOURCE	1
+#include <getopt.h>
+
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+
+typedef Elf32_Word Elf_Word;
+typedef Elf32_Addr Elf_Addr;
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Shdr Elf_Shdr;
+typedef Elf32_Sym Elf_Sym;
+typedef Elf32_Half Elf_Half;
+typedef Elf32_Off Elf_Off;
+typedef Elf32_Section Elf_Section;
+
+#define ELF_ST_BIND		ELF32_ST_BIND
+#define grub_target_to_host	grub_target_to_host32
+#define grub_host_to_target	grub_host_to_target32
+
+#elif GRUB_TARGET_SIZEOF_VOID_P == 8
+
+typedef Elf64_Word Elf_Word;
+typedef Elf64_Addr Elf_Addr;
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Shdr Elf_Shdr;
+typedef Elf64_Sym Elf_Sym;
+typedef Elf64_Half Elf_Half;
+typedef Elf64_Off Elf_Off;
+typedef Elf64_Section Elf_Section;
+
+#define ELF_ST_BIND		ELF64_ST_BIND
+#define grub_target_to_host	grub_target_to_host64
+#define grub_host_to_target	grub_host_to_target64
+
+#endif
+
+struct grub_symbol_list
+{
+  struct grub_symbol_list *next;
+  char *name;
+  struct grub_named_list *defs;
+  struct grub_named_list *unds;
+};
+
+static struct grub_symbol_list *symbol_list;
+
+struct grub_update_list
+{
+  struct grub_update_list *next;
+  char *name;
+  struct grub_named_list *add_mods;
+  struct grub_named_list *del_mods;
+  struct grub_named_list *cur_mods;
+};
+
+static struct grub_update_list *update_list;
+
+struct grub_mod_syms
+{
+  struct grub_named_list *defs;
+  struct grub_named_list *unds;
+};
+
+static void *
+insert_named_list (grub_named_list_t *head, grub_named_list_t item)
+{
+  grub_named_list_t *p, q;
+
+  for (p = head, q = *p; q; p = &(q->next), q = q->next)
+    {
+      int r;
+
+      r = strcmp (item->name, q->name);
+      if (! r)
+	return q;
+
+      if (r < 0)
+	break;
+    }
+
+  *p = item;
+  item->next = q;
+
+  return item;
+}
+
+static void
+free_named_list (grub_named_list_t *head)
+{
+  grub_named_list_t cur = *head;
+
+  while (cur)
+    {
+      grub_named_list_t tmp;
+
+      tmp = cur;
+      cur = cur->next;
+      free ((char *) tmp->name);
+      free (tmp);
+    }
+
+  *head = 0;
+}
+
+static int
+remove_string (grub_named_list_t *head, char *name)
+{
+  grub_named_list_t *p, q;
+
+  for (p = head, q = *p; q; p = &(q->next), q = q->next)
+    {
+      int r;
+
+      r = strcmp (name, q->name);
+      if (! r)
+	{
+	  *p = q->next;
+	  free ((char *) q->name);
+	  free (q);
+
+	  return 1;
+	}
+
+      if (r < 0)
+	break;
+    }
+
+  return 0;
+}
+
+static int
+insert_string (grub_named_list_t *head, char *name)
+{
+  struct grub_named_list *item, *n;
+
+  item = xmalloc (sizeof (struct grub_named_list));
+  item->name = xstrdup (name);
+
+  n = insert_named_list (head, item);
+  if (n != item)
+    {
+      free ((char *) item->name);
+      free (item);
+
+      return 0;
+    }
+
+  return 1;
+}
+
+static struct grub_symbol_list *
+insert_symbol (char *name)
+{
+  struct grub_symbol_list *s, *n;
+
+  s = xmalloc (sizeof (struct grub_symbol_list));
+  s->name = xstrdup (name);
+  s->defs = 0;
+  s->unds = 0;
+
+  n = insert_named_list (GRUB_AS_NAMED_LIST_P (&symbol_list),
+			 GRUB_AS_NAMED_LIST (s));
+
+  if (n != s)
+    {
+      free (s->name);
+      free (s);
+    }
+
+  return n;
+}
+
+static struct grub_update_list *
+insert_update (char *name)
+{
+  struct grub_update_list *u, *n;
+
+  u = xmalloc (sizeof (struct grub_update_list));
+  u->name = xstrdup (name);
+  u->add_mods = 0;
+  u->del_mods = 0;
+  u->cur_mods = 0;
+
+  n = insert_named_list (GRUB_AS_NAMED_LIST_P (&update_list),
+			 GRUB_AS_NAMED_LIST (u));
+
+  if (n != u)
+    {
+      free (u->name);
+      free (u);
+    }
+
+  return n;
+}
+
+static void
+add_update (char *m1, char *m2, int is_add)
+{
+  struct grub_update_list *u;
+
+  u = insert_update (m2);
+  if (is_add)
+    {
+      remove_string (&u->del_mods, m1);
+      insert_string (&u->add_mods, m1);
+    }
+  else
+    insert_string (&u->del_mods, m1);
+}
+
+static void
+read_symdb (char *path)
+{
+  FILE *fp;
+  char line[512];
+  struct grub_symbol_list *sym = 0;
+
+  fp = fopen (path, "r");
+  if (! fp)
+    return;
+
+  while (fgets (line, sizeof (line), fp))
+    {
+      char *p;
+
+      p = line + strlen (line) - 1;
+      while ((p >= line) && ((*p == '\r') || (*p == '\n') || (*p == ' ')))
+	p--;
+
+      if (p < line)
+	continue;
+
+      *(p + 1) = 0;
+
+      p = line;
+      while (*p == ' ')
+	p++;
+
+      if (*p == '#')
+	continue;
+
+      if ((*p == '+') || (*p == '-'))
+	{
+	  if (! sym)
+	    grub_util_error ("No current symbol.");
+
+	  insert_string ((*p == '+') ? &sym->defs : &sym->unds, p + 1);
+	}
+      else
+	sym = insert_symbol (p);
+    }
+
+  fclose (fp);
+}
+
+static void
+write_symdb (char *path)
+{
+  FILE *fp;
+  struct grub_symbol_list *sym;
+
+  fp = fopen (path, "w");
+  if (! fp)
+    grub_util_error ("Can\'t write to ", path);
+
+  sym = symbol_list;
+  while (sym)
+    {
+      struct grub_named_list *mod;
+
+      fprintf (fp, "%s\n", sym->name);
+      mod = sym->defs;
+      while (mod)
+	{
+	  fprintf (fp, "+%s\n", mod->name);
+	  mod = mod->next;
+	}
+      mod = sym->unds;
+      while (mod)
+	{
+	  fprintf (fp, "-%s\n", mod->name);
+	  mod = mod->next;
+	}
+
+      sym = sym->next;
+    }
+
+  fclose (fp);
+}
+
+static void
+check_symdb (void)
+{
+  struct grub_symbol_list *sym;
+
+  sym = symbol_list;
+  while (sym)
+    {
+      if (! sym->defs)
+	printf ("undefined: %s\n", sym->name);
+      else if (sym->defs->next)
+	printf ("duplicate: %s\n", sym->name);
+
+      sym = sym->next;
+    }
+}
+
+/* Return if the ELF header is valid.  */
+static int
+check_elf_header (Elf_Ehdr *e, size_t size)
+{
+  if (size < sizeof (*e)
+      || e->e_ident[EI_MAG0] != ELFMAG0
+      || e->e_ident[EI_MAG1] != ELFMAG1
+      || e->e_ident[EI_MAG2] != ELFMAG2
+      || e->e_ident[EI_MAG3] != ELFMAG3
+      || e->e_ident[EI_VERSION] != EV_CURRENT
+      || e->e_version != EV_CURRENT)
+     return 0;
+
+  return 1;
+}
+
+/* Return the symbol table section, if any.  */
+static Elf_Shdr *
+find_symtab_section (Elf_Shdr *sections,
+		     Elf_Half section_entsize, Elf_Half num_sections)
+{
+  int i;
+  Elf_Shdr *s;
+
+  for (i = 0, s = sections;
+       i < num_sections;
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+    if (s->sh_type == grub_target_to_host32 (SHT_SYMTAB))
+      return s;
+
+  return 0;
+}
+
+/* Return the address of the string table.  */
+static char *
+find_strtab (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Half section_entsize)
+{
+  Elf_Shdr *s;
+  char *strtab;
+
+  s = (Elf_Shdr *) ((char *) sections
+		    + grub_target_to_host16 (e->e_shstrndx) * section_entsize);
+  strtab = (char *) e + grub_target_to_host (s->sh_offset);
+  return strtab;
+}
+
+static Elf_Shdr *
+find_moddep_section (Elf_Shdr *sections,
+		     Elf_Half section_entsize, Elf_Half num_sections,
+		     char *strtab)
+{
+  int i;
+  Elf_Shdr *s;
+
+  for (i = 0, s = sections;
+       i < num_sections;
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+    {
+      char *name = strtab + grub_target_to_host32 (s->sh_name);
+
+      if (! strcmp (name, ".moddeps"))
+	return s;
+    }
+
+  return 0;
+}
+
+static void
+read_elf_symbols (struct grub_mod_syms *mod_syms,
+		  Elf_Ehdr *e, Elf_Shdr *sections,
+		  Elf_Shdr *symtab_section, Elf_Half section_entsize,
+		  Elf_Half num_sections)
+{
+  Elf_Word symtab_size, sym_size, num_syms;
+  Elf_Off symtab_offset;
+  Elf_Word i;
+  Elf_Sym *sym;
+  Elf_Shdr *strtab_section;
+  const char *strtab;
+
+  strtab_section
+    = (Elf_Shdr *) ((char *) sections
+		    + (grub_target_to_host32 (symtab_section->sh_link)
+		       * section_entsize));
+  strtab = (char *) e + grub_target_to_host32 (strtab_section->sh_offset);
+
+  symtab_size = grub_target_to_host32 (symtab_section->sh_size);
+  sym_size = grub_target_to_host32 (symtab_section->sh_entsize);
+  symtab_offset = grub_target_to_host (symtab_section->sh_offset);
+  num_syms = symtab_size / sym_size;
+
+  for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
+       i < num_syms;
+       i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
+    {
+      Elf_Section index;
+      struct grub_named_list **p = &mod_syms->defs;
+
+      if (ELF_ST_BIND (sym->st_info) == STB_LOCAL)
+	continue;
+
+      index = grub_target_to_host16 (sym->st_shndx);
+      if (index == STN_ABS)
+	{
+	  continue;
+	}
+      else if (index == STN_UNDEF)
+	{
+	  p = &mod_syms->unds;
+	}
+      else if (index >= num_sections)
+	grub_util_error ("section %d does not exist", index);
+
+      insert_string (p,
+		     (char *) (strtab + grub_target_to_host32 (sym->st_name)));
+    }
+}
+
+static void
+read_mod_syms (struct grub_mod_syms *mod_syms, char *path)
+{
+  size_t size;
+  char *image;
+  Elf_Ehdr *e;
+  Elf_Off section_offset;
+  Elf_Half section_entsize;
+  Elf_Half num_sections;
+  Elf_Shdr *sections;
+  Elf_Shdr *symtab_section;
+
+  mod_syms->defs = 0;
+  mod_syms->unds = 0;
+
+  size = grub_util_get_image_size (path);
+  image = grub_util_read_image (path);
+
+  e = (Elf_Ehdr *) image;
+  if (! check_elf_header (e, size))
+    grub_util_error ("invalid ELF header");
+
+  section_offset = grub_target_to_host (e->e_shoff);
+  section_entsize = grub_target_to_host16 (e->e_shentsize);
+  num_sections = grub_target_to_host16 (e->e_shnum);
+
+  if (size < section_offset + section_entsize * num_sections)
+    grub_util_error ("invalid ELF format");
+
+  sections = (Elf_Shdr *) (image + section_offset);
+  symtab_section = find_symtab_section (sections,
+					section_entsize, num_sections);
+  if (! symtab_section)
+    grub_util_error ("no symbol table");
+
+  read_elf_symbols (mod_syms, e, sections, symtab_section, section_entsize,
+		    num_sections);
+
+  free (image);
+}
+
+static void
+update_mods (char *mods[], const char *dir)
+{
+  for (; mods[0]; mods++)
+    {
+      char *mod_name, *mod_path;
+      struct grub_mod_syms mod_syms;
+      struct grub_named_list *m;
+
+      mod_name = grub_util_get_module_name (mods[0]);
+      mod_path = grub_util_get_module_path (dir, mod_name);
+
+      if (! strcmp (mod_name, "grub-symdb"))
+	{
+	  free (mod_name);
+	  free (mod_path);
+	  continue;
+	}
+
+      read_mod_syms (&mod_syms, mod_path);
+
+      m = mod_syms.defs;
+      while (m)
+	{
+	  struct grub_symbol_list *sym;
+	  struct grub_named_list *n;
+
+	  sym = insert_symbol ((char *) m->name);
+	  insert_string (&sym->defs, mod_name);
+
+	  n = sym->unds;
+	  while (n)
+	    {
+	      add_update ((char *) mod_name, (char *) n->name, 1);
+	      n = n->next;
+	    }
+
+	  m = m->next;
+	}
+
+      m = mod_syms.unds;
+      while (m)
+	{
+	  struct grub_symbol_list *sym;
+	  struct grub_named_list *n;
+
+	  sym = insert_symbol ((char *) m->name);
+	  insert_string (&sym->unds, mod_name);
+
+	  n = sym->defs;
+	  while (n)
+	    {
+	      add_update ((char *) n->name, (char *) mod_name, 1);
+	      n = n->next;
+	    }
+
+	  m = m->next;
+	}
+
+      free (mod_name);
+      free (mod_path);
+    }
+}
+
+static void
+remove_mods (char *mods[])
+{
+  for (; mods[0]; mods++)
+    {
+      char *mod_name;
+      struct grub_symbol_list *sym;
+
+      mod_name = grub_util_get_module_name (mods[0]);
+
+      sym = symbol_list;
+      while (sym)
+	{
+	  struct grub_named_list *m, *n;
+
+	  m = sym->defs;
+	  while (m)
+	    {
+	      int r;
+
+	      r = strcmp (mod_name, m->name);
+	      if (! r)
+		break;
+
+	      if (r < 0)
+		{
+		  m = 0;
+		  break;
+		}
+
+	      m = m->next;
+	    }
+
+	  n = sym->unds;
+	  while (n)
+	    {
+	      if (m)
+		{
+		  add_update ((char *) m->name, (char *) n->name, 0);
+		}
+	      else
+		{
+		  int r;
+
+		  r = strcmp (mod_name, n->name);
+		  if (! r)
+		    {
+		      m = sym->defs;
+		      while (m)
+			{
+			  add_update ((char *) m->name, (char *) n->name, 0);
+			  m = m->next;
+			}
+
+		      break;
+		    }
+
+		  if (r < 0)
+		    break;
+		}
+
+	      n = n->next;
+	    }
+
+	  sym = sym->next;
+	}
+
+      free (mod_name);
+    }
+}
+
+static void
+dump_update (void)
+{
+  struct grub_update_list *u;
+
+  u = update_list;
+  while (u)
+    {
+      struct grub_named_list *n;
+
+      printf ("%s:" , u->name);
+      n = u->add_mods;
+      while (n)
+	{
+	  printf (" +%s", n->name);
+	  n = n->next;
+	}
+
+      n = u->del_mods;
+      while (n)
+	{
+	  printf (" -%s", n->name);
+	  n = n->next;
+	}
+
+      printf ("\n");
+      u = u->next;
+    }
+}
+
+static void
+update_deps (struct grub_update_list *u, char *path)
+{
+  size_t size;
+  char *image;
+  Elf_Ehdr *e;
+  Elf_Off section_offset;
+  Elf_Half section_entsize;
+  Elf_Half num_sections;
+  Elf_Shdr *sections;
+  Elf_Shdr *moddep_section;
+  char *strtab, *pb, *pe;
+  struct grub_named_list *n;
+  int modified;
+
+  size = grub_util_get_image_size (path);
+  image = grub_util_read_image (path);
+
+  e = (Elf_Ehdr *) image;
+  if (! check_elf_header (e, size))
+    grub_util_error ("invalid ELF header");
+
+  section_offset = grub_target_to_host (e->e_shoff);
+  section_entsize = grub_target_to_host16 (e->e_shentsize);
+  num_sections = grub_target_to_host16 (e->e_shnum);
+
+  if (size < section_offset + section_entsize * num_sections)
+    grub_util_error ("invalid ELF format");
+
+  sections = (Elf_Shdr *) (image + section_offset);
+  strtab = find_strtab (e, sections, section_entsize);
+
+  moddep_section = find_moddep_section (sections, section_entsize,
+					num_sections, strtab);
+  if (! moddep_section)
+    grub_util_error ("no .moddeps section");
+
+  pb = (char *) e + grub_target_to_host (moddep_section->sh_offset);
+  pe = pb + grub_target_to_host32 (moddep_section->sh_size);
+  while (pb < pe)
+    {
+      if (! *pb)
+	break;
+
+      insert_string (&u->cur_mods, pb);
+      pb += strlen (pb) + 1;
+    }
+
+  modified = 0;
+  n = u->del_mods;
+  while (n)
+    {
+      modified += remove_string (&u->cur_mods, (char *) n->name);
+      n = n->next;
+    }
+  n = u->add_mods;
+  while (n)
+    {
+      modified += insert_string (&u->cur_mods, (char *) n->name);
+      n = n->next;
+    }
+
+  if (modified)
+    {
+      char *new_image, *p;
+      int old_size, new_size, delta, ofs;
+      Elf_Shdr *s;
+      int i;
+      FILE *fp;
+
+      new_size = 0;
+      n = u->cur_mods;
+      while (n)
+	{
+	  new_size += strlen (n->name) + 1;
+	  n = n->next;
+	}
+
+      old_size = (int) grub_target_to_host32 (moddep_section->sh_size);
+      delta = new_size - old_size ;
+
+      ofs = grub_target_to_host (moddep_section->sh_offset);
+      new_image = xmalloc ((int) size + delta);
+      e = (Elf_Ehdr *) new_image;
+
+      memcpy (new_image, image, ofs);
+
+      p = new_image + ofs;
+      n = u->cur_mods;
+      while (n)
+	{
+	  strcpy (p, n->name);
+	  p += strlen (p) + 1;
+	  n = n->next;
+	}
+
+      if (ofs + old_size < (int) size)
+	memcpy (p, image + ofs + old_size, (int) size - ofs - old_size);
+
+      if ((int) section_offset > ofs)
+	{
+	  section_offset = (int) section_offset + delta;
+	  e->e_shoff = grub_host_to_target (section_offset);
+	}
+
+      sections = (Elf_Shdr *) (new_image + section_offset);
+      moddep_section = find_moddep_section (sections, section_entsize,
+					    num_sections, strtab);
+      if (! moddep_section)
+	grub_util_error ("no .moddeps section");
+
+      moddep_section->sh_size = grub_host_to_target32 (new_size);
+
+      for (i = 0, s = sections;
+	   i < num_sections;
+	   i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+	{
+	  Elf_Off off;
+
+	  off = grub_target_to_host (s->sh_offset);
+	  if ((int) off > ofs)
+	    {
+	      off = (int) off + delta;
+	      s->sh_offset = grub_host_to_target (off);
+	    }
+	}
+
+      fp = fopen (path, "wb");
+      if (! fp)
+	grub_util_error ("Can\'t write to %s", path);
+
+      grub_util_write_image (new_image, (int) size + delta, fp);
+
+      fclose (fp);
+
+      free (new_image);
+    }
+
+  free (image);
+}
+
+static void
+write_moddep (struct grub_update_list *u, FILE *fp)
+{
+  struct grub_named_list *n;
+
+  if (! u->cur_mods)
+    return;
+
+  fprintf (fp, "%s:", u->name);
+  n = u->cur_mods;
+  while (n)
+    {
+      fprintf (fp, " %s", n->name);
+      n = n->next;
+    }
+
+  fprintf (fp, "\n");
+  free_named_list (&u->cur_mods);
+}
+
+static void
+update_moddep (char *dir)
+{
+  FILE *fp;
+  struct stat st;
+  char *path, *image;
+  struct grub_update_list *u;
+
+  path = grub_util_get_path (dir, "moddep.lst");
+  image = (stat (path, &st) == 0) ? grub_util_read_image (path) : 0;
+
+  fp = fopen (path, "w");
+  if (! fp)
+    grub_util_error ("Can\'t write to ", path);
+
+  if (image)
+    {
+      char *line;
+
+      line = image;
+      while (*line)
+	{
+	  char *p, *c;
+	  int n;
+
+	  n = strcspn (line, "\r\n");
+	  p = line;
+
+	  line += n;
+	  while ((*line == '\r') || (*line == '\n'))
+	    line++;
+
+	  *(p + n) = 0;
+
+	  c = strchr (p, ':');
+	  if (! c)
+	    continue;
+
+	  *c = 0;
+	  u = update_list;
+	  while (u)
+	    {
+	      int r;
+
+	      r = strcmp (p, u->name);
+	      if (! r)
+		break;
+
+	      if (r < 0)
+		{
+		  u = 0;
+		  break;
+		}
+
+	      u = u->next;
+	    }
+	  *c = ':';
+
+	  if (u)
+	    write_moddep (u, fp);
+	  else
+	    fprintf (fp, "%s\n", p);
+	}
+    }
+
+
+  u = update_list;
+  while (u)
+    {
+      write_moddep (u, fp);
+      u = u->next;
+    }
+
+  fclose (fp);
+  free (path);
+  free (image);
+}
+
+static void
+apply_update (char *dir)
+{
+  struct grub_update_list *u;
+
+  u = update_list;
+  while (u)
+    {
+      char *mod_path;
+
+      mod_path = grub_util_get_module_path (dir, u->name);
+      update_deps (u, mod_path);
+      free (mod_path);
+      u = u->next;
+    }
+
+  update_moddep (dir);
+}
+
+static struct option options[] =
+  {
+    {"directory", required_argument, 0, 'd'},
+    {"test", no_argument, 0, 't'},
+    {"help", no_argument, 0, 'h'},
+    {"version", no_argument, 0, 'V'},
+    {"verbose", no_argument, 0, 'v'},
+    {0, 0, 0, 0}
+  };
+
+static void
+usage (int status)
+{
+  if (status)
+    fprintf (stderr, "Try ``grub-symdb --help'' for more information.\n");
+  else
+    printf ("\
+Usage: grub-symdb [OPTION]... COMMAND\n\
+\n\
+Manage the symbol database of GRUB.\n\
+\nCommands:\n\
+  update MODULES          add/update modules to the symbol database\n\
+  remove MODULES          remove modules from the symbol databsae\n\
+  check                   check for duplicate and unresolved symbols\n\
+\n\
+  -d, --directory=DIR     use images and modules under DIR [default=%s]\n\
+  -t, --test              test mode\n\
+  -h, --help              display this message and exit\n\
+  -V, --version           print version information and exit\n\
+  -v, --verbose           print verbose messages\n\
+\n\
+Report bugs to <%s>.\n\
+", GRUB_LIBDIR, PACKAGE_BUGREPORT);
+
+  exit (status);
+}
+
+int
+main (int argc, char *argv[])
+{
+  char *dir = NULL;
+  char *path;
+  int test_mode = 0;
+
+  progname = "grub-symdb";
+
+  while (1)
+    {
+      int c = getopt_long (argc, argv, "d:thVv", options, 0);
+
+      if (c == -1)
+	break;
+      else
+	switch (c)
+	  {
+	  case 'd':
+	    if (dir)
+	      free (dir);
+
+	    dir = xstrdup (optarg);
+	    break;
+
+	  case 't':
+	    test_mode++;
+	    break;
+
+	  case 'h':
+	    usage (0);
+	    break;
+
+	  case 'V':
+	    printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+	    return 0;
+
+	  case 'v':
+	    verbosity++;
+	    break;
+
+	  default:
+	    usage (1);
+	    break;
+	  }
+    }
+
+  if (! dir)
+    dir = xstrdup (GRUB_LIBDIR);
+
+  path = grub_util_get_path (dir, "modsym.lst");
+
+  argv += optind;
+  argc -= optind;
+  if (argc == 0)
+    grub_util_error ("No command specified.");
+
+  read_symdb (path);
+  if (! strcmp (argv[0], "update"))
+    {
+      remove_mods (argv + 1);
+      update_mods (argv + 1, dir);
+      if (test_mode)
+	dump_update ();
+      else
+	{
+	  apply_update (dir);
+	  write_symdb (path);
+	}
+    }
+  else if (! strcmp (argv[0], "remove"))
+    {
+      remove_mods (argv + 1);
+      if (test_mode)
+	dump_update ();
+      else
+	{
+	  apply_update (dir);
+	  write_symdb (path);
+	}
+    }
+  else if (! strcmp (argv[0], "check"))
+    {
+      check_symdb ();
+    }
+  else
+    grub_util_error ("Unkown command %s.", argv[0]);
+
+  free (path);
+  free (dir);
+
+  return 0;
+}
diff --git a/util/resolve.c b/util/resolve.c
index 85aec72..37ee020 100644
--- a/util/resolve.c
+++ b/util/resolve.c
@@ -126,8 +126,8 @@ read_dep_list (FILE *fp)
   return dep_list;
 }
 
-static char *
-get_module_name (const char *str)
+char *
+grub_util_get_module_name (const char *str)
 {
   char *base;
   char *ext;
@@ -152,8 +152,8 @@ get_module_name (const char *str)
   return xstrdup (base);
 }
 
-static char *
-get_module_path (const char *prefix, const char *str)
+char *
+grub_util_get_module_path (const char *prefix, const char *str)
 {
   char *dir;
   char *base;
@@ -190,7 +190,7 @@ add_module (const char *dir,
   struct mod_list *mod;
   struct dep_list *dep;
   
-  mod_name = get_module_name (name);
+  mod_name = grub_util_get_module_name (name);
 
   /* Check if the module has already been added.  */
   for (mod = *mod_head; mod; mod = mod->next)
@@ -218,7 +218,7 @@ add_module (const char *dir,
 
   /* Add this path.  */
   path = (struct grub_util_path_list *) xmalloc (sizeof (*path));
-  path->name = get_module_path (dir, name);
+  path->name = grub_util_get_module_path (dir, name);
   path->next = *path_head;
   *path_head = path;
 }
_______________________________________________
Grub-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to