blob: 54ab99bffe9a6979e50d057d3a61d576f299fbc4 [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)) {
sewardjde4a1d02002-03-22 01:27:54 +0000137 ai->akind = UserG;
138 ai->blksize = vg_cgbs[i].size;
139 ai->rwoffset = (Int)(a) - (Int)(vg_cgbs[i].start);
140 ai->lastchange = vg_cgbs[i].where;
141 return True;
142 }
143 }
144 return False;
145}
146
njn72718642003-07-24 08:45:32 +0000147Bool SK_(handle_client_request) ( ThreadId tid, UInt* arg, UInt* ret )
sewardjde4a1d02002-03-22 01:27:54 +0000148{
sewardj2e93c502002-04-12 11:12:52 +0000149 Int i;
150 Bool ok;
151 Addr bad_addr;
sewardjde4a1d02002-03-22 01:27:54 +0000152
njnd7994182003-10-02 13:44:04 +0000153 if (!VG_IS_SKIN_USERREQ('M','C',arg[0])
154 && VG_USERREQ__MALLOCLIKE_BLOCK != arg[0]
155 && VG_USERREQ__FREELIKE_BLOCK != arg[0])
sewardj34042512002-10-22 04:14:35 +0000156 return False;
157
sewardj2e93c502002-04-12 11:12:52 +0000158 switch (arg[0]) {
njn25e49d8e72002-09-23 09:36:25 +0000159 case VG_USERREQ__CHECK_WRITABLE: /* check writable */
njn5c004e42002-11-18 11:04:50 +0000160 ok = MC_(check_writable) ( arg[1], arg[2], &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000161 if (!ok)
njn72718642003-07-24 08:45:32 +0000162 MC_(record_user_error) ( tid, bad_addr, True );
sewardj34042512002-10-22 04:14:35 +0000163 *ret = ok ? (UInt)NULL : bad_addr;
164 break;
njn25e49d8e72002-09-23 09:36:25 +0000165
166 case VG_USERREQ__CHECK_READABLE: /* check readable */
njn5c004e42002-11-18 11:04:50 +0000167 ok = MC_(check_readable) ( arg[1], arg[2], &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000168 if (!ok)
njn72718642003-07-24 08:45:32 +0000169 MC_(record_user_error) ( tid, bad_addr, False );
sewardj34042512002-10-22 04:14:35 +0000170 *ret = ok ? (UInt)NULL : bad_addr;
171 break;
njn25e49d8e72002-09-23 09:36:25 +0000172
173 case VG_USERREQ__DO_LEAK_CHECK:
njn5c004e42002-11-18 11:04:50 +0000174 MC_(detect_memory_leaks)();
sewardj34042512002-10-22 04:14:35 +0000175 *ret = 0; /* return value is meaningless */
176 break;
njn25e49d8e72002-09-23 09:36:25 +0000177
sewardj2e93c502002-04-12 11:12:52 +0000178 case VG_USERREQ__MAKE_NOACCESS: /* make no access */
sewardjde4a1d02002-03-22 01:27:54 +0000179 i = vg_alloc_client_block();
180 /* VG_(printf)("allocated %d %p\n", i, vg_cgbs); */
181 vg_cgbs[i].kind = CG_NoAccess;
sewardj2e93c502002-04-12 11:12:52 +0000182 vg_cgbs[i].start = arg[1];
183 vg_cgbs[i].size = arg[2];
njn72718642003-07-24 08:45:32 +0000184 vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
njn5c004e42002-11-18 11:04:50 +0000185 MC_(make_noaccess) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000186 *ret = i;
187 break;
njn25e49d8e72002-09-23 09:36:25 +0000188
sewardj2e93c502002-04-12 11:12:52 +0000189 case VG_USERREQ__MAKE_WRITABLE: /* make writable */
sewardjde4a1d02002-03-22 01:27:54 +0000190 i = vg_alloc_client_block();
191 vg_cgbs[i].kind = CG_Writable;
sewardj2e93c502002-04-12 11:12:52 +0000192 vg_cgbs[i].start = arg[1];
193 vg_cgbs[i].size = arg[2];
njn72718642003-07-24 08:45:32 +0000194 vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
njn5c004e42002-11-18 11:04:50 +0000195 MC_(make_writable) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000196 *ret = i;
197 break;
njn25e49d8e72002-09-23 09:36:25 +0000198
sewardj2e93c502002-04-12 11:12:52 +0000199 case VG_USERREQ__MAKE_READABLE: /* make readable */
sewardjde4a1d02002-03-22 01:27:54 +0000200 i = vg_alloc_client_block();
201 vg_cgbs[i].kind = CG_Readable;
sewardj2e93c502002-04-12 11:12:52 +0000202 vg_cgbs[i].start = arg[1];
203 vg_cgbs[i].size = arg[2];
njn72718642003-07-24 08:45:32 +0000204 vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
njn5c004e42002-11-18 11:04:50 +0000205 MC_(make_readable) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000206 *ret = i;
207 break;
208
sewardj2e93c502002-04-12 11:12:52 +0000209 case VG_USERREQ__DISCARD: /* discard */
sewardjde4a1d02002-03-22 01:27:54 +0000210 if (vg_cgbs == NULL
sewardj2e93c502002-04-12 11:12:52 +0000211 || arg[2] >= vg_cgb_used || vg_cgbs[arg[2]].kind == CG_NotInUse)
sewardjde4a1d02002-03-22 01:27:54 +0000212 return 1;
njne427a662002-10-02 11:08:25 +0000213 sk_assert(arg[2] >= 0 && arg[2] < vg_cgb_used);
sewardj2e93c502002-04-12 11:12:52 +0000214 vg_cgbs[arg[2]].kind = CG_NotInUse;
sewardjde4a1d02002-03-22 01:27:54 +0000215 vg_cgb_discards++;
sewardj34042512002-10-22 04:14:35 +0000216 *ret = 0;
217 break;
sewardjde4a1d02002-03-22 01:27:54 +0000218
sewardjee070842003-07-05 17:53:55 +0000219 case VG_USERREQ__GET_VBITS:
220 /* Returns: 1 == OK, 2 == alignment error, 3 == addressing
221 error. */
222 /* VG_(printf)("get_vbits %p %p %d\n", arg[1], arg[2], arg[3] ); */
223 *ret = MC_(get_or_set_vbits_for_client)
njn72718642003-07-24 08:45:32 +0000224 ( tid, arg[1], arg[2], arg[3], False /* get them */ );
sewardjee070842003-07-05 17:53:55 +0000225 break;
226
227 case VG_USERREQ__SET_VBITS:
228 /* Returns: 1 == OK, 2 == alignment error, 3 == addressing
229 error. */
230 /* VG_(printf)("set_vbits %p %p %d\n", arg[1], arg[2], arg[3] ); */
231 *ret = MC_(get_or_set_vbits_for_client)
njn72718642003-07-24 08:45:32 +0000232 ( tid, arg[1], arg[2], arg[3], True /* set them */ );
sewardjee070842003-07-05 17:53:55 +0000233 break;
234
fitzhardinge98abfc72003-12-16 02:05:15 +0000235 case _VG_USERREQ__MEMCHECK_GET_RECORD_OVERLAP:
236 *ret = (Addr)MAC_(record_overlap_error);
237 break;
238
sewardjde4a1d02002-03-22 01:27:54 +0000239 default:
njn72718642003-07-24 08:45:32 +0000240 if (MAC_(handle_common_client_requests)(tid, arg, ret )) {
njn47363ab2003-04-21 13:24:40 +0000241 return True;
242 } else {
243 VG_(message)(Vg_UserMsg,
244 "Warning: unknown memcheck client request code %d",
245 arg[0]);
246 return False;
247 }
sewardjde4a1d02002-03-22 01:27:54 +0000248 }
sewardj34042512002-10-22 04:14:35 +0000249 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000250}
251
252
253/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000254/*--- end mc_clientreqs.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +0000255/*--------------------------------------------------------------------*/