blob: f29261d5688acac6a749f39a4d82ea17c16caeac [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{
78 Int i, sz_new;
79 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{
129 Int i;
130 /* 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
sewardj34042512002-10-22 04:14:35 +0000147Bool SK_(handle_client_request) ( ThreadState* tst, UInt* arg_block, 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;
152 UInt* arg = arg_block;
sewardjde4a1d02002-03-22 01:27:54 +0000153
sewardj34042512002-10-22 04:14:35 +0000154 if (!VG_IS_SKIN_USERREQ('M','C',arg[0]))
155 return False;
156
sewardj2e93c502002-04-12 11:12:52 +0000157 switch (arg[0]) {
njn25e49d8e72002-09-23 09:36:25 +0000158 case VG_USERREQ__CHECK_WRITABLE: /* check writable */
njn5c004e42002-11-18 11:04:50 +0000159 ok = MC_(check_writable) ( arg[1], arg[2], &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000160 if (!ok)
njn5c004e42002-11-18 11:04:50 +0000161 MC_(record_user_error) ( tst, bad_addr, True );
sewardj34042512002-10-22 04:14:35 +0000162 *ret = ok ? (UInt)NULL : bad_addr;
163 break;
njn25e49d8e72002-09-23 09:36:25 +0000164
165 case VG_USERREQ__CHECK_READABLE: /* check readable */
njn5c004e42002-11-18 11:04:50 +0000166 ok = MC_(check_readable) ( arg[1], arg[2], &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000167 if (!ok)
njn5c004e42002-11-18 11:04:50 +0000168 MC_(record_user_error) ( tst, bad_addr, False );
sewardj34042512002-10-22 04:14:35 +0000169 *ret = ok ? (UInt)NULL : bad_addr;
170 break;
njn25e49d8e72002-09-23 09:36:25 +0000171
172 case VG_USERREQ__DO_LEAK_CHECK:
njn5c004e42002-11-18 11:04:50 +0000173 MC_(detect_memory_leaks)();
sewardj34042512002-10-22 04:14:35 +0000174 *ret = 0; /* return value is meaningless */
175 break;
njn25e49d8e72002-09-23 09:36:25 +0000176
sewardj2e93c502002-04-12 11:12:52 +0000177 case VG_USERREQ__MAKE_NOACCESS: /* make no access */
sewardjde4a1d02002-03-22 01:27:54 +0000178 i = vg_alloc_client_block();
179 /* VG_(printf)("allocated %d %p\n", i, vg_cgbs); */
180 vg_cgbs[i].kind = CG_NoAccess;
sewardj2e93c502002-04-12 11:12:52 +0000181 vg_cgbs[i].start = arg[1];
182 vg_cgbs[i].size = arg[2];
njn25e49d8e72002-09-23 09:36:25 +0000183 vg_cgbs[i].where = VG_(get_ExeContext) ( tst );
njn5c004e42002-11-18 11:04:50 +0000184 MC_(make_noaccess) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000185 *ret = i;
186 break;
njn25e49d8e72002-09-23 09:36:25 +0000187
sewardj2e93c502002-04-12 11:12:52 +0000188 case VG_USERREQ__MAKE_WRITABLE: /* make writable */
sewardjde4a1d02002-03-22 01:27:54 +0000189 i = vg_alloc_client_block();
190 vg_cgbs[i].kind = CG_Writable;
sewardj2e93c502002-04-12 11:12:52 +0000191 vg_cgbs[i].start = arg[1];
192 vg_cgbs[i].size = arg[2];
njn25e49d8e72002-09-23 09:36:25 +0000193 vg_cgbs[i].where = VG_(get_ExeContext) ( tst );
njn5c004e42002-11-18 11:04:50 +0000194 MC_(make_writable) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000195 *ret = i;
196 break;
njn25e49d8e72002-09-23 09:36:25 +0000197
sewardj2e93c502002-04-12 11:12:52 +0000198 case VG_USERREQ__MAKE_READABLE: /* make readable */
sewardjde4a1d02002-03-22 01:27:54 +0000199 i = vg_alloc_client_block();
200 vg_cgbs[i].kind = CG_Readable;
sewardj2e93c502002-04-12 11:12:52 +0000201 vg_cgbs[i].start = arg[1];
202 vg_cgbs[i].size = arg[2];
njn25e49d8e72002-09-23 09:36:25 +0000203 vg_cgbs[i].where = VG_(get_ExeContext) ( tst );
njn5c004e42002-11-18 11:04:50 +0000204 MC_(make_readable) ( arg[1], arg[2] );
sewardj34042512002-10-22 04:14:35 +0000205 *ret = i;
206 break;
207
sewardj2e93c502002-04-12 11:12:52 +0000208 case VG_USERREQ__DISCARD: /* discard */
sewardjde4a1d02002-03-22 01:27:54 +0000209 if (vg_cgbs == NULL
sewardj2e93c502002-04-12 11:12:52 +0000210 || arg[2] >= vg_cgb_used || vg_cgbs[arg[2]].kind == CG_NotInUse)
sewardjde4a1d02002-03-22 01:27:54 +0000211 return 1;
njne427a662002-10-02 11:08:25 +0000212 sk_assert(arg[2] >= 0 && arg[2] < vg_cgb_used);
sewardj2e93c502002-04-12 11:12:52 +0000213 vg_cgbs[arg[2]].kind = CG_NotInUse;
sewardjde4a1d02002-03-22 01:27:54 +0000214 vg_cgb_discards++;
sewardj34042512002-10-22 04:14:35 +0000215 *ret = 0;
216 break;
sewardjde4a1d02002-03-22 01:27:54 +0000217
sewardjde4a1d02002-03-22 01:27:54 +0000218 default:
219 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +0000220 "Warning: unknown memcheck client request code %d",
221 arg[0]);
sewardj34042512002-10-22 04:14:35 +0000222 return False;
sewardjde4a1d02002-03-22 01:27:54 +0000223 }
sewardj34042512002-10-22 04:14:35 +0000224 return True;
sewardjde4a1d02002-03-22 01:27:54 +0000225}
226
227
228/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000229/*--- end mc_clientreqs.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +0000230/*--------------------------------------------------------------------*/