source: grub-pc/trunk/fuentes/grub-core/kern/dl.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 18.4 KB
Line 
1/* dl.c - loadable module support */
2/*
3 *  GRUB  --  GRand Unified Bootloader
4 *  Copyright (C) 2002,2003,2004,2005,2007,2008,2009  Free Software Foundation, Inc.
5 *
6 *  GRUB is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  GRUB is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/* Force native word size */
21#define GRUB_TARGET_WORDSIZE (8 * GRUB_CPU_SIZEOF_VOID_P)
22
23#include <config.h>
24#include <grub/elf.h>
25#include <grub/dl.h>
26#include <grub/misc.h>
27#include <grub/mm.h>
28#include <grub/err.h>
29#include <grub/types.h>
30#include <grub/symbol.h>
31#include <grub/file.h>
32#include <grub/env.h>
33#include <grub/cache.h>
34#include <grub/i18n.h>
35
36/* Platforms where modules are in a readonly area of memory.  */
37#if defined(GRUB_MACHINE_QEMU)
38#define GRUB_MODULES_MACHINE_READONLY
39#endif
40
41#ifdef GRUB_MACHINE_EFI
42#include <grub/efi/efi.h>
43#endif
44
45
46
47#pragma GCC diagnostic ignored "-Wcast-align"
48
49grub_dl_t grub_dl_head = 0;
50
51grub_err_t
52grub_dl_add (grub_dl_t mod);
53
54/* Keep global so that GDB scripts work.  */
55grub_err_t
56grub_dl_add (grub_dl_t mod)
57{
58  if (grub_dl_get (mod->name))
59    return grub_error (GRUB_ERR_BAD_MODULE,
60                       "`%s' is already loaded", mod->name);
61
62  return GRUB_ERR_NONE;
63}
64
65static void
66grub_dl_remove (grub_dl_t mod)
67{
68  grub_dl_t *p, q;
69
70  for (p = &grub_dl_head, q = *p; q; p = &q->next, q = *p)
71    if (q == mod)
72      {
73        *p = q->next;
74        return;
75      }
76}
77
78
79
80struct grub_symbol
81{
82  struct grub_symbol *next;
83  const char *name;
84  void *addr;
85  int isfunc;
86  grub_dl_t mod;        /* The module to which this symbol belongs.  */
87};
88typedef struct grub_symbol *grub_symbol_t;
89
90/* The size of the symbol table.  */
91#define GRUB_SYMTAB_SIZE        509
92
93/* The symbol table (using an open-hash).  */
94static struct grub_symbol *grub_symtab[GRUB_SYMTAB_SIZE];
95
96/* Simple hash function.  */
97static unsigned
98grub_symbol_hash (const char *s)
99{
100  unsigned key = 0;
101
102  while (*s)
103    key = key * 65599 + *s++;
104
105  return (key + (key >> 5)) % GRUB_SYMTAB_SIZE;
106}
107
108/* Resolve the symbol name NAME and return the address.
109   Return NULL, if not found.  */
110static grub_symbol_t
111grub_dl_resolve_symbol (const char *name)
112{
113  grub_symbol_t sym;
114
115  for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next)
116    if (grub_strcmp (sym->name, name) == 0)
117      return sym;
118
119  return 0;
120}
121
122/* Register a symbol with the name NAME and the address ADDR.  */
123grub_err_t
124grub_dl_register_symbol (const char *name, void *addr, int isfunc,
125                         grub_dl_t mod)
126{
127  grub_symbol_t sym;
128  unsigned k;
129
130  sym = (grub_symbol_t) grub_malloc (sizeof (*sym));
131  if (! sym)
132    return grub_errno;
133
134  if (mod)
135    {
136      sym->name = grub_strdup (name);
137      if (! sym->name)
138        {
139          grub_free (sym);
140          return grub_errno;
141        }
142    }
143  else
144    sym->name = name;
145
146  sym->addr = addr;
147  sym->mod = mod;
148  sym->isfunc = isfunc;
149
150  k = grub_symbol_hash (name);
151  sym->next = grub_symtab[k];
152  grub_symtab[k] = sym;
153
154  return GRUB_ERR_NONE;
155}
156
157/* Unregister all the symbols defined in the module MOD.  */
158static void
159grub_dl_unregister_symbols (grub_dl_t mod)
160{
161  unsigned i;
162
163  if (! mod)
164    grub_fatal ("core symbols cannot be unregistered");
165
166  for (i = 0; i < GRUB_SYMTAB_SIZE; i++)
167    {
168      grub_symbol_t sym, *p, q;
169
170      for (p = &grub_symtab[i], sym = *p; sym; sym = q)
171        {
172          q = sym->next;
173          if (sym->mod == mod)
174            {
175              *p = q;
176              grub_free ((void *) sym->name);
177              grub_free (sym);
178            }
179          else
180            p = &sym->next;
181        }
182    }
183}
184
185/* Return the address of a section whose index is N.  */
186static void *
187grub_dl_get_section_addr (grub_dl_t mod, unsigned n)
188{
189  grub_dl_segment_t seg;
190
191  for (seg = mod->segment; seg; seg = seg->next)
192    if (seg->section == n)
193      return seg->addr;
194
195  return 0;
196}
197
198/* Check if EHDR is a valid ELF header.  */
199static grub_err_t
200grub_dl_check_header (void *ehdr, grub_size_t size)
201{
202  Elf_Ehdr *e = ehdr;
203  grub_err_t err;
204
205  /* Check the header size.  */
206  if (size < sizeof (Elf_Ehdr))
207    return grub_error (GRUB_ERR_BAD_OS, "ELF header smaller than expected");
208
209  /* Check the magic numbers.  */
210  if (e->e_ident[EI_MAG0] != ELFMAG0
211      || e->e_ident[EI_MAG1] != ELFMAG1
212      || e->e_ident[EI_MAG2] != ELFMAG2
213      || e->e_ident[EI_MAG3] != ELFMAG3
214      || e->e_ident[EI_VERSION] != EV_CURRENT
215      || e->e_version != EV_CURRENT)
216    return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
217
218  err = grub_arch_dl_check_header (ehdr);
219  if (err)
220    return err;
221
222  return GRUB_ERR_NONE;
223}
224
225/* Load all segments from memory specified by E.  */
226static grub_err_t
227grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
228{
229  unsigned i;
230  const Elf_Shdr *s;
231  grub_size_t tsize = 0, talign = 1;
232#if !defined (__i386__) && !defined (__x86_64__)
233  grub_size_t tramp;
234  grub_size_t got;
235  grub_err_t err;
236#endif
237  char *ptr;
238
239  for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
240       i < e->e_shnum;
241       i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
242    {
243      tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
244      if (talign < s->sh_addralign)
245        talign = s->sh_addralign;
246    }
247
248#if !defined (__i386__) && !defined (__x86_64__)
249  err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
250  if (err)
251    return err;
252  tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
253  if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
254    talign = GRUB_ARCH_DL_TRAMP_ALIGN;
255  tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
256  if (talign < GRUB_ARCH_DL_GOT_ALIGN)
257    talign = GRUB_ARCH_DL_GOT_ALIGN;
258#endif
259
260#ifdef GRUB_MACHINE_EMU
261  mod->base = grub_osdep_dl_memalign (talign, tsize);
262#else
263  mod->base = grub_memalign (talign, tsize);
264#endif
265  if (!mod->base)
266    return grub_errno;
267  mod->sz = tsize;
268  ptr = mod->base;
269
270  for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
271       i < e->e_shnum;
272       i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
273    {
274      if (s->sh_flags & SHF_ALLOC)
275        {
276          grub_dl_segment_t seg;
277
278          seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg));
279          if (! seg)
280            return grub_errno;
281
282          if (s->sh_size)
283            {
284              void *addr;
285
286              ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
287              addr = ptr;
288              ptr += s->sh_size;
289
290              switch (s->sh_type)
291                {
292                case SHT_PROGBITS:
293                  grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
294                  break;
295                case SHT_NOBITS:
296                  grub_memset (addr, 0, s->sh_size);
297                  break;
298                }
299
300              seg->addr = addr;
301            }
302          else
303            seg->addr = 0;
304
305          seg->size = s->sh_size;
306          seg->section = i;
307          seg->next = mod->segment;
308          mod->segment = seg;
309        }
310    }
311#if !defined (__i386__) && !defined (__x86_64__)
312  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
313  mod->tramp = ptr;
314  mod->trampptr = ptr;
315  ptr += tramp;
316  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
317  mod->got = ptr;
318  mod->gotptr = ptr;
319  ptr += got;
320#endif
321
322  return GRUB_ERR_NONE;
323}
324
325static grub_err_t
326grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
327{
328  unsigned i;
329  Elf_Shdr *s;
330  Elf_Sym *sym;
331  const char *str;
332  Elf_Word size, entsize;
333
334  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
335       i < e->e_shnum;
336       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
337    if (s->sh_type == SHT_SYMTAB)
338      break;
339
340  if (i == e->e_shnum)
341    return grub_error (GRUB_ERR_BAD_MODULE, N_("no symbol table"));
342
343#ifdef GRUB_MODULES_MACHINE_READONLY
344  mod->symtab = grub_malloc (s->sh_size);
345  if (!mod->symtab)
346    return grub_errno;
347  memcpy (mod->symtab, (char *) e + s->sh_offset, s->sh_size);
348#else
349  mod->symtab = (Elf_Sym *) ((char *) e + s->sh_offset);
350#endif
351  mod->symsize = s->sh_entsize;
352  sym = mod->symtab;
353  size = s->sh_size;
354  entsize = s->sh_entsize;
355
356  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link);
357  str = (char *) e + s->sh_offset;
358
359  for (i = 0;
360       i < size / entsize;
361       i++, sym = (Elf_Sym *) ((char *) sym + entsize))
362    {
363      unsigned char type = ELF_ST_TYPE (sym->st_info);
364      unsigned char bind = ELF_ST_BIND (sym->st_info);
365      const char *name = str + sym->st_name;
366
367      switch (type)
368        {
369        case STT_NOTYPE:
370        case STT_OBJECT:
371          /* Resolve a global symbol.  */
372          if (sym->st_name != 0 && sym->st_shndx == 0)
373            {
374              grub_symbol_t nsym = grub_dl_resolve_symbol (name);
375              if (! nsym)
376                return grub_error (GRUB_ERR_BAD_MODULE,
377                                   N_("symbol `%s' not found"), name);
378              sym->st_value = (Elf_Addr) nsym->addr;
379              if (nsym->isfunc)
380                sym->st_info = ELF_ST_INFO (bind, STT_FUNC);
381            }
382          else
383            {
384              sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
385                                                                    sym->st_shndx);
386              if (bind != STB_LOCAL)
387                if (grub_dl_register_symbol (name, (void *) sym->st_value, 0, mod))
388                  return grub_errno;
389            }
390          break;
391
392        case STT_FUNC:
393          sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
394                                                                sym->st_shndx);
395#ifdef __ia64__
396          {
397              /* FIXME: free descriptor once it's not used anymore. */
398              char **desc;
399              desc = grub_malloc (2 * sizeof (char *));
400              if (!desc)
401                return grub_errno;
402              desc[0] = (void *) sym->st_value;
403              desc[1] = mod->base;
404              sym->st_value = (grub_addr_t) desc;
405          }
406#endif
407          if (bind != STB_LOCAL)
408            if (grub_dl_register_symbol (name, (void *) sym->st_value, 1, mod))
409              return grub_errno;
410          if (grub_strcmp (name, "grub_mod_init") == 0)
411            mod->init = (void (*) (grub_dl_t)) sym->st_value;
412          else if (grub_strcmp (name, "grub_mod_fini") == 0)
413            mod->fini = (void (*) (void)) sym->st_value;
414          break;
415
416        case STT_SECTION:
417          sym->st_value = (Elf_Addr) grub_dl_get_section_addr (mod,
418                                                               sym->st_shndx);
419          break;
420
421        case STT_FILE:
422          sym->st_value = 0;
423          break;
424
425        default:
426          return grub_error (GRUB_ERR_BAD_MODULE,
427                             "unknown symbol type `%d'", (int) type);
428        }
429    }
430
431  return GRUB_ERR_NONE;
432}
433
434static Elf_Shdr *
435grub_dl_find_section (Elf_Ehdr *e, const char *name)
436{
437  Elf_Shdr *s;
438  const char *str;
439  unsigned i;
440
441  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
442  str = (char *) e + s->sh_offset;
443
444  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
445       i < e->e_shnum;
446       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
447    if (grub_strcmp (str + s->sh_name, name) == 0)
448      return s;
449  return NULL;
450}
451
452/* Me, Vladimir Serbinenko, hereby I add this module check as per new
453   GNU module policy. Note that this license check is informative only.
454   Modules have to be licensed under GPLv3 or GPLv3+ (optionally
455   multi-licensed under other licences as well) independently of the
456   presence of this check and solely by linking (module loading in GRUB
457   constitutes linking) and GRUB core being licensed under GPLv3+.
458   Be sure to understand your license obligations.
459*/
460static grub_err_t
461grub_dl_check_license (Elf_Ehdr *e)
462{
463  Elf_Shdr *s = grub_dl_find_section (e, ".module_license");
464  if (s && (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0
465            || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0
466            || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0))
467    return GRUB_ERR_NONE;
468  return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license");
469}
470
471static grub_err_t
472grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
473{
474  Elf_Shdr *s;
475
476  s = grub_dl_find_section (e, ".modname");
477  if (!s)
478    return grub_error (GRUB_ERR_BAD_MODULE, "no module name found");
479 
480  mod->name = grub_strdup ((char *) e + s->sh_offset);
481  if (! mod->name)
482    return grub_errno;
483
484  return GRUB_ERR_NONE;
485}
486
487static grub_err_t
488grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e)
489{
490  Elf_Shdr *s;
491
492  s = grub_dl_find_section (e, ".moddeps");
493
494  if (!s)
495    return GRUB_ERR_NONE;
496
497  const char *name = (char *) e + s->sh_offset;
498  const char *max = name + s->sh_size;
499
500  while ((name < max) && (*name))
501    {
502      grub_dl_t m;
503      grub_dl_dep_t dep;
504
505      m = grub_dl_load (name);
506      if (! m)
507        return grub_errno;
508
509      grub_dl_ref (m);
510
511      dep = (grub_dl_dep_t) grub_malloc (sizeof (*dep));
512      if (! dep)
513        return grub_errno;
514
515      dep->mod = m;
516      dep->next = mod->dep;
517      mod->dep = dep;
518
519      name += grub_strlen (name) + 1;
520    }
521
522  return GRUB_ERR_NONE;
523}
524
525int
526grub_dl_ref (grub_dl_t mod)
527{
528  grub_dl_dep_t dep;
529
530  if (!mod)
531    return 0;
532
533  for (dep = mod->dep; dep; dep = dep->next)
534    grub_dl_ref (dep->mod);
535
536  return ++mod->ref_count;
537}
538
539int
540grub_dl_unref (grub_dl_t mod)
541{
542  grub_dl_dep_t dep;
543
544  if (!mod)
545    return 0;
546
547  for (dep = mod->dep; dep; dep = dep->next)
548    grub_dl_unref (dep->mod);
549
550  return --mod->ref_count;
551}
552
553static void
554grub_dl_flush_cache (grub_dl_t mod)
555{
556  grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
557                (unsigned long) mod->sz, mod->base);
558  grub_arch_sync_caches (mod->base, mod->sz);
559}
560
561static grub_err_t
562grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
563{
564  Elf_Ehdr *e = ehdr;
565  Elf_Shdr *s;
566  unsigned i;
567
568  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
569       i < e->e_shnum;
570       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
571    if (s->sh_type == SHT_REL || s->sh_type == SHT_RELA)
572      {
573        grub_dl_segment_t seg;
574        grub_err_t err;
575
576        /* Find the target segment.  */
577        for (seg = mod->segment; seg; seg = seg->next)
578          if (seg->section == s->sh_info)
579            break;
580
581        if (seg)
582          {
583            err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
584            if (err)
585              return err;
586          }
587      }
588
589  return GRUB_ERR_NONE;
590}
591
592/* Load a module from core memory.  */
593grub_dl_t
594grub_dl_load_core_noinit (void *addr, grub_size_t size)
595{
596  Elf_Ehdr *e;
597  grub_dl_t mod;
598
599  grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr,
600                (unsigned long) size);
601  e = addr;
602  if (grub_dl_check_header (e, size))
603    return 0;
604
605  if (e->e_type != ET_REL)
606    {
607      grub_error (GRUB_ERR_BAD_MODULE, N_("this ELF file is not of the right type"));
608      return 0;
609    }
610
611  /* Make sure that every section is within the core.  */
612  if (size < e->e_shoff + e->e_shentsize * e->e_shnum)
613    {
614      grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core");
615      return 0;
616    }
617
618  mod = (grub_dl_t) grub_zalloc (sizeof (*mod));
619  if (! mod)
620    return 0;
621
622  mod->ref_count = 1;
623
624  grub_dprintf ("modules", "relocating to %p\n", mod);
625  /* Me, Vladimir Serbinenko, hereby I add this module check as per new
626     GNU module policy. Note that this license check is informative only.
627     Modules have to be licensed under GPLv3 or GPLv3+ (optionally
628     multi-licensed under other licences as well) independently of the
629     presence of this check and solely by linking (module loading in GRUB
630     constitutes linking) and GRUB core being licensed under GPLv3+.
631     Be sure to understand your license obligations.
632  */
633  if (grub_dl_check_license (e)
634      || grub_dl_resolve_name (mod, e)
635      || grub_dl_resolve_dependencies (mod, e)
636      || grub_dl_load_segments (mod, e)
637      || grub_dl_resolve_symbols (mod, e)
638      || grub_dl_relocate_symbols (mod, e))
639    {
640      mod->fini = 0;
641      grub_dl_unload (mod);
642      return 0;
643    }
644
645  grub_dl_flush_cache (mod);
646
647  grub_dprintf ("modules", "module name: %s\n", mod->name);
648  grub_dprintf ("modules", "init function: %p\n", mod->init);
649
650  if (grub_dl_add (mod))
651    {
652      grub_dl_unload (mod);
653      return 0;
654    }
655
656  return mod;
657}
658
659grub_dl_t
660grub_dl_load_core (void *addr, grub_size_t size)
661{
662  grub_dl_t mod;
663
664  grub_boot_time ("Parsing module");
665
666  mod = grub_dl_load_core_noinit (addr, size);
667
668  if (!mod)
669    return NULL;
670
671  grub_boot_time ("Initing module %s", mod->name);
672  grub_dl_init (mod);
673  grub_boot_time ("Module %s inited", mod->name);
674
675  return mod;
676}
677
678/* Load a module from the file FILENAME.  */
679grub_dl_t
680grub_dl_load_file (const char *filename)
681{
682  grub_file_t file = NULL;
683  grub_ssize_t size;
684  void *core = 0;
685  grub_dl_t mod = 0;
686
687#ifdef GRUB_MACHINE_EFI
688  if (grub_efi_secure_boot ())
689    {
690      grub_error (GRUB_ERR_ACCESS_DENIED,
691                  "Secure Boot forbids loading module from %s", filename);
692      return 0;
693    }
694#endif
695
696  grub_boot_time ("Loading module %s", filename);
697
698  file = grub_file_open (filename);
699  if (! file)
700    return 0;
701
702  size = grub_file_size (file);
703  core = grub_malloc (size);
704  if (! core)
705    {
706      grub_file_close (file);
707      return 0;
708    }
709
710  if (grub_file_read (file, core, size) != (int) size)
711    {
712      grub_file_close (file);
713      grub_free (core);
714      return 0;
715    }
716
717  /* We must close this before we try to process dependencies.
718     Some disk backends do not handle gracefully multiple concurrent
719     opens of the same device.  */
720  grub_file_close (file);
721
722  mod = grub_dl_load_core (core, size);
723  grub_free (core);
724  if (! mod)
725    return 0;
726
727  mod->ref_count--;
728  return mod;
729}
730
731/* Load a module using a symbolic name.  */
732grub_dl_t
733grub_dl_load (const char *name)
734{
735  char *filename;
736  grub_dl_t mod;
737  const char *grub_dl_dir = grub_env_get ("prefix");
738
739  mod = grub_dl_get (name);
740  if (mod)
741    return mod;
742
743  if (grub_no_modules)
744    return 0;
745
746  if (! grub_dl_dir) {
747    grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
748    return 0;
749  }
750
751  filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM "/%s.mod",
752                             grub_dl_dir, name);
753  if (! filename)
754    return 0;
755
756  mod = grub_dl_load_file (filename);
757  grub_free (filename);
758
759  if (! mod)
760    return 0;
761
762  if (grub_strcmp (mod->name, name) != 0)
763    grub_error (GRUB_ERR_BAD_MODULE, "mismatched names");
764
765  return mod;
766}
767
768/* Unload the module MOD.  */
769int
770grub_dl_unload (grub_dl_t mod)
771{
772  grub_dl_dep_t dep, depn;
773
774  if (mod->ref_count > 0)
775    return 0;
776
777  if (mod->fini)
778    (mod->fini) ();
779
780  grub_dl_remove (mod);
781  grub_dl_unregister_symbols (mod);
782
783  for (dep = mod->dep; dep; dep = depn)
784    {
785      depn = dep->next;
786
787      grub_dl_unload (dep->mod);
788
789      grub_free (dep);
790    }
791
792#ifdef GRUB_MACHINE_EMU
793  grub_dl_osdep_dl_free (mod->base);
794#else
795  grub_free (mod->base);
796#endif
797  grub_free (mod->name);
798#ifdef GRUB_MODULES_MACHINE_READONLY
799  grub_free (mod->symtab);
800#endif
801  grub_free (mod);
802  return 1;
803}
804
805/* Unload unneeded modules.  */
806void
807grub_dl_unload_unneeded (void)
808{
809  /* Because grub_dl_remove modifies the list of modules, this
810     implementation is tricky.  */
811  grub_dl_t p = grub_dl_head;
812
813  while (p)
814    {
815      if (grub_dl_unload (p))
816        {
817          p = grub_dl_head;
818          continue;
819        }
820
821      p = p->next;
822    }
823}
Note: See TracBrowser for help on using the repository browser.