Commit | Line | Data |
---|---|---|
2d822687 AC |
1 | /* This testcase is part of GDB, the GNU debugger. |
2 | ||
3 | Copyright 2004 Free Software Foundation, Inc. | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 | ||
19 | Please email any bugs, comments, and/or additions to this file to: | |
20 | bug-gdb@prep.ai.mit.edu */ | |
21 | ||
3c0edcdc AC |
22 | /* Get 64-bit stuff if on a GNU system. */ |
23 | #define _GNU_SOURCE | |
24 | ||
4e838464 MK |
25 | #include <sys/types.h> |
26 | #include <sys/time.h> | |
2d822687 | 27 | #include <sys/resource.h> |
3c0edcdc AC |
28 | #include <sys/stat.h> |
29 | #include <fcntl.h> | |
2d822687 | 30 | |
4e838464 MK |
31 | #include <stdlib.h> |
32 | #include <unistd.h> | |
33 | ||
2d822687 AC |
34 | /* Print routines: |
35 | ||
36 | The following are so that printf et.al. can be avoided. Those | |
37 | might try to use malloc() and that, for this code, would be a | |
38 | disaster. */ | |
39 | ||
40 | #define printf do not use | |
41 | ||
42 | const char digit[] = "0123456789abcdefghijklmnopqrstuvwxyz"; | |
43 | ||
44 | static void | |
45 | print_char (char c) | |
46 | { | |
47 | write (1, &c, sizeof (c)); | |
48 | } | |
49 | ||
50 | static void | |
3c0edcdc | 51 | print_unsigned (unsigned long long u) |
2d822687 AC |
52 | { |
53 | if (u >= 10) | |
54 | print_unsigned (u / 10); | |
55 | print_char (digit[u % 10]); | |
56 | } | |
57 | ||
58 | static void | |
3c0edcdc | 59 | print_hex (unsigned long long u) |
2d822687 AC |
60 | { |
61 | if (u >= 16) | |
62 | print_hex (u / 16); | |
63 | print_char (digit[u % 16]); | |
64 | } | |
65 | ||
66 | static void | |
67 | print_string (const char *s) | |
68 | { | |
69 | for (; (*s) != '\0'; s++) | |
70 | print_char ((*s)); | |
71 | } | |
72 | ||
73 | static void | |
74 | print_address (const void *a) | |
75 | { | |
76 | print_string ("0x"); | |
77 | print_hex ((unsigned long) a); | |
78 | } | |
79 | ||
3c0edcdc AC |
80 | static void |
81 | print_byte_count (unsigned long long u) | |
82 | { | |
83 | print_unsigned (u); | |
84 | print_string (" ("); | |
85 | print_string ("0x"); | |
86 | print_hex (u); | |
87 | print_string (") bytes"); | |
88 | } | |
89 | ||
2d822687 AC |
90 | /* Print the current values of RESOURCE. */ |
91 | ||
92 | static void | |
93 | print_rlimit (int resource) | |
94 | { | |
95 | struct rlimit rl; | |
96 | getrlimit (resource, &rl); | |
97 | print_string ("cur=0x"); | |
98 | print_hex (rl.rlim_cur); | |
99 | print_string (" max=0x"); | |
100 | print_hex (rl.rlim_max); | |
101 | } | |
102 | ||
103 | static void | |
104 | maximize_rlimit (int resource, const char *prefix) | |
105 | { | |
106 | struct rlimit rl; | |
107 | print_string (" "); | |
108 | print_string (prefix); | |
109 | print_string (": "); | |
110 | print_rlimit (resource); | |
111 | getrlimit (resource, &rl); | |
112 | rl.rlim_cur = rl.rlim_max; | |
113 | setrlimit (resource, &rl); | |
114 | print_string (" -> "); | |
115 | print_rlimit (resource); | |
116 | print_string ("\n"); | |
117 | } | |
118 | ||
119 | /* Maintain a doublely linked list. */ | |
120 | struct list | |
121 | { | |
122 | struct list *next; | |
123 | struct list *prev; | |
124 | size_t size; | |
125 | }; | |
126 | ||
127 | /* Put the "heap" in the DATA section. That way it is more likely | |
128 | that the variable will occur early in the core file (an address | |
129 | before the heap) and hence more likely that GDB will at least get | |
130 | its value right. | |
131 | ||
132 | To simplify the list append logic, start the heap out with one | |
133 | entry (that lives in the BSS section). */ | |
134 | ||
135 | static struct list dummy; | |
136 | static struct list heap = { &dummy, &dummy }; | |
137 | ||
bf08c2a1 DJ |
138 | static unsigned long bytes_allocated; |
139 | ||
3c0edcdc AC |
140 | #ifdef O_LARGEFILE |
141 | #define large_off_t off64_t | |
142 | #define large_lseek lseek64 | |
143 | #else | |
144 | #define large_off_t off_t | |
145 | #define O_LARGEFILE 0 | |
146 | #define large_lseek lseek | |
147 | #endif | |
148 | ||
2d822687 AC |
149 | int |
150 | main () | |
151 | { | |
152 | size_t max_chunk_size; | |
3c0edcdc | 153 | large_off_t max_core_size; |
2d822687 AC |
154 | |
155 | /* Try to expand all the resource limits beyond the point of sanity | |
156 | - we're after the biggest possible core file. */ | |
157 | ||
158 | print_string ("Maximize resource limits ...\n"); | |
159 | #ifdef RLIMIT_CORE | |
160 | maximize_rlimit (RLIMIT_CORE, "core"); | |
161 | #endif | |
162 | #ifdef RLIMIT_DATA | |
163 | maximize_rlimit (RLIMIT_DATA, "data"); | |
164 | #endif | |
165 | #ifdef RLIMIT_STACK | |
166 | maximize_rlimit (RLIMIT_STACK, "stack"); | |
167 | #endif | |
168 | #ifdef RLIMIT_AS | |
169 | maximize_rlimit (RLIMIT_AS, "stack"); | |
170 | #endif | |
171 | ||
3c0edcdc AC |
172 | print_string ("Maximize allocation limits ...\n"); |
173 | ||
174 | /* Compute the largest possible corefile size. No point in trying | |
175 | to create a corefile larger than the largest file supported by | |
176 | the file system. What about 64-bit lseek64? */ | |
177 | { | |
178 | int fd; | |
179 | large_off_t tmp; | |
180 | unlink ("bigcore.corefile"); | |
f3fb768d AS |
181 | fd = open ("bigcore.corefile", O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, |
182 | 0666); | |
3c0edcdc AC |
183 | for (tmp = 1; tmp > 0; tmp <<= 1) |
184 | { | |
185 | if (large_lseek (fd, tmp, SEEK_SET) > 0) | |
186 | max_core_size = tmp; | |
187 | } | |
188 | close (fd); | |
189 | } | |
190 | ||
2d822687 | 191 | /* Compute an initial chunk size. The math is dodgy but it works |
3c0edcdc AC |
192 | for the moment. Perhaphs there's a constant around somewhere. |
193 | Limit this to max_core_size bytes - no point in trying to | |
194 | allocate more than can be written to the corefile. */ | |
2d822687 AC |
195 | { |
196 | size_t tmp; | |
3c0edcdc | 197 | for (tmp = 1; tmp > 0 && tmp < max_core_size; tmp <<= 1) |
2d822687 AC |
198 | max_chunk_size = tmp; |
199 | } | |
200 | ||
3c0edcdc AC |
201 | print_string (" core: "); |
202 | print_byte_count (max_core_size); | |
203 | print_string ("\n"); | |
204 | print_string (" chunk: "); | |
205 | print_byte_count (max_chunk_size); | |
206 | print_string ("\n"); | |
207 | print_string (" large? "); | |
208 | if (O_LARGEFILE) | |
209 | print_string ("yes\n"); | |
210 | else | |
211 | print_string ("no\n"); | |
212 | ||
2d822687 AC |
213 | /* Allocate as much memory as possible creating a linked list of |
214 | each section. The linking ensures that some, but not all, the | |
215 | memory is allocated. NB: Some kernels handle this efficiently - | |
216 | only allocating and writing out referenced pages leaving holes in | |
bf08c2a1 DJ |
217 | the file for unmodified pages - while others handle this poorly - |
218 | writing out all pages including those that weren't modified. */ | |
2d822687 AC |
219 | |
220 | print_string ("Alocating the entire heap ...\n"); | |
221 | { | |
222 | size_t chunk_size; | |
bf08c2a1 | 223 | unsigned long chunks_allocated = 0; |
2d822687 AC |
224 | /* Create a linked list of memory chunks. Start with |
225 | MAX_CHUNK_SIZE blocks of memory and then try allocating smaller | |
226 | and smaller amounts until all (well at least most) memory has | |
227 | been allocated. */ | |
228 | for (chunk_size = max_chunk_size; | |
229 | chunk_size >= sizeof (struct list); | |
230 | chunk_size >>= 1) | |
231 | { | |
232 | unsigned long count = 0; | |
233 | print_string (" "); | |
3c0edcdc AC |
234 | print_byte_count (chunk_size); |
235 | print_string (" ... "); | |
236 | while (bytes_allocated + (1 + count) * chunk_size | |
237 | < max_core_size) | |
2d822687 AC |
238 | { |
239 | struct list *chunk = malloc (chunk_size); | |
240 | if (chunk == NULL) | |
241 | break; | |
242 | chunk->size = chunk_size; | |
243 | /* Link it in. */ | |
244 | chunk->next = NULL; | |
245 | chunk->prev = heap.prev; | |
246 | heap.prev->next = chunk; | |
247 | heap.prev = chunk; | |
248 | count++; | |
249 | } | |
250 | print_unsigned (count); | |
251 | print_string (" chunks\n"); | |
252 | chunks_allocated += count; | |
253 | bytes_allocated += chunk_size * count; | |
254 | } | |
255 | print_string ("Total of "); | |
3c0edcdc | 256 | print_byte_count (bytes_allocated); |
2d822687 AC |
257 | print_string (" bytes "); |
258 | print_unsigned (chunks_allocated); | |
259 | print_string (" chunks\n"); | |
260 | } | |
261 | ||
262 | /* Push everything out to disk. */ | |
263 | ||
264 | print_string ("Dump core ....\n"); | |
265 | *(char*)0 = 0; | |
266 | } |