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