1*c42dbd0eSchristos /* Copyright (C) 2021 Free Software Foundation, Inc.
2*c42dbd0eSchristos Contributed by Oracle.
3*c42dbd0eSchristos
4*c42dbd0eSchristos This file is part of GNU Binutils.
5*c42dbd0eSchristos
6*c42dbd0eSchristos This program is free software; you can redistribute it and/or modify
7*c42dbd0eSchristos it under the terms of the GNU General Public License as published by
8*c42dbd0eSchristos the Free Software Foundation; either version 3, or (at your option)
9*c42dbd0eSchristos any later version.
10*c42dbd0eSchristos
11*c42dbd0eSchristos This program is distributed in the hope that it will be useful,
12*c42dbd0eSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
13*c42dbd0eSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*c42dbd0eSchristos GNU General Public License for more details.
15*c42dbd0eSchristos
16*c42dbd0eSchristos You should have received a copy of the GNU General Public License
17*c42dbd0eSchristos along with this program; if not, write to the Free Software
18*c42dbd0eSchristos Foundation, 51 Franklin Street - Fifth Floor, Boston,
19*c42dbd0eSchristos MA 02110-1301, USA. */
20*c42dbd0eSchristos
21*c42dbd0eSchristos #include "config.h"
22*c42dbd0eSchristos #include <dlfcn.h>
23*c42dbd0eSchristos #include "util.h"
24*c42dbd0eSchristos
25*c42dbd0eSchristos #define CHECK_OUT_OF_MEM(ptr, size) if (ptr == NULL) err_out_of_memory(size)
26*c42dbd0eSchristos
27*c42dbd0eSchristos /* Report Out of Memory error and exit */
28*c42dbd0eSchristos static void
err_out_of_memory(unsigned nbytes)29*c42dbd0eSchristos err_out_of_memory (unsigned nbytes)
30*c42dbd0eSchristos {
31*c42dbd0eSchristos char *nm = get_prog_name (1);
32*c42dbd0eSchristos if (nm)
33*c42dbd0eSchristos fprintf (stderr, GTXT ("%s: Error: Memory capacity exceeded.\n"), nm);
34*c42dbd0eSchristos else
35*c42dbd0eSchristos fprintf (stderr, GTXT ("Error: Memory capacity exceeded.\n"));
36*c42dbd0eSchristos fprintf (stderr, GTXT (" Requested %u bytes.\n"), nbytes);
37*c42dbd0eSchristos exit (16);
38*c42dbd0eSchristos }
39*c42dbd0eSchristos
40*c42dbd0eSchristos #define CALL_REAL(x) (__real_##x)
41*c42dbd0eSchristos #define NULL_PTR(x) ( __real_##x == NULL )
42*c42dbd0eSchristos
43*c42dbd0eSchristos static void *(*__real_malloc)(size_t) = NULL;
44*c42dbd0eSchristos static void (*__real_free)(void *) = NULL;
45*c42dbd0eSchristos static void *(*__real_realloc)(void *, size_t) = NULL;
46*c42dbd0eSchristos static void *(*__real_calloc)(size_t, size_t) = NULL;
47*c42dbd0eSchristos static char *(*__real_strdup)(const char*) = NULL;
48*c42dbd0eSchristos static volatile int in_init = 0;
49*c42dbd0eSchristos
50*c42dbd0eSchristos static int
init_heap_intf()51*c42dbd0eSchristos init_heap_intf ()
52*c42dbd0eSchristos {
53*c42dbd0eSchristos in_init = 1;
54*c42dbd0eSchristos __real_malloc = (void*(*)(size_t))dlsym (RTLD_NEXT, "malloc");
55*c42dbd0eSchristos __real_free = (void(*)(void *))dlsym (RTLD_NEXT, "free");
56*c42dbd0eSchristos __real_realloc = (void*(*)(void *, size_t))dlsym (RTLD_NEXT, "realloc");
57*c42dbd0eSchristos __real_calloc = (void*(*)(size_t, size_t))dlsym (RTLD_NEXT, "calloc");
58*c42dbd0eSchristos __real_strdup = (char*(*)(const char*))dlsym (RTLD_NEXT, "strdup");
59*c42dbd0eSchristos in_init = 0;
60*c42dbd0eSchristos return 0;
61*c42dbd0eSchristos }
62*c42dbd0eSchristos
63*c42dbd0eSchristos /* --------------------------------------------------------------------------- */
64*c42dbd0eSchristos /* libc's memory management functions substitutions */
65*c42dbd0eSchristos
66*c42dbd0eSchristos /* Allocate memory and make sure we got some */
67*c42dbd0eSchristos void *
malloc(size_t size)68*c42dbd0eSchristos malloc (size_t size)
69*c42dbd0eSchristos {
70*c42dbd0eSchristos if (NULL_PTR (malloc))
71*c42dbd0eSchristos init_heap_intf ();
72*c42dbd0eSchristos void *ptr = CALL_REAL (malloc)(size);
73*c42dbd0eSchristos CHECK_OUT_OF_MEM (ptr, size);
74*c42dbd0eSchristos return ptr;
75*c42dbd0eSchristos }
76*c42dbd0eSchristos
77*c42dbd0eSchristos
78*c42dbd0eSchristos /* Implement a workaround for a libdl recursion problem */
79*c42dbd0eSchristos void *
calloc(size_t nelem,size_t size)80*c42dbd0eSchristos calloc (size_t nelem, size_t size)
81*c42dbd0eSchristos {
82*c42dbd0eSchristos if (NULL_PTR (calloc))
83*c42dbd0eSchristos {
84*c42dbd0eSchristos /* If a program is linked with libpthread then the following
85*c42dbd0eSchristos * calling sequence occurs:
86*c42dbd0eSchristos * init_heap_intf -> dlsym -> calloc -> malloc -> init_heap_intf
87*c42dbd0eSchristos * We break some performance improvement in libdl by returning
88*c42dbd0eSchristos * NULL but preserve functionality.
89*c42dbd0eSchristos */
90*c42dbd0eSchristos if (in_init)
91*c42dbd0eSchristos return NULL;
92*c42dbd0eSchristos init_heap_intf ();
93*c42dbd0eSchristos }
94*c42dbd0eSchristos return CALL_REAL (calloc)(nelem, size);
95*c42dbd0eSchristos }
96*c42dbd0eSchristos
97*c42dbd0eSchristos /* Free the storage associated with data */
98*c42dbd0eSchristos void
free(void * ptr)99*c42dbd0eSchristos free (void *ptr)
100*c42dbd0eSchristos {
101*c42dbd0eSchristos if (ptr == NULL)
102*c42dbd0eSchristos return;
103*c42dbd0eSchristos if (NULL_PTR (free))
104*c42dbd0eSchristos init_heap_intf ();
105*c42dbd0eSchristos CALL_REAL (free)(ptr);
106*c42dbd0eSchristos return;
107*c42dbd0eSchristos }
108*c42dbd0eSchristos
109*c42dbd0eSchristos /* Reallocate buffer */
110*c42dbd0eSchristos void *
realloc(void * ptr,size_t size)111*c42dbd0eSchristos realloc (void *ptr, size_t size)
112*c42dbd0eSchristos {
113*c42dbd0eSchristos if (NULL_PTR (realloc))
114*c42dbd0eSchristos init_heap_intf ();
115*c42dbd0eSchristos ptr = CALL_REAL (realloc)(ptr, size);
116*c42dbd0eSchristos CHECK_OUT_OF_MEM (ptr, size);
117*c42dbd0eSchristos return ptr;
118*c42dbd0eSchristos }
119