1 /* $NetBSD: mem1.c,v 1.18 2016/12/24 17:43:45 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995 Jochen Pohl 5 * All Rights Reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Jochen Pohl for 18 * The NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #if HAVE_NBTOOL_CONFIG_H 35 #include "nbtool_config.h" 36 #endif 37 38 #include <sys/cdefs.h> 39 #if defined(__RCSID) && !defined(lint) 40 __RCSID("$NetBSD: mem1.c,v 1.18 2016/12/24 17:43:45 christos Exp $"); 41 #endif 42 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include "lint1.h" 50 51 /* 52 * Filenames allocated by fnalloc() and fnnalloc() are shared. 53 */ 54 typedef struct fn { 55 char *fn_name; 56 size_t fn_len; 57 int fn_id; 58 struct fn *fn_nxt; 59 } fn_t; 60 61 static fn_t *fnames; 62 63 static fn_t *srchfn(const char *, size_t); 64 65 /* 66 * Look for a Filename of length l. 67 */ 68 static fn_t * 69 srchfn(const char *s, size_t len) 70 { 71 fn_t *fn; 72 73 for (fn = fnames; fn != NULL; fn = fn->fn_nxt) { 74 if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0) 75 break; 76 } 77 return (fn); 78 } 79 80 /* 81 * Return a shared string for filename s. 82 */ 83 const char * 84 fnalloc(const char *s) 85 { 86 87 return (s != NULL ? fnnalloc(s, strlen(s)) : NULL); 88 } 89 90 struct repl { 91 char *orig; 92 char *repl; 93 size_t len; 94 struct repl *next; 95 }; 96 97 struct repl *replist; 98 99 void 100 fnaddreplsrcdir(char *arg) 101 { 102 struct repl *r = xmalloc(sizeof(*r)); 103 104 r->orig = arg; 105 if ((r->repl = strchr(arg, '=')) == NULL) 106 err(1, "Bad replacement directory spec `%s'", arg); 107 r->len = r->repl - r->orig; 108 *(r->repl)++ = '\0'; 109 if (replist == NULL) { 110 r->next = NULL; 111 } else 112 r->next = replist; 113 replist = r; 114 } 115 116 const char * 117 fnxform(const char *name, size_t len) 118 { 119 static char buf[MAXPATHLEN]; 120 struct repl *r; 121 122 for (r = replist; r; r = r->next) 123 if (r->len < len && memcmp(name, r->orig, r->len) == 0) 124 break; 125 if (r == NULL) 126 return name; 127 snprintf(buf, sizeof(buf), "%s%s", r->repl, name + r->len); 128 return buf; 129 } 130 131 const char * 132 fnnalloc(const char *s, size_t len) 133 { 134 fn_t *fn; 135 136 static int nxt_id = 0; 137 138 if (s == NULL) 139 return (NULL); 140 141 if ((fn = srchfn(s, len)) == NULL) { 142 fn = xmalloc(sizeof (fn_t)); 143 /* Do not used strdup() because string is not NUL-terminated.*/ 144 fn->fn_name = xmalloc(len + 1); 145 (void)memcpy(fn->fn_name, s, len); 146 fn->fn_name[len] = '\0'; 147 fn->fn_len = len; 148 fn->fn_id = nxt_id++; 149 fn->fn_nxt = fnames; 150 fnames = fn; 151 /* Write id of this filename to the output file. */ 152 outclr(); 153 outint(fn->fn_id); 154 outchar('s'); 155 outstrg(fnxform(fn->fn_name, fn->fn_len)); 156 } 157 return (fn->fn_name); 158 } 159 160 /* 161 * Get id of a filename. 162 */ 163 int 164 getfnid(const char *s) 165 { 166 fn_t *fn; 167 168 if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL) 169 return (-1); 170 return (fn->fn_id); 171 } 172 173 /* 174 * Memory for declarations and other things which must be available 175 * until the end of a block (or the end of the translation unit) 176 * are associated with the level (mblklev) of the block (or with 0). 177 * Because this memory is allocated in large blocks associated with 178 * a given level it can be freed easily at the end of a block. 179 */ 180 #define ML_INC ((size_t)32) /* Increment for length of *mblks */ 181 182 typedef struct mbl { 183 void *blk; /* beginning of memory block */ 184 void *ffree; /* first free byte */ 185 size_t nfree; /* # of free bytes */ 186 size_t size; /* total size of memory block */ 187 struct mbl *nxt; /* next block */ 188 } mbl_t; 189 190 /* 191 * Array of pointers to lists of memory blocks. mblklev is used as 192 * index into this array. 193 */ 194 static mbl_t **mblks; 195 196 /* number of elements in *mblks */ 197 static size_t nmblks; 198 199 /* free list for memory blocks */ 200 static mbl_t *frmblks; 201 202 /* length of new allocated memory blocks */ 203 static size_t mblklen; 204 205 static void *xgetblk(mbl_t **, size_t); 206 static void xfreeblk(mbl_t **); 207 static mbl_t *xnewblk(void); 208 209 static mbl_t * 210 xnewblk(void) 211 { 212 mbl_t *mb = xmalloc(sizeof (mbl_t)); 213 214 /* use mmap instead of malloc to avoid malloc's size overhead */ 215 mb->blk = xmapalloc(mblklen); 216 mb->size = mblklen; 217 218 return (mb); 219 } 220 221 /* 222 * Allocate new memory. If the first block of the list has not enough 223 * free space, or there is no first block, get a new block. The new 224 * block is taken from the free list or, if there is no block on the 225 * free list, is allocated using xnewblk(). If a new block is allocated 226 * it is initialized with zero. Blocks taken from the free list are 227 * zero'd in xfreeblk(). 228 */ 229 static void * 230 xgetblk(mbl_t **mbp, size_t s) 231 { 232 mbl_t *mb; 233 void *p; 234 size_t t = 0; 235 236 s = WORST_ALIGN(s); 237 if ((mb = *mbp) == NULL || mb->nfree < s) { 238 if ((mb = frmblks) == NULL || mb->size < s) { 239 if (s > mblklen) { 240 t = mblklen; 241 mblklen = s; 242 } 243 mb = xnewblk(); 244 #ifndef BLKDEBUG 245 (void)memset(mb->blk, 0, mb->size); 246 #endif 247 if (t) 248 mblklen = t; 249 } else { 250 frmblks = mb->nxt; 251 } 252 mb->ffree = mb->blk; 253 mb->nfree = mb->size; 254 mb->nxt = *mbp; 255 *mbp = mb; 256 } 257 p = mb->ffree; 258 mb->ffree = (char *)mb->ffree + s; 259 mb->nfree -= s; 260 #ifdef BLKDEBUG 261 (void)memset(p, 0, s); 262 #endif 263 return (p); 264 } 265 266 /* 267 * Move all blocks from list *fmbp to free list. For each block, set all 268 * used memory to zero. 269 */ 270 static void 271 xfreeblk(mbl_t **fmbp) 272 { 273 mbl_t *mb; 274 275 while ((mb = *fmbp) != NULL) { 276 *fmbp = mb->nxt; 277 mb->nxt = frmblks; 278 frmblks = mb; 279 (void)memset(mb->blk, ZERO, mb->size - mb->nfree); 280 } 281 } 282 283 void 284 initmem(void) 285 { 286 int pgsz; 287 288 pgsz = getpagesize(); 289 mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz; 290 291 mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *)); 292 } 293 294 295 /* 296 * Allocate memory associated with level l. 297 */ 298 void * 299 getlblk(size_t l, size_t s) 300 { 301 302 while (l >= nmblks) { 303 mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *)); 304 (void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *)); 305 nmblks += ML_INC; 306 } 307 return (xgetblk(&mblks[l], s)); 308 } 309 310 void * 311 getblk(size_t s) 312 { 313 314 return (getlblk(mblklev, s)); 315 } 316 317 /* 318 * Free all memory associated with level l. 319 */ 320 void 321 freelblk(int l) 322 { 323 324 xfreeblk(&mblks[l]); 325 } 326 327 void 328 freeblk(void) 329 { 330 331 freelblk(mblklev); 332 } 333 334 /* 335 * tgetblk() returns memory which is associated with the current 336 * expression. 337 */ 338 static mbl_t *tmblk; 339 340 void * 341 tgetblk(size_t s) 342 { 343 344 return (xgetblk(&tmblk, s)); 345 } 346 347 /* 348 * Get memory for a new tree node. 349 */ 350 tnode_t * 351 getnode(void) 352 { 353 354 return (tgetblk(sizeof (tnode_t))); 355 } 356 357 /* 358 * Free all memory which is allocated by the current expression. 359 */ 360 void 361 tfreeblk(void) 362 { 363 364 xfreeblk(&tmblk); 365 } 366 367 /* 368 * Save the memory which is used by the current expression. This memory 369 * is not freed by the next tfreeblk() call. The pointer returned can be 370 * used to restore the memory. 371 */ 372 mbl_t * 373 tsave(void) 374 { 375 mbl_t *tmem; 376 377 tmem = tmblk; 378 tmblk = NULL; 379 return (tmem); 380 } 381 382 /* 383 * Free all memory used for the current expression and the memory used 384 * be a previous expression and saved by tsave(). The next call to 385 * tfreeblk() frees the restored memory. 386 */ 387 void 388 trestor(mbl_t *tmem) 389 { 390 391 tfreeblk(); 392 if (tmblk != NULL) { 393 free(tmblk->blk); 394 free(tmblk); 395 } 396 tmblk = tmem; 397 } 398