blob: 3b387d570c4bf7fde035080db90bb04f6ef1f817 [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070027/*
28 * These routines simply provide wrappers around malloc(3C) and free(3C)
29 * for now. In the future we hope to provide a userland equivalent to
30 * the kmem allocator, including cache allocators.
31 */
32
33#include <strings.h>
34#include <stdlib.h>
35#include <poll.h>
36
37#ifdef _KMDB
38#include <kmdb/kmdb_fault.h>
39#endif
40#include <mdb/mdb_debug.h>
41#include <mdb/mdb_stdlib.h>
42#include <mdb/mdb_frame.h>
43#include <mdb/mdb_umem.h>
44#include <mdb/mdb_err.h>
45#include <mdb/mdb.h>
46
47#define UMF_DEBUG 0x1
48
49#ifdef DEBUG
50int mdb_umem_flags = UMF_DEBUG;
51#else
52int mdb_umem_flags = 0;
53#endif
54
55struct mdb_mblk {
56 void *blk_addr; /* address of allocated block */
57 size_t blk_size; /* size of block in bytes */
58 struct mdb_mblk *blk_next; /* link to next block */
59};
60
61/*ARGSUSED*/
62static void *
63mdb_umem_handler(size_t nbytes, size_t align, uint_t flags)
64{
65#ifdef _KMDB
66
67 /*
68 * kmdb has a fixed, dedicated VA range in which to play. This range
69 * won't change size while the debugger is running, regardless of how
70 * long we wait. As a result, the only sensible course of action is
71 * to fail the request. If we're here, however, the request was made
72 * with UM_SLEEP. The caller is thus not expecting a NULL back. We'll
73 * have to fail the current dcmd set.
74 */
75 if (mdb.m_depth > 0) {
76 warn("failed to allocate %lu bytes -- recovering\n",
77 (ulong_t)nbytes);
78
79 kmdb_print_stack();
80
81 longjmp(mdb.m_frame->f_pcb, MDB_ERR_NOMEM);
82 }
83
84#else
85
86 /*
87 * mdb, on the other hand, can afford to wait, as someone may actually
88 * free something.
89 */
90 if (errno == EAGAIN) {
91 void *ptr = NULL;
92 char buf[64];
93
94 (void) mdb_iob_snprintf(buf, sizeof (buf),
95 "[ sleeping for %lu bytes of free memory ... ]",
96 (ulong_t)nbytes);
97
98 (void) mdb_iob_puts(mdb.m_err, buf);
99 (void) mdb_iob_flush(mdb.m_err);
100
101 do {
102 (void) poll(NULL, 0, 1000);
103 if (align != 0)
104 ptr = memalign(align, nbytes);
105 else
106 ptr = malloc(nbytes);
107 } while (ptr == NULL && errno == EAGAIN);
108
109 if (ptr != NULL)
110 return (ptr);
111
112 (void) memset(buf, '\b', strlen(buf));
113 (void) mdb_iob_puts(mdb.m_err, buf);
114 (void) mdb_iob_flush(mdb.m_err);
115
116 (void) memset(buf, ' ', strlen(buf));
117 (void) mdb_iob_puts(mdb.m_err, buf);
118 (void) mdb_iob_flush(mdb.m_err);
119
120 (void) memset(buf, '\b', strlen(buf));
121 (void) mdb_iob_puts(mdb.m_err, buf);
122 (void) mdb_iob_flush(mdb.m_err);
123 }
124#endif
125
126 die("failed to allocate %lu bytes -- terminating\n", (ulong_t)nbytes);
127
128 /*NOTREACHED*/
129
130 return (NULL);
131}
132
133static void
134mdb_umem_gc_enter(void *ptr, size_t nbytes)
135{
136 mdb_mblk_t *blkp = mdb_alloc(sizeof (mdb_mblk_t), UM_SLEEP);
137
138 blkp->blk_addr = ptr;
139 blkp->blk_size = nbytes;
140 blkp->blk_next = mdb.m_frame->f_mblks;
141
142 mdb.m_frame->f_mblks = blkp;
143}
144
145/*
146 * If we're compiled in debug mode, we use this function (gratuitously
147 * stolen from kmem.c) to set uninitialized and freed regions to
148 * special bit patterns.
149 */
150static void
151mdb_umem_copy_pattern(uint32_t pattern, void *buf_arg, size_t size)
152{
153 /* LINTED - alignment of bufend */
154 uint32_t *bufend = (uint32_t *)((char *)buf_arg + size);
155 uint32_t *buf = buf_arg;
156
157 while (buf < bufend - 3) {
158 buf[3] = buf[2] = buf[1] = buf[0] = pattern;
159 buf += 4;
160 }
161
162 while (buf < bufend)
163 *buf++ = pattern;
164}
165
166void *
167mdb_alloc_align(size_t nbytes, size_t align, uint_t flags)
168{
169 void *ptr;
Robert Mustacchi258e8622016-02-27 04:00:42 +0000170 size_t obytes = nbytes;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700171
Robert Mustacchi258e8622016-02-27 04:00:42 +0000172 if (nbytes == 0 || nbytes > MDB_ALLOC_MAX)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700173 return (NULL);
174
175 nbytes = (nbytes + sizeof (uint32_t) - 1) & ~(sizeof (uint32_t) - 1);
Robert Mustacchi258e8622016-02-27 04:00:42 +0000176 if (nbytes < obytes || nbytes == 0)
177 return (NULL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700178
179 if (align != 0)
180 ptr = memalign(align, nbytes);
181 else
182 ptr = malloc(nbytes);
183
184 if (flags & UM_SLEEP) {
185 while (ptr == NULL)
186 ptr = mdb_umem_handler(nbytes, align, flags);
187 }
188
189 if (ptr != NULL && (mdb_umem_flags & UMF_DEBUG) != 0)
190 mdb_umem_copy_pattern(UMEM_UNINITIALIZED_PATTERN, ptr, nbytes);
191
192 if (flags & UM_GC)
193 mdb_umem_gc_enter(ptr, nbytes);
194
195 return (ptr);
196}
197
198void *
199mdb_alloc(size_t nbytes, uint_t flags)
200{
201 return (mdb_alloc_align(nbytes, 0, flags));
202}
203
204void *
205mdb_zalloc(size_t nbytes, uint_t flags)
206{
207 void *ptr = mdb_alloc(nbytes, flags);
208
209 if (ptr != NULL)
210 bzero(ptr, nbytes);
211
212 return (ptr);
213}
214
215void
216mdb_free(void *ptr, size_t nbytes)
217{
218 ASSERT(ptr != NULL || nbytes == 0);
219
220 nbytes = (nbytes + sizeof (uint32_t) - 1) & ~(sizeof (uint32_t) - 1);
221
222 if (ptr != NULL) {
223 if (mdb_umem_flags & UMF_DEBUG)
224 mdb_umem_copy_pattern(UMEM_FREE_PATTERN, ptr, nbytes);
225 free(ptr);
226 }
227}
228
229void
230mdb_free_align(void *ptr, size_t nbytes)
231{
232 mdb_free(ptr, nbytes);
233}
234
235void
236mdb_recycle(mdb_mblk_t **blkpp)
237{
238 mdb_mblk_t *blkp, *nblkp;
239
240 for (blkp = *blkpp; blkp != NULL; blkp = nblkp) {
241 mdb_dprintf(MDB_DBG_UMEM,
242 "garbage collect %p size %lu bytes\n", blkp->blk_addr,
243 (ulong_t)blkp->blk_size);
244
245 nblkp = blkp->blk_next;
246 mdb_free(blkp->blk_addr, blkp->blk_size);
247 mdb_free(blkp, sizeof (mdb_mblk_t));
248 }
249
250 *blkpp = NULL;
251}