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