blob: 959223774105b886965ea203a48f89725595ab01 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00003/*--- For when the client advises Valgrind about memory ---*/
4/*--- permissions. ---*/
njn25cac76cb2002-09-23 11:21:57 +00005/*--- mc_clientreqs.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +00006/*--------------------------------------------------------------------*/
7
8/*
nethercote137bc552003-11-14 17:47:54 +00009 This file is part of MemCheck, a heavyweight Valgrind tool for
njnc9539842002-10-02 13:26:35 +000010 detecting memory errors.
sewardjde4a1d02002-03-22 01:27:54 +000011
nethercotebb1c9912004-01-04 16:43:23 +000012 Copyright (C) 2000-2004 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000013 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000014
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
njn25e49d8e72002-09-23 09:36:25 +000030 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000031*/
32
njn25cac76cb2002-09-23 11:21:57 +000033#include "mc_include.h"
sewardjde4a1d02002-03-22 01:27:54 +000034
njn25cac76cb2002-09-23 11:21:57 +000035#include "memcheck.h" /* for VG_USERREQ__* */
sewardj2e93c502002-04-12 11:12:52 +000036
sewardjde4a1d02002-03-22 01:27:54 +000037
38/*------------------------------------------------------------*/
39/*--- General client block management. ---*/
40/*------------------------------------------------------------*/
41
42/* This is managed as an expanding array of client block descriptors.
43 Indices of live descriptors are issued to the client, so it can ask
44 to free them later. Therefore we cannot slide live entries down
45 over dead ones. Instead we must use free/inuse flags and scan for
46 an empty slot at allocation time. This in turn means allocation is
47 relatively expensive, so we hope this does not happen too often.
48*/
49
50typedef
51 enum { CG_NotInUse, CG_NoAccess, CG_Writable, CG_Readable }
52 CGenBlockKind;
53
54typedef
55 struct {
56 Addr start;
57 UInt size;
58 ExeContext* where;
59 CGenBlockKind kind;
60 }
61 CGenBlock;
62
63/* This subsystem is self-initialising. */
64static UInt vg_cgb_size = 0;
65static UInt vg_cgb_used = 0;
66static CGenBlock* vg_cgbs = NULL;
67
68/* Stats for this subsystem. */
69static UInt vg_cgb_used_MAX = 0; /* Max in use. */
70static UInt vg_cgb_allocs = 0; /* Number of allocs. */
71static UInt vg_cgb_discards = 0; /* Number of discards. */
72static UInt vg_cgb_search = 0; /* Number of searches. */
73
74
75static
76Int vg_alloc_client_block ( void )
77{
sewardj05bcdcb2003-05-18 10:05:38 +000078 UInt i, sz_new;
sewardjde4a1d02002-03-22 01:27:54 +000079 CGenBlock* cgbs_new;
80
81 vg_cgb_allocs++;
82
83 for (i = 0; i < vg_cgb_used; i++) {
84 vg_cgb_search++;
85 if (vg_cgbs[i].kind == CG_NotInUse)
86 return i;
87 }
88
89 /* Not found. Try to allocate one at the end. */
90 if (vg_cgb_used < vg_cgb_size) {
91 vg_cgb_used++;
92 return vg_cgb_used-1;
93 }
94
95 /* Ok, we have to allocate a new one. */
njne427a662002-10-02 11:08:25 +000096 sk_assert(vg_cgb_used == vg_cgb_size);
sewardjde4a1d02002-03-22 01:27:54 +000097 sz_new = (vg_cgbs == NULL) ? 10 : (2 * vg_cgb_size);
98
njn25e49d8e72002-09-23 09:36:25 +000099 cgbs_new = VG_(malloc)( sz_new * sizeof(CGenBlock) );
sewardjde4a1d02002-03-22 01:27:54 +0000100 for (i = 0; i < vg_cgb_used; i++)
101 cgbs_new[i] = vg_cgbs[i];
102
103 if (vg_cgbs != NULL)
njn25e49d8e72002-09-23 09:36:25 +0000104 VG_(free)( vg_cgbs );
sewardjde4a1d02002-03-22 01:27:54 +0000105 vg_cgbs = cgbs_new;
106
107 vg_cgb_size = sz_new;
108 vg_cgb_used++;
109 if (vg_cgb_used > vg_cgb_used_MAX)
110 vg_cgb_used_MAX = vg_cgb_used;
111 return vg_cgb_used-1;
112}
113
114
115/*------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +0000116/*--- Externally visible functions. ---*/
117/*------------------------------------------------------------*/
118
njn5c004e42002-11-18 11:04:50 +0000119void MC_(show_client_block_stats) ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000120{
121 VG_(message)(Vg_DebugMsg,
122 "general CBs: %d allocs, %d discards, %d maxinuse, %d search",
123 vg_cgb_allocs, vg_cgb_discards, vg_cgb_used_MAX, vg_cgb_search
124 );
sewardjde4a1d02002-03-22 01:27:54 +0000125}
126
njn5c004e42002-11-18 11:04:50 +0000127Bool MC_(client_perm_maybe_describe)( Addr a, AddrInfo* ai )
sewardjde4a1d02002-03-22 01:27:54 +0000128{
sewardj05bcdcb2003-05-18 10:05:38 +0000129 UInt i;
sewardjde4a1d02002-03-22 01:27:54 +0000130 /* VG_(printf)("try to identify %d\n", a); */
131
sewardja81709d2002-12-28 12:55:48 +0000132 /* Perhaps it's a general block ? */
sewardjde4a1d02002-03-22 01:27:54 +0000133 for (i = 0; i < vg_cgb_used; i++) {
134 if (vg_cgbs[i].kind == CG_NotInUse)
135 continue;
njn25e49d8e72002-09-23 09:36:25 +0000136 if (VG_(addr_is_in_block)(a, vg_cgbs[i].start, vg_cgbs[i].size)) {
rjwalshbc0bb832004-06-19 18:12:36 +0000137 MAC_Mempool **d, *mp;
138
139 /* OK - maybe it's a mempool, too? */
140 mp = (MAC_Mempool*)VG_(HT_get_node)(MAC_(mempool_list),
141 (UInt)vg_cgbs[i].start,
142 (VgHashNode***)&d);
143 if(mp != NULL) {
144 if(mp->chunks != NULL) {
145 MAC_Chunk *mc;
146
147 Bool find_addr(VgHashNode* sh_ch)
148 {
149 MAC_Chunk *m = (MAC_Chunk*)sh_ch;
150 return VG_(addr_is_in_block)(a, m->data, m->size);
151 }
152
153 mc = (MAC_Chunk*)VG_(HT_first_match)(mp->chunks, find_addr);
154 if(mc != NULL) {
155 ai->akind = UserG;
156 ai->blksize = mc->size;
157 ai->rwoffset = (Int)(a) - (Int)mc->data;
158 ai->lastchange = mc->where;
159 return True;
160 }
161 }
162 ai->akind = Mempool;
163 ai->blksize = vg_cgbs[i].size;
164 ai->rwoffset = (Int)(a) - (Int)(vg_cgbs[i].start);
165 ai->lastchange = vg_cgbs[i].where;
166 return True;
167 }
sewardjde4a1d02002-03-22 01:27:54 +0000168 ai->akind = UserG;
169 ai->blksize = vg_cgbs[i].size;
170 ai->rwoffset = (Int)(a) - (Int)(vg_cgbs[i].start);
171 ai->lastchange = vg_cgbs[i].where;
172 return True;
173 }
174 }
175 return False;
176}
177
njn72718642003-07-24 08:45:32 +0000178Bool SK_(handle_client_request) ( ThreadId tid, UInt* arg, UInt* ret )
sewardjde4a1d02002-03-22 01:27:54 +0000179{
sewardj2e93c502002-04-12 11:12:52 +0000180 Int i;
181 Bool ok;
182 Addr bad_addr;
sewardjde4a1d02002-03-22 01:27:54 +0000183
njnd7994182003-10-02 13:44:04 +0000184 if (!VG_IS_SKIN_USERREQ('M','C',arg[0])
185 && VG_USERREQ__MALLOCLIKE_BLOCK != arg[0]
rjwalshbc0bb832004-06-19 18:12:36 +0000186 && VG_USERREQ__FREELIKE_BLOCK != arg[0]
187 && VG_USERREQ__CREATE_MEMPOOL != arg[0]
188 && VG_USERREQ__DESTROY_MEMPOOL != arg[0]
189 && VG_USERREQ__MEMPOOL_ALLOC != arg[0]
190 && VG_USERREQ__MEMPOOL_FREE != arg[0])
sewardj34042512002-10-22 04:14:35 +0000191 return False;
192
sewardj2e93c502002-04-12 11:12:52 +0000193 switch (arg[0]) {
njn25e49d8e72002-09-23 09:36:25 +0000194 case VG_USERREQ__CHECK_WRITABLE: /* check writable */
njn5c004e42002-11-18 11:04:50 +0000195 ok = MC_(check_writable) ( arg[1], arg[2], &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000196 if (!ok)
njn72718642003-07-24 08:45:32 +0000197 MC_(record_user_error) ( tid, bad_addr, True );
sewardj34042512002-10-22 04:14:35 +0000198 *ret = ok ? (UInt)NULL : bad_addr;
199 break;
njn25e49d8e72002-09-23 09:36:25 +0000200
201 case VG_USERREQ__CHECK_READABLE: /* check readable */
njn5c004e42002-11-18 11:04:50 +0000202 ok = MC_(check_readable) ( arg[1], arg[2], &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000203 if (!ok)
njn72718642003-07-24 08:45:32 +0000204 MC_(record_user_error) ( tid, bad_addr, False );
sewardj34042512002-10-22 04:14:35 +0000205 *ret = ok ? (UInt)NULL : bad_addr;
206 break;
njn25e49d8e72002-09-23 09:36:25 +0000207
208 case VG_USERREQ__DO_LEAK_CHECK:
njn5c004e42002-11-18 11:04:50 +0000209 MC_(detect_memory_leaks)();
sewardj34042512002-10-22 04:14:35 +0000210 *ret = 0; /* return value is meaningless */
211 break;
njn25e49d8e72002-09-23 09:36:25 +0000212
sewardj2e93c502002-04-12 11:12:52 +0000213 case VG_USERREQ__MAKE_NOACCESS: /* make no access */
sewardjde4a1d02002-03-22 01:27:54 +0000214 i = vg_alloc_client_block();
215 /* VG_(printf)("allocated %d %p\n", i, vg_cgbs); */
216 vg_cgbs[i].kind = CG_NoAccess;
sewardj2e93c502002-04-12 11:12:52 +0000217 vg_cgbs[i].start = arg[1];
218 vg_cgbs[i].size = arg[2];
njn72718642003-07-24 08:45:32 +0000219 vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
njn5c004e42002-11-18 11:04:50 +0000220 MC_(make_noaccess) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000221 *ret = i;
222 break;
njn25e49d8e72002-09-23 09:36:25 +0000223
sewardj2e93c502002-04-12 11:12:52 +0000224 case VG_USERREQ__MAKE_WRITABLE: /* make writable */
sewardjde4a1d02002-03-22 01:27:54 +0000225 i = vg_alloc_client_block();
226 vg_cgbs[i].kind = CG_Writable;
sewardj2e93c502002-04-12 11:12:52 +0000227 vg_cgbs[i].start = arg[1];
228 vg_cgbs[i].size = arg[2];
njn72718642003-07-24 08:45:32 +0000229 vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
njn5c004e42002-11-18 11:04:50 +0000230 MC_(make_writable) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000231 *ret = i;
232 break;
njn25e49d8e72002-09-23 09:36:25 +0000233
sewardj2e93c502002-04-12 11:12:52 +0000234 case VG_USERREQ__MAKE_READABLE: /* make readable */
sewardjde4a1d02002-03-22 01:27:54 +0000235 i = vg_alloc_client_block();
236 vg_cgbs[i].kind = CG_Readable;
sewardj2e93c502002-04-12 11:12:52 +0000237 vg_cgbs[i].start = arg[1];
238 vg_cgbs[i].size = arg[2];
njn72718642003-07-24 08:45:32 +0000239 vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
njn5c004e42002-11-18 11:04:50 +0000240 MC_(make_readable) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000241 *ret = i;
242 break;
243
sewardj2e93c502002-04-12 11:12:52 +0000244 case VG_USERREQ__DISCARD: /* discard */
sewardjde4a1d02002-03-22 01:27:54 +0000245 if (vg_cgbs == NULL
sewardj2e93c502002-04-12 11:12:52 +0000246 || arg[2] >= vg_cgb_used || vg_cgbs[arg[2]].kind == CG_NotInUse)
sewardjde4a1d02002-03-22 01:27:54 +0000247 return 1;
njne427a662002-10-02 11:08:25 +0000248 sk_assert(arg[2] >= 0 && arg[2] < vg_cgb_used);
sewardj2e93c502002-04-12 11:12:52 +0000249 vg_cgbs[arg[2]].kind = CG_NotInUse;
sewardjde4a1d02002-03-22 01:27:54 +0000250 vg_cgb_discards++;
sewardj34042512002-10-22 04:14:35 +0000251 *ret = 0;
252 break;
sewardjde4a1d02002-03-22 01:27:54 +0000253
sewardjee070842003-07-05 17:53:55 +0000254 case VG_USERREQ__GET_VBITS:
255 /* Returns: 1 == OK, 2 == alignment error, 3 == addressing
256 error. */
257 /* VG_(printf)("get_vbits %p %p %d\n", arg[1], arg[2], arg[3] ); */
258 *ret = MC_(get_or_set_vbits_for_client)
njn72718642003-07-24 08:45:32 +0000259 ( tid, arg[1], arg[2], arg[3], False /* get them */ );
sewardjee070842003-07-05 17:53:55 +0000260 break;
261
262 case VG_USERREQ__SET_VBITS:
263 /* Returns: 1 == OK, 2 == alignment error, 3 == addressing
264 error. */
265 /* VG_(printf)("set_vbits %p %p %d\n", arg[1], arg[2], arg[3] ); */
266 *ret = MC_(get_or_set_vbits_for_client)
njn72718642003-07-24 08:45:32 +0000267 ( tid, arg[1], arg[2], arg[3], True /* set them */ );
sewardjee070842003-07-05 17:53:55 +0000268 break;
269
sewardjde4a1d02002-03-22 01:27:54 +0000270 default:
njn72718642003-07-24 08:45:32 +0000271 if (MAC_(handle_common_client_requests)(tid, arg, ret )) {
njn47363ab2003-04-21 13:24:40 +0000272 return True;
273 } else {
274 VG_(message)(Vg_UserMsg,
275 "Warning: unknown memcheck client request code %d",
276 arg[0]);
277 return False;
278 }
sewardjde4a1d02002-03-22 01:27:54 +0000279 }
sewardj34042512002-10-22 04:14:35 +0000280 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000281}
282
283
284/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000285/*--- end mc_clientreqs.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +0000286/*--------------------------------------------------------------------*/