blob: 58c9b0e68aa7c5768697f93a560bd6e4d4d6e176 [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/*
njnc9539842002-10-02 13:26:35 +00009 This file is part of MemCheck, a heavyweight Valgrind skin for
10 detecting memory errors.
sewardjde4a1d02002-03-22 01:27:54 +000011
njn0e1b5142003-04-15 14:58:06 +000012 Copyright (C) 2000-2003 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
njn47363ab2003-04-21 13:24:40 +0000147Bool SK_(handle_client_request) ( ThreadState* tst, 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
sewardj34042512002-10-22 04:14:35 +0000153 if (!VG_IS_SKIN_USERREQ('M','C',arg[0]))
154 return False;
155
sewardj2e93c502002-04-12 11:12:52 +0000156 switch (arg[0]) {
njn25e49d8e72002-09-23 09:36:25 +0000157 case VG_USERREQ__CHECK_WRITABLE: /* check writable */
njn5c004e42002-11-18 11:04:50 +0000158 ok = MC_(check_writable) ( arg[1], arg[2], &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000159 if (!ok)
njn5c004e42002-11-18 11:04:50 +0000160 MC_(record_user_error) ( tst, bad_addr, True );
sewardj34042512002-10-22 04:14:35 +0000161 *ret = ok ? (UInt)NULL : bad_addr;
162 break;
njn25e49d8e72002-09-23 09:36:25 +0000163
164 case VG_USERREQ__CHECK_READABLE: /* check readable */
njn5c004e42002-11-18 11:04:50 +0000165 ok = MC_(check_readable) ( arg[1], arg[2], &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000166 if (!ok)
njn5c004e42002-11-18 11:04:50 +0000167 MC_(record_user_error) ( tst, bad_addr, False );
sewardj34042512002-10-22 04:14:35 +0000168 *ret = ok ? (UInt)NULL : bad_addr;
169 break;
njn25e49d8e72002-09-23 09:36:25 +0000170
171 case VG_USERREQ__DO_LEAK_CHECK:
njn5c004e42002-11-18 11:04:50 +0000172 MC_(detect_memory_leaks)();
sewardj34042512002-10-22 04:14:35 +0000173 *ret = 0; /* return value is meaningless */
174 break;
njn25e49d8e72002-09-23 09:36:25 +0000175
sewardj2e93c502002-04-12 11:12:52 +0000176 case VG_USERREQ__MAKE_NOACCESS: /* make no access */
sewardjde4a1d02002-03-22 01:27:54 +0000177 i = vg_alloc_client_block();
178 /* VG_(printf)("allocated %d %p\n", i, vg_cgbs); */
179 vg_cgbs[i].kind = CG_NoAccess;
sewardj2e93c502002-04-12 11:12:52 +0000180 vg_cgbs[i].start = arg[1];
181 vg_cgbs[i].size = arg[2];
njn25e49d8e72002-09-23 09:36:25 +0000182 vg_cgbs[i].where = VG_(get_ExeContext) ( tst );
njn5c004e42002-11-18 11:04:50 +0000183 MC_(make_noaccess) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000184 *ret = i;
185 break;
njn25e49d8e72002-09-23 09:36:25 +0000186
sewardj2e93c502002-04-12 11:12:52 +0000187 case VG_USERREQ__MAKE_WRITABLE: /* make writable */
sewardjde4a1d02002-03-22 01:27:54 +0000188 i = vg_alloc_client_block();
189 vg_cgbs[i].kind = CG_Writable;
sewardj2e93c502002-04-12 11:12:52 +0000190 vg_cgbs[i].start = arg[1];
191 vg_cgbs[i].size = arg[2];
njn25e49d8e72002-09-23 09:36:25 +0000192 vg_cgbs[i].where = VG_(get_ExeContext) ( tst );
njn5c004e42002-11-18 11:04:50 +0000193 MC_(make_writable) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000194 *ret = i;
195 break;
njn25e49d8e72002-09-23 09:36:25 +0000196
sewardj2e93c502002-04-12 11:12:52 +0000197 case VG_USERREQ__MAKE_READABLE: /* make readable */
sewardjde4a1d02002-03-22 01:27:54 +0000198 i = vg_alloc_client_block();
199 vg_cgbs[i].kind = CG_Readable;
sewardj2e93c502002-04-12 11:12:52 +0000200 vg_cgbs[i].start = arg[1];
201 vg_cgbs[i].size = arg[2];
njn25e49d8e72002-09-23 09:36:25 +0000202 vg_cgbs[i].where = VG_(get_ExeContext) ( tst );
njn5c004e42002-11-18 11:04:50 +0000203 MC_(make_readable) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000204 *ret = i;
205 break;
206
sewardj2e93c502002-04-12 11:12:52 +0000207 case VG_USERREQ__DISCARD: /* discard */
sewardjde4a1d02002-03-22 01:27:54 +0000208 if (vg_cgbs == NULL
sewardj2e93c502002-04-12 11:12:52 +0000209 || arg[2] >= vg_cgb_used || vg_cgbs[arg[2]].kind == CG_NotInUse)
sewardjde4a1d02002-03-22 01:27:54 +0000210 return 1;
njne427a662002-10-02 11:08:25 +0000211 sk_assert(arg[2] >= 0 && arg[2] < vg_cgb_used);
sewardj2e93c502002-04-12 11:12:52 +0000212 vg_cgbs[arg[2]].kind = CG_NotInUse;
sewardjde4a1d02002-03-22 01:27:54 +0000213 vg_cgb_discards++;
sewardj34042512002-10-22 04:14:35 +0000214 *ret = 0;
215 break;
sewardjde4a1d02002-03-22 01:27:54 +0000216
sewardjde4a1d02002-03-22 01:27:54 +0000217 default:
njn47363ab2003-04-21 13:24:40 +0000218 if (MAC_(handle_common_client_requests)(tst, arg, ret )) {
219 return True;
220 } else {
221 VG_(message)(Vg_UserMsg,
222 "Warning: unknown memcheck client request code %d",
223 arg[0]);
224 return False;
225 }
sewardjde4a1d02002-03-22 01:27:54 +0000226 }
sewardj34042512002-10-22 04:14:35 +0000227 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000228}
229
230
231/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000232/*--- end mc_clientreqs.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +0000233/*--------------------------------------------------------------------*/