Print this page
3946 ::gcore
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libproc/common/Pgcore.c
+++ new/usr/src/lib/libproc/common/Pgcore.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26 /*
27 27 * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
28 28 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
29 + * Copyright (c) 2013 by Delphix. All rights reserved.
29 30 */
30 31
31 32 #define _STRUCTURED_PROC 1
32 33
33 34 #include <stdlib.h>
34 35 #include <ctype.h>
35 36 #include <string.h>
36 37 #include <strings.h>
37 38 #include <errno.h>
38 39 #include <procfs.h>
39 40 #include <priv.h>
40 41 #include <sys/elf.h>
41 42 #include <sys/machelf.h>
42 43 #include <sys/sysmacros.h>
43 44 #include <sys/systeminfo.h>
44 45 #include <sys/proc.h>
45 46 #include <sys/utsname.h>
46 47
47 48 #include <sys/old_procfs.h>
48 49
49 50 #include "Pcontrol.h"
50 51 #include "P32ton.h"
51 52
52 53 typedef enum {
53 54 STR_NONE,
54 55 STR_CTF,
55 56 STR_SYMTAB,
56 57 STR_DYNSYM,
57 58 STR_STRTAB,
58 59 STR_DYNSTR,
59 60 STR_SHSTRTAB,
60 61 STR_NUM
61 62 } shstrtype_t;
62 63
63 64 static const char *shstrtab_data[] = {
64 65 "",
65 66 ".SUNW_ctf",
66 67 ".symtab",
67 68 ".dynsym",
68 69 ".strtab",
69 70 ".dynstr",
70 71 ".shstrtab"
71 72 };
72 73
73 74 typedef struct shstrtab {
74 75 int sst_ndx[STR_NUM];
75 76 int sst_cur;
76 77 } shstrtab_t;
77 78
78 79 typedef struct {
79 80 struct ps_prochandle *P;
80 81 int pgc_fd;
81 82 off64_t *pgc_poff;
82 83 off64_t *pgc_soff;
83 84 off64_t *pgc_doff;
84 85 core_content_t pgc_content;
85 86 void *pgc_chunk;
86 87 size_t pgc_chunksz;
87 88
88 89 shstrtab_t pgc_shstrtab;
89 90 } pgcore_t;
90 91
91 92 typedef struct {
92 93 int fd_fd;
93 94 off64_t *fd_doff;
94 95 } fditer_t;
95 96
96 97 static void
97 98 shstrtab_init(shstrtab_t *s)
98 99 {
99 100 bzero(&s->sst_ndx, sizeof (s->sst_ndx));
100 101 s->sst_cur = 1;
101 102 }
102 103
103 104 static int
104 105 shstrtab_ndx(shstrtab_t *s, shstrtype_t type)
105 106 {
106 107 int ret;
107 108
108 109 if ((ret = s->sst_ndx[type]) != 0 || type == STR_NONE)
109 110 return (ret);
110 111
111 112 ret = s->sst_ndx[type] = s->sst_cur;
112 113 s->sst_cur += strlen(shstrtab_data[type]) + 1;
113 114
114 115 return (ret);
115 116 }
116 117
117 118 static size_t
118 119 shstrtab_size(const shstrtab_t *s)
119 120 {
120 121 return (s->sst_cur);
121 122 }
122 123
123 124 int
124 125 Pgcore(struct ps_prochandle *P, const char *fname, core_content_t content)
125 126 {
126 127 int fd;
127 128 int err;
128 129
129 130 if ((fd = creat64(fname, 0666)) < 0)
130 131 return (-1);
131 132
132 133 if ((err = Pfgcore(P, fd, content)) != 0) {
133 134 (void) close(fd);
134 135 (void) unlink(fname);
135 136 return (err);
136 137 }
137 138
138 139 return (close(fd));
139 140 }
140 141
141 142 /*
142 143 * Since we don't want to use the old-school procfs interfaces, we use the
143 144 * new-style data structures we already have to construct the old-style
144 145 * data structures. We include these data structures in core files for
145 146 * backward compatability.
146 147 */
147 148
148 149 static void
149 150 mkprstatus(struct ps_prochandle *P, const lwpstatus_t *lsp,
150 151 const lwpsinfo_t *lip, prstatus_t *psp)
151 152 {
152 153 bzero(psp, sizeof (*psp));
153 154
154 155 if (lsp->pr_flags & PR_STOPPED)
155 156 psp->pr_flags = 0x0001;
156 157 if (lsp->pr_flags & PR_ISTOP)
157 158 psp->pr_flags = 0x0002;
158 159 if (lsp->pr_flags & PR_DSTOP)
159 160 psp->pr_flags = 0x0004;
160 161 if (lsp->pr_flags & PR_ASLEEP)
161 162 psp->pr_flags = 0x0008;
162 163 if (lsp->pr_flags & PR_FORK)
163 164 psp->pr_flags = 0x0010;
164 165 if (lsp->pr_flags & PR_RLC)
165 166 psp->pr_flags = 0x0020;
166 167 /*
167 168 * Note that PR_PTRACE (0x0040) from <sys/old_procfs.h> is never set;
168 169 * PR_PCOMPAT corresponds to PR_PTRACE in the newer <sys/procfs.h>.
169 170 */
170 171 if (lsp->pr_flags & PR_PCINVAL)
171 172 psp->pr_flags = 0x0080;
172 173 if (lsp->pr_flags & PR_ISSYS)
173 174 psp->pr_flags = 0x0100;
174 175 if (lsp->pr_flags & PR_STEP)
175 176 psp->pr_flags = 0x0200;
176 177 if (lsp->pr_flags & PR_KLC)
177 178 psp->pr_flags = 0x0400;
178 179 if (lsp->pr_flags & PR_ASYNC)
179 180 psp->pr_flags = 0x0800;
180 181 if (lsp->pr_flags & PR_PTRACE)
181 182 psp->pr_flags = 0x1000;
182 183 if (lsp->pr_flags & PR_MSACCT)
183 184 psp->pr_flags = 0x2000;
184 185 if (lsp->pr_flags & PR_BPTADJ)
185 186 psp->pr_flags = 0x4000;
186 187 if (lsp->pr_flags & PR_ASLWP)
187 188 psp->pr_flags = 0x8000;
188 189
189 190 psp->pr_why = lsp->pr_why;
190 191 psp->pr_what = lsp->pr_what;
191 192 psp->pr_info = lsp->pr_info;
192 193 psp->pr_cursig = lsp->pr_cursig;
193 194 psp->pr_nlwp = P->status.pr_nlwp;
194 195 psp->pr_sigpend = P->status.pr_sigpend;
195 196 psp->pr_sighold = lsp->pr_lwphold;
196 197 psp->pr_altstack = lsp->pr_altstack;
197 198 psp->pr_action = lsp->pr_action;
198 199 psp->pr_pid = P->status.pr_pid;
199 200 psp->pr_ppid = P->status.pr_ppid;
200 201 psp->pr_pgrp = P->status.pr_pgid;
201 202 psp->pr_sid = P->status.pr_sid;
202 203 psp->pr_utime = P->status.pr_utime;
203 204 psp->pr_stime = P->status.pr_stime;
204 205 psp->pr_cutime = P->status.pr_cutime;
205 206 psp->pr_cstime = P->status.pr_cstime;
206 207 (void) strncpy(psp->pr_clname, lsp->pr_clname, sizeof (psp->pr_clname));
207 208 psp->pr_syscall = lsp->pr_syscall;
208 209 psp->pr_nsysarg = lsp->pr_nsysarg;
209 210 bcopy(lsp->pr_sysarg, psp->pr_sysarg, sizeof (psp->pr_sysarg));
210 211 psp->pr_who = lsp->pr_lwpid;
211 212 psp->pr_lwppend = lsp->pr_lwppend;
212 213 psp->pr_oldcontext = (ucontext_t *)lsp->pr_oldcontext;
213 214 psp->pr_brkbase = (caddr_t)P->status.pr_brkbase;
214 215 psp->pr_brksize = P->status.pr_brksize;
215 216 psp->pr_stkbase = (caddr_t)P->status.pr_stkbase;
216 217 psp->pr_stksize = P->status.pr_stksize;
217 218 psp->pr_processor = (short)lip->pr_onpro;
218 219 psp->pr_bind = (short)lip->pr_bindpro;
219 220 psp->pr_instr = lsp->pr_instr;
220 221 bcopy(lsp->pr_reg, psp->pr_reg, sizeof (psp->pr_sysarg));
221 222 }
222 223
223 224 static void
224 225 mkprpsinfo(struct ps_prochandle *P, prpsinfo_t *psp)
225 226 {
226 227 bzero(psp, sizeof (*psp));
227 228 psp->pr_state = P->psinfo.pr_lwp.pr_state;
228 229 psp->pr_sname = P->psinfo.pr_lwp.pr_sname;
229 230 psp->pr_zomb = (psp->pr_state == SZOMB);
230 231 psp->pr_nice = P->psinfo.pr_lwp.pr_nice;
231 232 psp->pr_flag = P->psinfo.pr_lwp.pr_flag;
232 233 psp->pr_uid = P->psinfo.pr_uid;
233 234 psp->pr_gid = P->psinfo.pr_gid;
234 235 psp->pr_pid = P->psinfo.pr_pid;
235 236 psp->pr_ppid = P->psinfo.pr_ppid;
236 237 psp->pr_pgrp = P->psinfo.pr_pgid;
237 238 psp->pr_sid = P->psinfo.pr_sid;
238 239 psp->pr_addr = (caddr_t)P->psinfo.pr_addr;
239 240 psp->pr_size = P->psinfo.pr_size;
240 241 psp->pr_rssize = P->psinfo.pr_rssize;
241 242 psp->pr_wchan = (caddr_t)P->psinfo.pr_lwp.pr_wchan;
242 243 psp->pr_start = P->psinfo.pr_start;
243 244 psp->pr_time = P->psinfo.pr_time;
244 245 psp->pr_pri = P->psinfo.pr_lwp.pr_pri;
245 246 psp->pr_oldpri = P->psinfo.pr_lwp.pr_oldpri;
246 247 psp->pr_cpu = P->psinfo.pr_lwp.pr_cpu;
247 248 psp->pr_ottydev = cmpdev(P->psinfo.pr_ttydev);
248 249 psp->pr_lttydev = P->psinfo.pr_ttydev;
249 250 (void) strncpy(psp->pr_clname, P->psinfo.pr_lwp.pr_clname,
250 251 sizeof (psp->pr_clname));
251 252 (void) strncpy(psp->pr_fname, P->psinfo.pr_fname,
252 253 sizeof (psp->pr_fname));
253 254 bcopy(&P->psinfo.pr_psargs, &psp->pr_psargs,
254 255 sizeof (psp->pr_psargs));
255 256 psp->pr_syscall = P->psinfo.pr_lwp.pr_syscall;
256 257 psp->pr_ctime = P->psinfo.pr_ctime;
257 258 psp->pr_bysize = psp->pr_size * PAGESIZE;
258 259 psp->pr_byrssize = psp->pr_rssize * PAGESIZE;
259 260 psp->pr_argc = P->psinfo.pr_argc;
260 261 psp->pr_argv = (char **)P->psinfo.pr_argv;
261 262 psp->pr_envp = (char **)P->psinfo.pr_envp;
262 263 psp->pr_wstat = P->psinfo.pr_wstat;
263 264 psp->pr_pctcpu = P->psinfo.pr_pctcpu;
264 265 psp->pr_pctmem = P->psinfo.pr_pctmem;
265 266 psp->pr_euid = P->psinfo.pr_euid;
266 267 psp->pr_egid = P->psinfo.pr_egid;
267 268 psp->pr_aslwpid = 0;
268 269 psp->pr_dmodel = P->psinfo.pr_dmodel;
269 270 }
270 271
271 272 #ifdef _LP64
272 273
273 274 static void
274 275 mkprstatus32(struct ps_prochandle *P, const lwpstatus_t *lsp,
275 276 const lwpsinfo_t *lip, prstatus32_t *psp)
276 277 {
277 278 bzero(psp, sizeof (*psp));
278 279
279 280 if (lsp->pr_flags & PR_STOPPED)
280 281 psp->pr_flags = 0x0001;
281 282 if (lsp->pr_flags & PR_ISTOP)
282 283 psp->pr_flags = 0x0002;
283 284 if (lsp->pr_flags & PR_DSTOP)
284 285 psp->pr_flags = 0x0004;
285 286 if (lsp->pr_flags & PR_ASLEEP)
286 287 psp->pr_flags = 0x0008;
287 288 if (lsp->pr_flags & PR_FORK)
288 289 psp->pr_flags = 0x0010;
289 290 if (lsp->pr_flags & PR_RLC)
290 291 psp->pr_flags = 0x0020;
291 292 /*
292 293 * Note that PR_PTRACE (0x0040) from <sys/old_procfs.h> is never set;
293 294 * PR_PCOMPAT corresponds to PR_PTRACE in the newer <sys/procfs.h>.
294 295 */
295 296 if (lsp->pr_flags & PR_PCINVAL)
296 297 psp->pr_flags = 0x0080;
297 298 if (lsp->pr_flags & PR_ISSYS)
298 299 psp->pr_flags = 0x0100;
299 300 if (lsp->pr_flags & PR_STEP)
300 301 psp->pr_flags = 0x0200;
301 302 if (lsp->pr_flags & PR_KLC)
302 303 psp->pr_flags = 0x0400;
303 304 if (lsp->pr_flags & PR_ASYNC)
304 305 psp->pr_flags = 0x0800;
305 306 if (lsp->pr_flags & PR_PTRACE)
306 307 psp->pr_flags = 0x1000;
307 308 if (lsp->pr_flags & PR_MSACCT)
308 309 psp->pr_flags = 0x2000;
309 310 if (lsp->pr_flags & PR_BPTADJ)
310 311 psp->pr_flags = 0x4000;
311 312 if (lsp->pr_flags & PR_ASLWP)
312 313 psp->pr_flags = 0x8000;
313 314
314 315 psp->pr_why = lsp->pr_why;
315 316 psp->pr_what = lsp->pr_what;
316 317 siginfo_n_to_32(&lsp->pr_info, &psp->pr_info);
317 318 psp->pr_cursig = lsp->pr_cursig;
318 319 psp->pr_nlwp = P->status.pr_nlwp;
319 320 psp->pr_sigpend = P->status.pr_sigpend;
320 321 psp->pr_sighold = lsp->pr_lwphold;
321 322 stack_n_to_32(&lsp->pr_altstack, &psp->pr_altstack);
322 323 sigaction_n_to_32(&lsp->pr_action, &psp->pr_action);
323 324 psp->pr_pid = P->status.pr_pid;
324 325 psp->pr_ppid = P->status.pr_ppid;
325 326 psp->pr_pgrp = P->status.pr_pgid;
326 327 psp->pr_sid = P->status.pr_sid;
327 328 timestruc_n_to_32(&P->status.pr_utime, &psp->pr_utime);
328 329 timestruc_n_to_32(&P->status.pr_stime, &psp->pr_stime);
329 330 timestruc_n_to_32(&P->status.pr_cutime, &psp->pr_cutime);
330 331 timestruc_n_to_32(&P->status.pr_cstime, &psp->pr_cstime);
331 332 (void) strncpy(psp->pr_clname, lsp->pr_clname, sizeof (psp->pr_clname));
332 333 psp->pr_syscall = lsp->pr_syscall;
333 334 psp->pr_nsysarg = lsp->pr_nsysarg;
334 335 bcopy(lsp->pr_sysarg, psp->pr_sysarg, sizeof (psp->pr_sysarg));
335 336 psp->pr_who = lsp->pr_lwpid;
336 337 psp->pr_lwppend = lsp->pr_lwppend;
337 338 psp->pr_oldcontext = (caddr32_t)lsp->pr_oldcontext;
338 339 psp->pr_brkbase = (caddr32_t)P->status.pr_brkbase;
339 340 psp->pr_brksize = P->status.pr_brksize;
340 341 psp->pr_stkbase = (caddr32_t)P->status.pr_stkbase;
341 342 psp->pr_stksize = P->status.pr_stksize;
342 343 psp->pr_processor = (short)lip->pr_onpro;
343 344 psp->pr_bind = (short)lip->pr_bindpro;
344 345 psp->pr_instr = lsp->pr_instr;
345 346 bcopy(lsp->pr_reg, psp->pr_reg, sizeof (psp->pr_sysarg));
346 347 }
347 348
348 349 static void
349 350 mkprpsinfo32(struct ps_prochandle *P, prpsinfo32_t *psp)
350 351 {
351 352 bzero(psp, sizeof (*psp));
352 353 psp->pr_state = P->psinfo.pr_lwp.pr_state;
353 354 psp->pr_sname = P->psinfo.pr_lwp.pr_sname;
354 355 psp->pr_zomb = (psp->pr_state == SZOMB);
355 356 psp->pr_nice = P->psinfo.pr_lwp.pr_nice;
356 357 psp->pr_flag = P->psinfo.pr_lwp.pr_flag;
357 358 psp->pr_uid = P->psinfo.pr_uid;
358 359 psp->pr_gid = P->psinfo.pr_gid;
359 360 psp->pr_pid = P->psinfo.pr_pid;
360 361 psp->pr_ppid = P->psinfo.pr_ppid;
361 362 psp->pr_pgrp = P->psinfo.pr_pgid;
362 363 psp->pr_sid = P->psinfo.pr_sid;
363 364 psp->pr_addr = (caddr32_t)P->psinfo.pr_addr;
364 365 psp->pr_size = P->psinfo.pr_size;
365 366 psp->pr_rssize = P->psinfo.pr_rssize;
366 367 psp->pr_wchan = (caddr32_t)P->psinfo.pr_lwp.pr_wchan;
367 368 timestruc_n_to_32(&P->psinfo.pr_start, &psp->pr_start);
368 369 timestruc_n_to_32(&P->psinfo.pr_time, &psp->pr_time);
369 370 psp->pr_pri = P->psinfo.pr_lwp.pr_pri;
370 371 psp->pr_oldpri = P->psinfo.pr_lwp.pr_oldpri;
371 372 psp->pr_cpu = P->psinfo.pr_lwp.pr_cpu;
372 373 psp->pr_ottydev = cmpdev(P->psinfo.pr_ttydev);
373 374 psp->pr_lttydev = prcmpldev(P->psinfo.pr_ttydev);
374 375 (void) strncpy(psp->pr_clname, P->psinfo.pr_lwp.pr_clname,
375 376 sizeof (psp->pr_clname));
376 377 (void) strncpy(psp->pr_fname, P->psinfo.pr_fname,
377 378 sizeof (psp->pr_fname));
378 379 bcopy(&P->psinfo.pr_psargs, &psp->pr_psargs,
379 380 sizeof (psp->pr_psargs));
380 381 psp->pr_syscall = P->psinfo.pr_lwp.pr_syscall;
381 382 timestruc_n_to_32(&P->psinfo.pr_ctime, &psp->pr_ctime);
382 383 psp->pr_bysize = psp->pr_size * PAGESIZE;
383 384 psp->pr_byrssize = psp->pr_rssize * PAGESIZE;
384 385 psp->pr_argc = P->psinfo.pr_argc;
385 386 psp->pr_argv = (caddr32_t)P->psinfo.pr_argv;
386 387 psp->pr_envp = (caddr32_t)P->psinfo.pr_envp;
387 388 psp->pr_wstat = P->psinfo.pr_wstat;
388 389 psp->pr_pctcpu = P->psinfo.pr_pctcpu;
389 390 psp->pr_pctmem = P->psinfo.pr_pctmem;
390 391 psp->pr_euid = P->psinfo.pr_euid;
391 392 psp->pr_egid = P->psinfo.pr_egid;
392 393 psp->pr_aslwpid = 0;
393 394 psp->pr_dmodel = P->psinfo.pr_dmodel;
394 395 }
395 396
396 397 #endif /* _LP64 */
397 398
398 399 static int
399 400 write_note(int fd, uint_t type, const void *desc, size_t descsz, off64_t *offp)
400 401 {
401 402 /*
402 403 * Note headers are the same regardless of the data model of the
403 404 * ELF file; we arbitrarily use Elf64_Nhdr here.
404 405 */
405 406 struct {
406 407 Elf64_Nhdr nhdr;
407 408 char name[8];
408 409 } n;
409 410
410 411 bzero(&n, sizeof (n));
411 412 bcopy("CORE", n.name, 4);
412 413 n.nhdr.n_type = type;
413 414 n.nhdr.n_namesz = 5;
414 415 n.nhdr.n_descsz = roundup(descsz, 4);
415 416
416 417 if (pwrite64(fd, &n, sizeof (n), *offp) != sizeof (n))
417 418 return (-1);
418 419
419 420 *offp += sizeof (n);
420 421
421 422 if (pwrite64(fd, desc, n.nhdr.n_descsz, *offp) != n.nhdr.n_descsz)
422 423 return (-1);
423 424
424 425 *offp += n.nhdr.n_descsz;
425 426
426 427 return (0);
427 428 }
428 429
429 430 static int
430 431 old_per_lwp(void *data, const lwpstatus_t *lsp, const lwpsinfo_t *lip)
431 432 {
432 433 pgcore_t *pgc = data;
433 434 struct ps_prochandle *P = pgc->P;
434 435
435 436 /*
436 437 * Legacy core files don't contain information about zombie LWPs.
437 438 * We use Plwp_iter_all() so that we get the lwpsinfo_t structure
438 439 * more cheaply.
439 440 */
440 441 if (lsp == NULL)
441 442 return (0);
442 443
443 444 if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
444 445 prstatus_t prstatus;
445 446 mkprstatus(P, lsp, lip, &prstatus);
446 447 if (write_note(pgc->pgc_fd, NT_PRSTATUS, &prstatus,
447 448 sizeof (prstatus_t), pgc->pgc_doff) != 0)
448 449 return (0);
449 450 if (write_note(pgc->pgc_fd, NT_PRFPREG, &lsp->pr_fpreg,
450 451 sizeof (prfpregset_t), pgc->pgc_doff) != 0)
451 452 return (1);
452 453 #ifdef _LP64
453 454 } else {
454 455 prstatus32_t pr32;
455 456 prfpregset32_t pf32;
456 457 mkprstatus32(P, lsp, lip, &pr32);
457 458 if (write_note(pgc->pgc_fd, NT_PRSTATUS, &pr32,
458 459 sizeof (prstatus32_t), pgc->pgc_doff) != 0)
459 460 return (1);
460 461 prfpregset_n_to_32(&lsp->pr_fpreg, &pf32);
461 462 if (write_note(pgc->pgc_fd, NT_PRFPREG, &pf32,
462 463 sizeof (prfpregset32_t), pgc->pgc_doff) != 0)
463 464 return (1);
464 465 #endif /* _LP64 */
465 466 }
466 467
467 468 #ifdef sparc
468 469 {
469 470 prxregset_t xregs;
470 471 if (Plwp_getxregs(P, lsp->pr_lwpid, &xregs) == 0 &&
471 472 write_note(pgc->pgc_fd, NT_PRXREG, &xregs,
472 473 sizeof (prxregset_t), pgc->pgc_doff) != 0)
473 474 return (1);
474 475 }
475 476 #endif /* sparc */
476 477
477 478 return (0);
478 479 }
479 480
480 481 static int
481 482 new_per_lwp(void *data, const lwpstatus_t *lsp, const lwpsinfo_t *lip)
482 483 {
483 484 pgcore_t *pgc = data;
484 485 struct ps_prochandle *P = pgc->P;
485 486 psinfo_t ps;
486 487
487 488 /*
488 489 * If lsp is NULL this indicates that this is a zombie LWP in
489 490 * which case we dump only the lwpsinfo_t structure and none of
490 491 * the other ancillary LWP state data.
491 492 */
492 493 if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
493 494 if (write_note(pgc->pgc_fd, NT_LWPSINFO, lip,
494 495 sizeof (lwpsinfo_t), pgc->pgc_doff) != 0)
495 496 return (1);
496 497 if (lsp == NULL)
497 498 return (0);
498 499 if (write_note(pgc->pgc_fd, NT_LWPSTATUS, lsp,
499 500 sizeof (lwpstatus_t), pgc->pgc_doff) != 0)
500 501 return (1);
501 502 #ifdef _LP64
502 503 } else {
503 504 lwpsinfo32_t li32;
504 505 lwpstatus32_t ls32;
505 506 lwpsinfo_n_to_32(lip, &li32);
506 507 if (write_note(pgc->pgc_fd, NT_LWPSINFO, &li32,
507 508 sizeof (lwpsinfo32_t), pgc->pgc_doff) != 0)
508 509 return (1);
509 510 if (lsp == NULL)
510 511 return (0);
511 512 lwpstatus_n_to_32(lsp, &ls32);
512 513 if (write_note(pgc->pgc_fd, NT_LWPSTATUS, &ls32,
513 514 sizeof (lwpstatus32_t), pgc->pgc_doff) != 0)
514 515 return (1);
515 516 #endif /* _LP64 */
516 517 }
517 518
518 519 #ifdef sparc
519 520 {
520 521 prxregset_t xregs;
521 522 gwindows_t gwins;
522 523 size_t size;
523 524
524 525 if (Plwp_getxregs(P, lsp->pr_lwpid, &xregs) == 0) {
525 526 if (write_note(pgc->pgc_fd, NT_PRXREG, &xregs,
526 527 sizeof (prxregset_t), pgc->pgc_doff) != 0)
527 528 return (1);
528 529 }
529 530
530 531 if (Plwp_getgwindows(P, lsp->pr_lwpid, &gwins) == 0 &&
531 532 gwins.wbcnt > 0) {
532 533 size = sizeof (gwins) - sizeof (gwins.wbuf) +
533 534 gwins.wbcnt * sizeof (gwins.wbuf[0]);
534 535
535 536 if (write_note(pgc->pgc_fd, NT_GWINDOWS, &gwins, size,
536 537 pgc->pgc_doff) != 0)
537 538 return (1);
538 539 }
539 540
540 541 }
541 542 #ifdef __sparcv9
542 543 if (P->status.pr_dmodel == PR_MODEL_LP64) {
543 544 asrset_t asrs;
544 545 if (Plwp_getasrs(P, lsp->pr_lwpid, asrs) == 0) {
545 546 if (write_note(pgc->pgc_fd, NT_ASRS, &asrs,
546 547 sizeof (asrset_t), pgc->pgc_doff) != 0)
547 548 return (1);
548 549 }
549 550 }
550 551 #endif /* __sparcv9 */
551 552 #endif /* sparc */
552 553
553 554 if (!(lsp->pr_flags & PR_AGENT))
554 555 return (0);
555 556
556 557 if (Plwp_getspymaster(P, lsp->pr_lwpid, &ps) != 0)
557 558 return (0);
558 559
559 560 if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
560 561 if (write_note(pgc->pgc_fd, NT_SPYMASTER, &ps,
561 562 sizeof (psinfo_t), pgc->pgc_doff) != 0)
562 563 return (1);
563 564 #ifdef _LP64
564 565 } else {
565 566 psinfo32_t ps32;
566 567 psinfo_n_to_32(&ps, &ps32);
567 568 if (write_note(pgc->pgc_fd, NT_SPYMASTER, &ps32,
568 569 sizeof (psinfo32_t), pgc->pgc_doff) != 0)
569 570 return (1);
570 571 #endif /* _LP64 */
571 572 }
572 573
573 574
574 575 return (0);
575 576 }
576 577
577 578 static int
578 579 iter_fd(void *data, prfdinfo_t *fdinfo)
579 580 {
580 581 fditer_t *iter = data;
581 582
582 583 if (write_note(iter->fd_fd, NT_FDINFO, fdinfo,
583 584 sizeof (*fdinfo), iter->fd_doff) != 0)
584 585 return (1);
585 586 return (0);
586 587 }
587 588
588 589 static uint_t
589 590 count_sections(pgcore_t *pgc)
590 591 {
591 592 struct ps_prochandle *P = pgc->P;
592 593 file_info_t *fptr;
593 594 uint_t cnt;
594 595 uint_t nshdrs = 0;
595 596
596 597 if (!(pgc->pgc_content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)))
597 598 return (0);
598 599
599 600 fptr = list_next(&P->file_head);
600 601 for (cnt = P->num_files; cnt > 0; cnt--, fptr = list_next(fptr)) {
601 602 int hit_symtab = 0;
602 603
603 604 Pbuild_file_symtab(P, fptr);
604 605
605 606 if ((pgc->pgc_content & CC_CONTENT_CTF) &&
606 607 Pbuild_file_ctf(P, fptr) != NULL) {
607 608 sym_tbl_t *sym;
608 609
609 610 nshdrs++;
610 611
611 612 if (fptr->file_ctf_dyn) {
612 613 sym = &fptr->file_dynsym;
613 614 } else {
614 615 sym = &fptr->file_symtab;
615 616 hit_symtab = 1;
616 617 }
617 618
618 619 if (sym->sym_data_pri != NULL && sym->sym_symn != 0 &&
619 620 sym->sym_strs != NULL)
620 621 nshdrs += 2;
621 622 }
622 623
623 624 if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab &&
624 625 fptr->file_symtab.sym_data_pri != NULL &&
625 626 fptr->file_symtab.sym_symn != 0 &&
626 627 fptr->file_symtab.sym_strs != NULL) {
627 628 nshdrs += 2;
628 629 }
629 630 }
630 631
631 632 return (nshdrs == 0 ? 0 : nshdrs + 2);
632 633 }
633 634
634 635 static int
635 636 write_shdr(pgcore_t *pgc, shstrtype_t name, uint_t type, ulong_t flags,
636 637 uintptr_t addr, ulong_t offset, size_t size, uint_t link, uint_t info,
637 638 uintptr_t addralign, uintptr_t entsize)
638 639 {
639 640 if (pgc->P->status.pr_dmodel == PR_MODEL_ILP32) {
640 641 Elf32_Shdr shdr;
641 642
642 643 bzero(&shdr, sizeof (shdr));
643 644 shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, name);
644 645 shdr.sh_type = type;
645 646 shdr.sh_flags = flags;
646 647 shdr.sh_addr = (Elf32_Addr)addr;
647 648 shdr.sh_offset = offset;
648 649 shdr.sh_size = size;
649 650 shdr.sh_link = link;
650 651 shdr.sh_info = info;
651 652 shdr.sh_addralign = addralign;
652 653 shdr.sh_entsize = entsize;
653 654
654 655 if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
655 656 *pgc->pgc_soff) != sizeof (shdr))
656 657 return (-1);
657 658
658 659 *pgc->pgc_soff += sizeof (shdr);
659 660 #ifdef _LP64
660 661 } else {
661 662 Elf64_Shdr shdr;
662 663
663 664 bzero(&shdr, sizeof (shdr));
664 665 shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, name);
665 666 shdr.sh_type = type;
666 667 shdr.sh_flags = flags;
667 668 shdr.sh_addr = addr;
668 669 shdr.sh_offset = offset;
669 670 shdr.sh_size = size;
670 671 shdr.sh_link = link;
671 672 shdr.sh_info = info;
672 673 shdr.sh_addralign = addralign;
673 674 shdr.sh_entsize = entsize;
674 675
675 676 if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
676 677 *pgc->pgc_soff) != sizeof (shdr))
677 678 return (-1);
678 679
679 680 *pgc->pgc_soff += sizeof (shdr);
680 681 #endif /* _LP64 */
681 682 }
682 683
683 684 return (0);
684 685 }
685 686
686 687 static int
687 688 dump_symtab(pgcore_t *pgc, file_info_t *fptr, uint_t index, int dynsym)
688 689 {
689 690 sym_tbl_t *sym = dynsym ? &fptr->file_dynsym : &fptr->file_symtab;
690 691 shstrtype_t symname = dynsym ? STR_DYNSYM : STR_SYMTAB;
691 692 shstrtype_t strname = dynsym ? STR_DYNSTR : STR_STRTAB;
692 693 uint_t symtype = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
693 694 size_t size;
694 695 uintptr_t addr = fptr->file_map->map_pmap.pr_vaddr;
695 696
696 697 if (sym->sym_data_pri == NULL || sym->sym_symn == 0 ||
697 698 sym->sym_strs == NULL)
698 699 return (0);
699 700
700 701 size = sym->sym_hdr_pri.sh_size;
701 702 if (pwrite64(pgc->pgc_fd, sym->sym_data_pri->d_buf, size,
702 703 *pgc->pgc_doff) != size)
703 704 return (-1);
704 705
705 706 if (write_shdr(pgc, symname, symtype, 0, addr, *pgc->pgc_doff, size,
706 707 index + 1, sym->sym_hdr_pri.sh_info, sym->sym_hdr_pri.sh_addralign,
707 708 sym->sym_hdr_pri.sh_entsize) != 0)
708 709 return (-1);
709 710
710 711 *pgc->pgc_doff += roundup(size, 8);
711 712
712 713 size = sym->sym_strhdr.sh_size;
713 714 if (pwrite64(pgc->pgc_fd, sym->sym_strs, size, *pgc->pgc_doff) != size)
714 715 return (-1);
715 716
716 717 if (write_shdr(pgc, strname, SHT_STRTAB, SHF_STRINGS, addr,
717 718 *pgc->pgc_doff, size, 0, 0, 1, 0) != 0)
718 719 return (-1);
719 720
720 721 *pgc->pgc_doff += roundup(size, 8);
721 722
722 723 return (0);
723 724 }
724 725
725 726 static int
726 727 dump_sections(pgcore_t *pgc)
727 728 {
728 729 struct ps_prochandle *P = pgc->P;
729 730 file_info_t *fptr;
730 731 uint_t cnt;
731 732 uint_t index = 1;
732 733
733 734 if (!(pgc->pgc_content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)))
734 735 return (0);
735 736
736 737 fptr = list_next(&P->file_head);
737 738 for (cnt = P->num_files; cnt > 0; cnt--, fptr = list_next(fptr)) {
738 739 int hit_symtab = 0;
739 740
740 741 Pbuild_file_symtab(P, fptr);
741 742
742 743 if ((pgc->pgc_content & CC_CONTENT_CTF) &&
743 744 Pbuild_file_ctf(P, fptr) != NULL) {
744 745 sym_tbl_t *sym;
745 746 uint_t dynsym;
746 747 uint_t symindex = 0;
747 748
748 749 /*
749 750 * Write the symtab out first so we can correctly
750 751 * set the sh_link field in the CTF section header.
751 752 * symindex will be 0 if there is no corresponding
752 753 * symbol table section.
753 754 */
754 755 if (fptr->file_ctf_dyn) {
755 756 sym = &fptr->file_dynsym;
756 757 dynsym = 1;
757 758 } else {
758 759 sym = &fptr->file_symtab;
759 760 dynsym = 0;
760 761 hit_symtab = 1;
761 762 }
762 763
763 764 if (sym->sym_data_pri != NULL && sym->sym_symn != 0 &&
764 765 sym->sym_strs != NULL) {
765 766 symindex = index;
766 767 if (dump_symtab(pgc, fptr, index, dynsym) != 0)
767 768 return (-1);
768 769 index += 2;
769 770 }
770 771
771 772 /*
772 773 * Write the CTF data that we've read out of the
773 774 * file itself into the core file.
774 775 */
775 776 if (pwrite64(pgc->pgc_fd, fptr->file_ctf_buf,
776 777 fptr->file_ctf_size, *pgc->pgc_doff) !=
777 778 fptr->file_ctf_size)
778 779 return (-1);
779 780
780 781 if (write_shdr(pgc, STR_CTF, SHT_PROGBITS, 0,
781 782 fptr->file_map->map_pmap.pr_vaddr, *pgc->pgc_doff,
782 783 fptr->file_ctf_size, symindex, 0, 4, 0) != 0)
783 784 return (-1);
784 785
785 786 index++;
786 787 *pgc->pgc_doff += roundup(fptr->file_ctf_size, 8);
787 788 }
788 789
789 790 if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab &&
790 791 fptr->file_symtab.sym_data_pri != NULL &&
791 792 fptr->file_symtab.sym_symn != 0 &&
792 793 fptr->file_symtab.sym_strs != NULL) {
793 794 if (dump_symtab(pgc, fptr, index, 0) != 0)
794 795 return (-1);
795 796 index += 2;
796 797 }
797 798 }
798 799
799 800 return (0);
800 801 }
801 802
802 803 /*ARGSUSED*/
803 804 static int
804 805 dump_map(void *data, const prmap_t *pmp, const char *name)
805 806 {
806 807 pgcore_t *pgc = data;
807 808 struct ps_prochandle *P = pgc->P;
808 809 #ifdef _LP64
809 810 Elf64_Phdr phdr;
810 811 #else
811 812 Elf32_Phdr phdr;
812 813 #endif
813 814 size_t n;
814 815
815 816 bzero(&phdr, sizeof (phdr));
816 817 phdr.p_type = PT_LOAD;
817 818 phdr.p_vaddr = pmp->pr_vaddr;
818 819 phdr.p_memsz = pmp->pr_size;
819 820 if (pmp->pr_mflags & MA_READ)
820 821 phdr.p_flags |= PF_R;
821 822 if (pmp->pr_mflags & MA_WRITE)
822 823 phdr.p_flags |= PF_W;
823 824 if (pmp->pr_mflags & MA_EXEC)
824 825 phdr.p_flags |= PF_X;
825 826
826 827 if (pmp->pr_vaddr + pmp->pr_size > P->status.pr_stkbase &&
827 828 pmp->pr_vaddr < P->status.pr_stkbase + P->status.pr_stksize) {
828 829 if (!(pgc->pgc_content & CC_CONTENT_STACK))
829 830 goto exclude;
830 831
831 832 } else if ((pmp->pr_mflags & MA_ANON) &&
832 833 pmp->pr_vaddr + pmp->pr_size > P->status.pr_brkbase &&
833 834 pmp->pr_vaddr < P->status.pr_brkbase + P->status.pr_brksize) {
834 835 if (!(pgc->pgc_content & CC_CONTENT_HEAP))
835 836 goto exclude;
836 837
837 838 } else if (pmp->pr_mflags & MA_ISM) {
838 839 if (pmp->pr_mflags & MA_NORESERVE) {
839 840 if (!(pgc->pgc_content & CC_CONTENT_DISM))
840 841 goto exclude;
841 842 } else {
842 843 if (!(pgc->pgc_content & CC_CONTENT_ISM))
843 844 goto exclude;
844 845 }
845 846
846 847 } else if (pmp->pr_mflags & MA_SHM) {
847 848 if (!(pgc->pgc_content & CC_CONTENT_SHM))
848 849 goto exclude;
849 850
850 851 } else if (pmp->pr_mflags & MA_SHARED) {
851 852 if (pmp->pr_mflags & MA_ANON) {
852 853 if (!(pgc->pgc_content & CC_CONTENT_SHANON))
853 854 goto exclude;
854 855 } else {
855 856 if (!(pgc->pgc_content & CC_CONTENT_SHFILE))
856 857 goto exclude;
857 858 }
858 859
859 860 } else if (pmp->pr_mflags & MA_ANON) {
860 861 if (!(pgc->pgc_content & CC_CONTENT_ANON))
861 862 goto exclude;
862 863
863 864 } else if (phdr.p_flags == (PF_R | PF_X)) {
864 865 if (!(pgc->pgc_content & CC_CONTENT_TEXT))
865 866 goto exclude;
866 867
867 868 } else if (phdr.p_flags == PF_R) {
868 869 if (!(pgc->pgc_content & CC_CONTENT_RODATA))
869 870 goto exclude;
870 871
871 872 } else {
872 873 if (!(pgc->pgc_content & CC_CONTENT_DATA))
873 874 goto exclude;
874 875 }
875 876
876 877 n = 0;
877 878 while (n < pmp->pr_size) {
878 879 size_t csz = MIN(pmp->pr_size - n, pgc->pgc_chunksz);
879 880
880 881 /*
881 882 * If we can't read out part of the victim's address
882 883 * space for some reason ignore that failure and try to
883 884 * emit a partial core file without that mapping's data.
884 885 * As in the kernel, we mark these failures with the
885 886 * PF_SUNW_FAILURE flag and store the errno where the
886 887 * mapping would have been.
887 888 */
888 889 if (Pread(P, pgc->pgc_chunk, csz, pmp->pr_vaddr + n) != csz ||
889 890 pwrite64(pgc->pgc_fd, pgc->pgc_chunk, csz,
890 891 *pgc->pgc_doff + n) != csz) {
891 892 int err = errno;
892 893 (void) pwrite64(pgc->pgc_fd, &err, sizeof (err),
893 894 *pgc->pgc_doff);
894 895 *pgc->pgc_doff += roundup(sizeof (err), 8);
895 896
896 897 phdr.p_flags |= PF_SUNW_FAILURE;
897 898 (void) ftruncate64(pgc->pgc_fd, *pgc->pgc_doff);
898 899 goto exclude;
899 900 }
900 901
901 902 n += csz;
902 903 }
903 904
904 905 phdr.p_offset = *pgc->pgc_doff;
905 906 phdr.p_filesz = pmp->pr_size;
906 907 *pgc->pgc_doff += roundup(phdr.p_filesz, 8);
907 908
908 909 exclude:
909 910 if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
910 911 if (pwrite64(pgc->pgc_fd, &phdr, sizeof (phdr),
911 912 *pgc->pgc_poff) != sizeof (phdr))
912 913 return (1);
913 914
914 915 *pgc->pgc_poff += sizeof (phdr);
915 916 #ifdef _LP64
916 917 } else {
917 918 Elf32_Phdr phdr32;
918 919
919 920 bzero(&phdr32, sizeof (phdr32));
920 921 phdr32.p_type = phdr.p_type;
921 922 phdr32.p_vaddr = (Elf32_Addr)phdr.p_vaddr;
922 923 phdr32.p_memsz = (Elf32_Word)phdr.p_memsz;
923 924 phdr32.p_flags = phdr.p_flags;
924 925 phdr32.p_offset = (Elf32_Off)phdr.p_offset;
925 926 phdr32.p_filesz = (Elf32_Word)phdr.p_filesz;
926 927
927 928 if (pwrite64(pgc->pgc_fd, &phdr32, sizeof (phdr32),
928 929 *pgc->pgc_poff) != sizeof (phdr32))
929 930 return (1);
930 931
931 932 *pgc->pgc_poff += sizeof (phdr32);
932 933 #endif /* _LP64 */
933 934 }
934 935
935 936 return (0);
936 937 }
937 938
938 939 int
939 940 write_shstrtab(struct ps_prochandle *P, pgcore_t *pgc)
940 941 {
941 942 off64_t off = *pgc->pgc_doff;
942 943 size_t size = 0;
943 944 shstrtab_t *s = &pgc->pgc_shstrtab;
944 945 int i, ndx;
945 946
946 947 if (shstrtab_size(s) == 1)
947 948 return (0);
948 949
949 950 /*
950 951 * Preemptively stick the name of the shstrtab in the string table.
951 952 */
952 953 (void) shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
953 954 size = shstrtab_size(s);
954 955
955 956 /*
956 957 * Dump all the strings that we used being sure we include the
957 958 * terminating null character.
958 959 */
959 960 for (i = 0; i < STR_NUM; i++) {
960 961 if ((ndx = s->sst_ndx[i]) != 0 || i == STR_NONE) {
961 962 const char *str = shstrtab_data[i];
962 963 size_t len = strlen(str) + 1;
963 964 if (pwrite64(pgc->pgc_fd, str, len, off + ndx) != len)
964 965 return (1);
965 966 }
966 967 }
967 968
968 969 if (P->status.pr_dmodel == PR_MODEL_ILP32) {
969 970 Elf32_Shdr shdr;
970 971
971 972 bzero(&shdr, sizeof (shdr));
972 973 shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
973 974 shdr.sh_size = size;
974 975 shdr.sh_offset = *pgc->pgc_doff;
975 976 shdr.sh_addralign = 1;
976 977 shdr.sh_flags = SHF_STRINGS;
977 978 shdr.sh_type = SHT_STRTAB;
978 979
979 980 if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
980 981 *pgc->pgc_soff) != sizeof (shdr))
981 982 return (1);
982 983
983 984 *pgc->pgc_soff += sizeof (shdr);
984 985 #ifdef _LP64
985 986 } else {
986 987 Elf64_Shdr shdr;
987 988
988 989 bzero(&shdr, sizeof (shdr));
989 990 shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
990 991 shdr.sh_size = size;
991 992 shdr.sh_offset = *pgc->pgc_doff;
992 993 shdr.sh_addralign = 1;
993 994 shdr.sh_flags = SHF_STRINGS;
994 995 shdr.sh_type = SHT_STRTAB;
995 996
996 997 if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
997 998 *pgc->pgc_soff) != sizeof (shdr))
998 999 return (1);
999 1000
1000 1001 *pgc->pgc_soff += sizeof (shdr);
1001 1002 #endif /* _LP64 */
1002 1003 }
1003 1004
1004 1005 *pgc->pgc_doff += roundup(size, 8);
1005 1006
1006 1007 return (0);
1007 1008 }
1008 1009
1009 1010 /*
1010 1011 * Don't explicity stop the process; that's up to the consumer.
1011 1012 */
1012 1013 int
1013 1014 Pfgcore(struct ps_prochandle *P, int fd, core_content_t content)
1014 1015 {
1015 1016 char plat[SYS_NMLN];
1016 1017 char zonename[ZONENAME_MAX];
1017 1018 int platlen = -1;
1018 1019 pgcore_t pgc;
1019 1020 off64_t poff, soff, doff, boff;
1020 1021 struct utsname uts;
1021 1022 uint_t nphdrs, nshdrs;
1022 1023
1023 1024 if (ftruncate64(fd, 0) != 0)
1024 1025 return (-1);
1025 1026
1026 1027 if (content == CC_CONTENT_INVALID) {
1027 1028 errno = EINVAL;
1028 1029 return (-1);
1029 1030 }
1030 1031
1031 1032 /*
1032 1033 * Cache the mappings and other useful data.
1033 1034 */
1034 1035 (void) Prd_agent(P);
1035 1036 (void) Ppsinfo(P);
1036 1037
1037 1038 pgc.P = P;
1038 1039 pgc.pgc_fd = fd;
1039 1040 pgc.pgc_poff = &poff;
1040 1041 pgc.pgc_soff = &soff;
1041 1042 pgc.pgc_doff = &doff;
1042 1043 pgc.pgc_content = content;
1043 1044 pgc.pgc_chunksz = PAGESIZE;
1044 1045 if ((pgc.pgc_chunk = malloc(pgc.pgc_chunksz)) == NULL)
1045 1046 return (-1);
1046 1047
1047 1048 shstrtab_init(&pgc.pgc_shstrtab);
1048 1049
1049 1050 /*
1050 1051 * There are two PT_NOTE program headers for ancillary data, and
1051 1052 * one for each mapping.
1052 1053 */
1053 1054 nphdrs = 2 + P->map_count;
1054 1055 nshdrs = count_sections(&pgc);
1055 1056
1056 1057 (void) Pplatform(P, plat, sizeof (plat));
1057 1058 platlen = strlen(plat) + 1;
1058 1059 Preadauxvec(P);
1059 1060 (void) Puname(P, &uts);
1060 1061 if (Pzonename(P, zonename, sizeof (zonename)) == NULL)
1061 1062 zonename[0] = '\0';
1062 1063
1063 1064 /*
1064 1065 * The core file contents may required zero section headers, but if we
1065 1066 * overflow the 16 bits allotted to the program header count in the ELF
1066 1067 * header, we'll need that program header at index zero.
1067 1068 */
1068 1069 if (nshdrs == 0 && nphdrs >= PN_XNUM)
1069 1070 nshdrs = 1;
1070 1071
1071 1072 /*
1072 1073 * Set up the ELF header.
1073 1074 */
1074 1075 if (P->status.pr_dmodel == PR_MODEL_ILP32) {
1075 1076 Elf32_Ehdr ehdr;
1076 1077
1077 1078 bzero(&ehdr, sizeof (ehdr));
1078 1079 ehdr.e_ident[EI_MAG0] = ELFMAG0;
1079 1080 ehdr.e_ident[EI_MAG1] = ELFMAG1;
1080 1081 ehdr.e_ident[EI_MAG2] = ELFMAG2;
1081 1082 ehdr.e_ident[EI_MAG3] = ELFMAG3;
1082 1083 ehdr.e_type = ET_CORE;
1083 1084
1084 1085 ehdr.e_ident[EI_CLASS] = ELFCLASS32;
1085 1086 #if defined(__sparc)
1086 1087 ehdr.e_machine = EM_SPARC;
1087 1088 ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
1088 1089 #elif defined(__i386) || defined(__amd64)
1089 1090 ehdr.e_machine = EM_386;
1090 1091 ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
1091 1092 #else
1092 1093 #error "unknown machine type"
1093 1094 #endif
1094 1095 ehdr.e_ident[EI_VERSION] = EV_CURRENT;
1095 1096
1096 1097 ehdr.e_version = EV_CURRENT;
1097 1098 ehdr.e_ehsize = sizeof (ehdr);
1098 1099
1099 1100 if (nphdrs >= PN_XNUM)
1100 1101 ehdr.e_phnum = PN_XNUM;
1101 1102 else
1102 1103 ehdr.e_phnum = (unsigned short)nphdrs;
1103 1104
1104 1105 ehdr.e_phentsize = sizeof (Elf32_Phdr);
1105 1106 ehdr.e_phoff = ehdr.e_ehsize;
1106 1107
1107 1108 if (nshdrs > 0) {
1108 1109 if (nshdrs >= SHN_LORESERVE)
1109 1110 ehdr.e_shnum = 0;
1110 1111 else
1111 1112 ehdr.e_shnum = (unsigned short)nshdrs;
1112 1113
1113 1114 if (nshdrs - 1 >= SHN_LORESERVE)
1114 1115 ehdr.e_shstrndx = SHN_XINDEX;
1115 1116 else
1116 1117 ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);
1117 1118
1118 1119 ehdr.e_shentsize = sizeof (Elf32_Shdr);
1119 1120 ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
1120 1121 }
1121 1122
1122 1123 if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
1123 1124 goto err;
1124 1125
1125 1126 poff = ehdr.e_phoff;
1126 1127 soff = ehdr.e_shoff;
1127 1128 doff = boff = ehdr.e_ehsize +
1128 1129 ehdr.e_phentsize * nphdrs +
1129 1130 ehdr.e_shentsize * nshdrs;
1130 1131
1131 1132 #ifdef _LP64
1132 1133 } else {
1133 1134 Elf64_Ehdr ehdr;
1134 1135
1135 1136 bzero(&ehdr, sizeof (ehdr));
1136 1137 ehdr.e_ident[EI_MAG0] = ELFMAG0;
1137 1138 ehdr.e_ident[EI_MAG1] = ELFMAG1;
1138 1139 ehdr.e_ident[EI_MAG2] = ELFMAG2;
1139 1140 ehdr.e_ident[EI_MAG3] = ELFMAG3;
1140 1141 ehdr.e_type = ET_CORE;
1141 1142
1142 1143 ehdr.e_ident[EI_CLASS] = ELFCLASS64;
1143 1144 #if defined(__sparc)
1144 1145 ehdr.e_machine = EM_SPARCV9;
1145 1146 ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
1146 1147 #elif defined(__i386) || defined(__amd64)
1147 1148 ehdr.e_machine = EM_AMD64;
1148 1149 ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
1149 1150 #else
1150 1151 #error "unknown machine type"
1151 1152 #endif
1152 1153 ehdr.e_ident[EI_VERSION] = EV_CURRENT;
1153 1154
1154 1155 ehdr.e_version = EV_CURRENT;
1155 1156 ehdr.e_ehsize = sizeof (ehdr);
1156 1157
1157 1158 if (nphdrs >= PN_XNUM)
1158 1159 ehdr.e_phnum = PN_XNUM;
1159 1160 else
1160 1161 ehdr.e_phnum = (unsigned short)nphdrs;
1161 1162
1162 1163 ehdr.e_phentsize = sizeof (Elf64_Phdr);
1163 1164 ehdr.e_phoff = ehdr.e_ehsize;
1164 1165
1165 1166 if (nshdrs > 0) {
1166 1167 if (nshdrs >= SHN_LORESERVE)
1167 1168 ehdr.e_shnum = 0;
1168 1169 else
1169 1170 ehdr.e_shnum = (unsigned short)nshdrs;
1170 1171
1171 1172 if (nshdrs - 1 >= SHN_LORESERVE)
1172 1173 ehdr.e_shstrndx = SHN_XINDEX;
1173 1174 else
1174 1175 ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);
1175 1176
1176 1177 ehdr.e_shentsize = sizeof (Elf64_Shdr);
1177 1178 ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
1178 1179 }
1179 1180
1180 1181 if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
1181 1182 goto err;
1182 1183
1183 1184 poff = ehdr.e_phoff;
1184 1185 soff = ehdr.e_shoff;
1185 1186 doff = boff = ehdr.e_ehsize +
1186 1187 ehdr.e_phentsize * nphdrs +
1187 1188 ehdr.e_shentsize * nshdrs;
1188 1189
1189 1190 #endif /* _LP64 */
1190 1191 }
1191 1192
1192 1193 /*
1193 1194 * Write the zero indexed section if it exists.
1194 1195 */
1195 1196 if (nshdrs > 0 && write_shdr(&pgc, STR_NONE, 0, 0, 0, 0,
1196 1197 nshdrs >= SHN_LORESERVE ? nshdrs : 0,
1197 1198 nshdrs - 1 >= SHN_LORESERVE ? nshdrs - 1 : 0,
1198 1199 nphdrs >= PN_XNUM ? nphdrs : 0, 0, 0) != 0)
1199 1200 goto err;
1200 1201
1201 1202 /*
1202 1203 * Construct the old-style note header and section.
1203 1204 */
1204 1205
1205 1206 if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
1206 1207 prpsinfo_t prpsinfo;
1207 1208
1208 1209 mkprpsinfo(P, &prpsinfo);
1209 1210 if (write_note(fd, NT_PRPSINFO, &prpsinfo, sizeof (prpsinfo_t),
1210 1211 &doff) != 0) {
1211 1212 goto err;
1212 1213 }
1213 1214 if (write_note(fd, NT_AUXV, P->auxv,
1214 1215 P->nauxv * sizeof (P->auxv[0]), &doff) != 0) {
1215 1216 goto err;
1216 1217 }
1217 1218 #ifdef _LP64
1218 1219 } else {
1219 1220 prpsinfo32_t pi32;
1220 1221 auxv32_t *av32;
1221 1222 size_t size = sizeof (auxv32_t) * P->nauxv;
1222 1223 int i;
1223 1224
1224 1225 mkprpsinfo32(P, &pi32);
1225 1226 if (write_note(fd, NT_PRPSINFO, &pi32, sizeof (prpsinfo32_t),
1226 1227 &doff) != 0) {
1227 1228 goto err;
1228 1229 }
1229 1230
1230 1231 if ((av32 = malloc(size)) == NULL)
1231 1232 goto err;
1232 1233
1233 1234 for (i = 0; i < P->nauxv; i++) {
1234 1235 auxv_n_to_32(&P->auxv[i], &av32[i]);
1235 1236 }
1236 1237
1237 1238 if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) {
1238 1239 free(av32);
1239 1240 goto err;
1240 1241 }
1241 1242
1242 1243 free(av32);
1243 1244 #endif /* _LP64 */
1244 1245 }
1245 1246
1246 1247 if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0)
1247 1248 goto err;
1248 1249
1249 1250 if (Plwp_iter_all(P, old_per_lwp, &pgc) != 0)
1250 1251 goto err;
1251 1252
1252 1253 if (P->status.pr_dmodel == PR_MODEL_ILP32) {
1253 1254 Elf32_Phdr phdr;
1254 1255
1255 1256 bzero(&phdr, sizeof (phdr));
1256 1257 phdr.p_type = PT_NOTE;
1257 1258 phdr.p_flags = PF_R;
1258 1259 phdr.p_offset = (Elf32_Off)boff;
1259 1260 phdr.p_filesz = doff - boff;
1260 1261 boff = doff;
1261 1262
1262 1263 if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
1263 1264 goto err;
1264 1265 poff += sizeof (phdr);
1265 1266 #ifdef _LP64
1266 1267 } else {
1267 1268 Elf64_Phdr phdr;
1268 1269
1269 1270 bzero(&phdr, sizeof (phdr));
1270 1271 phdr.p_type = PT_NOTE;
1271 1272 phdr.p_flags = PF_R;
1272 1273 phdr.p_offset = boff;
1273 1274 phdr.p_filesz = doff - boff;
1274 1275 boff = doff;
1275 1276
1276 1277 if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
1277 1278 goto err;
1278 1279 poff += sizeof (phdr);
1279 1280 #endif /* _LP64 */
1280 1281 }
1281 1282
1282 1283 /*
1283 1284 * Construct the new-style note header and section.
1284 1285 */
1285 1286
1286 1287 if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
1287 1288 if (write_note(fd, NT_PSINFO, &P->psinfo, sizeof (psinfo_t),
1288 1289 &doff) != 0) {
1289 1290 goto err;
1290 1291 }
1291 1292 if (write_note(fd, NT_PSTATUS, &P->status, sizeof (pstatus_t),
1292 1293 &doff) != 0) {
1293 1294 goto err;
1294 1295 }
1295 1296 if (write_note(fd, NT_AUXV, P->auxv,
1296 1297 P->nauxv * sizeof (P->auxv[0]), &doff) != 0) {
1297 1298 goto err;
1298 1299 }
1299 1300 #ifdef _LP64
1300 1301 } else {
1301 1302 psinfo32_t pi32;
1302 1303 pstatus32_t ps32;
1303 1304 auxv32_t *av32;
1304 1305 size_t size = sizeof (auxv32_t) * P->nauxv;
1305 1306 int i;
1306 1307
1307 1308 psinfo_n_to_32(&P->psinfo, &pi32);
1308 1309 if (write_note(fd, NT_PSINFO, &pi32, sizeof (psinfo32_t),
1309 1310 &doff) != 0) {
1310 1311 goto err;
1311 1312 }
1312 1313 pstatus_n_to_32(&P->status, &ps32);
1313 1314 if (write_note(fd, NT_PSTATUS, &ps32, sizeof (pstatus32_t),
1314 1315 &doff) != 0) {
1315 1316 goto err;
1316 1317 }
1317 1318 if ((av32 = malloc(size)) == NULL)
1318 1319 goto err;
1319 1320
1320 1321 for (i = 0; i < P->nauxv; i++) {
1321 1322 auxv_n_to_32(&P->auxv[i], &av32[i]);
1322 1323 }
1323 1324
1324 1325 if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) {
1325 1326 free(av32);
1326 1327 goto err;
1327 1328 }
1328 1329
1329 1330 free(av32);
1330 1331 #endif /* _LP64 */
1331 1332 }
1332 1333
1333 1334 if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0 ||
1334 1335 write_note(fd, NT_UTSNAME, &uts, sizeof (uts), &doff) != 0 ||
1335 1336 write_note(fd, NT_CONTENT, &content, sizeof (content), &doff) != 0)
1336 1337 goto err;
1337 1338
1338 1339 {
1339 1340 prcred_t cred, *cp;
1340 1341 size_t size = sizeof (prcred_t);
1341 1342
1342 1343 if (Pcred(P, &cred, 0) != 0)
1343 1344 goto err;
1344 1345
1345 1346 if (cred.pr_ngroups > 0)
1346 1347 size += sizeof (gid_t) * (cred.pr_ngroups - 1);
1347 1348 if ((cp = malloc(size)) == NULL)
1348 1349 goto err;
1349 1350
↓ open down ↓ |
1311 lines elided |
↑ open up ↑ |
1350 1351 if (Pcred(P, cp, cred.pr_ngroups) != 0 ||
1351 1352 write_note(fd, NT_PRCRED, cp, size, &doff) != 0) {
1352 1353 free(cp);
1353 1354 goto err;
1354 1355 }
1355 1356
1356 1357 free(cp);
1357 1358 }
1358 1359
1359 1360 {
1360 - prpriv_t *ppriv;
1361 + prpriv_t *ppriv = NULL;
1361 1362 const priv_impl_info_t *pinfo;
1362 1363 size_t pprivsz, pinfosz;
1363 1364
1364 - if ((ppriv = proc_get_priv(P->pid)) == NULL)
1365 + if (Ppriv(P, &ppriv) == -1)
1365 1366 goto err;
1366 1367 pprivsz = PRIV_PRPRIV_SIZE(ppriv);
1367 1368
1368 1369 if (write_note(fd, NT_PRPRIV, ppriv, pprivsz, &doff) != 0) {
1369 1370 free(ppriv);
1370 1371 goto err;
1371 1372 }
1372 1373 free(ppriv);
1373 1374
1374 1375 if ((pinfo = getprivimplinfo()) == NULL)
1375 1376 goto err;
1376 1377 pinfosz = PRIV_IMPL_INFO_SIZE(pinfo);
1377 1378
1378 1379 if (write_note(fd, NT_PRPRIVINFO, pinfo, pinfosz, &doff) != 0)
1379 1380 goto err;
1380 1381 }
1381 1382
1382 1383 if (write_note(fd, NT_ZONENAME, zonename, strlen(zonename) + 1,
1383 1384 &doff) != 0)
1384 1385 goto err;
1385 1386
1386 1387 {
1387 1388 fditer_t iter;
1388 1389 iter.fd_fd = fd;
1389 1390 iter.fd_doff = &doff;
1390 1391
1391 1392 if (Pfdinfo_iter(P, iter_fd, &iter) != 0)
1392 1393 goto err;
1393 1394 }
1394 1395
1395 1396 #if defined(__i386) || defined(__amd64)
1396 1397 /* CSTYLED */
1397 1398 {
1398 1399 struct ssd *ldtp;
1399 1400 size_t size;
1400 1401 int nldt;
1401 1402
1402 1403 /*
1403 1404 * Only dump out non-zero sized LDT notes.
1404 1405 */
1405 1406 if ((nldt = Pldt(P, NULL, 0)) != 0) {
1406 1407 size = sizeof (struct ssd) * nldt;
1407 1408 if ((ldtp = malloc(size)) == NULL)
1408 1409 goto err;
1409 1410
1410 1411 if (Pldt(P, ldtp, nldt) == -1 ||
1411 1412 write_note(fd, NT_LDT, ldtp, size, &doff) != 0) {
1412 1413 free(ldtp);
1413 1414 goto err;
1414 1415 }
1415 1416
1416 1417 free(ldtp);
1417 1418 }
1418 1419 }
1419 1420 #endif /* __i386 || __amd64 */
1420 1421
1421 1422 if (Plwp_iter_all(P, new_per_lwp, &pgc) != 0)
1422 1423 goto err;
1423 1424
1424 1425 if (P->status.pr_dmodel == PR_MODEL_ILP32) {
1425 1426 Elf32_Phdr phdr;
1426 1427
1427 1428 bzero(&phdr, sizeof (phdr));
1428 1429 phdr.p_type = PT_NOTE;
1429 1430 phdr.p_flags = PF_R;
1430 1431 phdr.p_offset = (Elf32_Off)boff;
1431 1432 phdr.p_filesz = doff - boff;
1432 1433 boff = doff;
1433 1434
1434 1435 if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
1435 1436 goto err;
1436 1437 poff += sizeof (phdr);
1437 1438 #ifdef _LP64
1438 1439 } else {
1439 1440 Elf64_Phdr phdr;
1440 1441
1441 1442 bzero(&phdr, sizeof (phdr));
1442 1443 phdr.p_type = PT_NOTE;
1443 1444 phdr.p_flags = PF_R;
1444 1445 phdr.p_offset = boff;
1445 1446 phdr.p_filesz = doff - boff;
1446 1447 boff = doff;
1447 1448
1448 1449 if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
1449 1450 goto err;
1450 1451 poff += sizeof (phdr);
1451 1452 #endif /* _LP64 */
1452 1453 }
1453 1454
1454 1455 /*
1455 1456 * Construct the headers for each mapping and write out its data
1456 1457 * if the content parameter indicates that it should be present
1457 1458 * in the core file.
1458 1459 */
1459 1460 if (Pmapping_iter(P, dump_map, &pgc) != 0)
1460 1461 goto err;
1461 1462
1462 1463 if (dump_sections(&pgc) != 0)
1463 1464 goto err;
1464 1465
1465 1466 if (write_shstrtab(P, &pgc) != 0)
1466 1467 goto err;
1467 1468
1468 1469 free(pgc.pgc_chunk);
1469 1470
1470 1471 return (0);
1471 1472
1472 1473 err:
1473 1474 /*
1474 1475 * Wipe out anything we may have written if there was an error.
1475 1476 */
1476 1477 (void) ftruncate64(fd, 0);
1477 1478 free(pgc.pgc_chunk);
1478 1479 return (-1);
1479 1480 }
1480 1481
1481 1482 static const char *content_str[] = {
1482 1483 "stack", /* CC_CONTENT_STACK */
1483 1484 "heap", /* CC_CONTENT_HEAP */
1484 1485 "shfile", /* CC_CONTENT_SHFILE */
1485 1486 "shanon", /* CC_CONTENT_SHANON */
1486 1487 "text", /* CC_CONTENT_TEXT */
1487 1488 "data", /* CC_CONTENT_DATA */
1488 1489 "rodata", /* CC_CONTENT_RODATA */
1489 1490 "anon", /* CC_CONTENT_ANON */
1490 1491 "shm", /* CC_CONTENT_SHM */
1491 1492 "ism", /* CC_CONTENT_ISM */
1492 1493 "dism", /* CC_CONTENT_DISM */
1493 1494 "ctf", /* CC_CONTENT_CTF */
1494 1495 "symtab", /* CC_CONTENT_SYMTAB */
1495 1496 };
1496 1497
1497 1498 static uint_t ncontent_str = sizeof (content_str) / sizeof (content_str[0]);
1498 1499
1499 1500 #define STREQ(a, b, n) (strlen(b) == (n) && strncmp(a, b, n) == 0)
1500 1501
1501 1502 int
1502 1503 proc_str2content(const char *str, core_content_t *cp)
1503 1504 {
1504 1505 const char *cur = str;
1505 1506 int add = 1;
1506 1507 core_content_t mask, content = 0;
1507 1508
1508 1509 for (;;) {
1509 1510 for (cur = str; isalpha(*cur); cur++)
1510 1511 continue;
1511 1512
1512 1513 if (STREQ(str, "default", cur - str)) {
1513 1514 mask = CC_CONTENT_DEFAULT;
1514 1515 } else if (STREQ(str, "all", cur - str)) {
1515 1516 mask = CC_CONTENT_ALL;
1516 1517 } else if (STREQ(str, "none", cur - str)) {
1517 1518 mask = 0;
1518 1519 } else {
1519 1520 int i = 0;
1520 1521
1521 1522 while (!STREQ(str, content_str[i], cur - str)) {
1522 1523 i++;
1523 1524
1524 1525 if (i >= ncontent_str)
1525 1526 return (-1);
1526 1527 }
1527 1528
1528 1529 mask = (core_content_t)1 << i;
1529 1530 }
1530 1531
1531 1532 if (add)
1532 1533 content |= mask;
1533 1534 else
1534 1535 content &= ~mask;
1535 1536
1536 1537 switch (*cur) {
1537 1538 case '\0':
1538 1539 *cp = content;
1539 1540 return (0);
1540 1541 case '+':
1541 1542 add = 1;
1542 1543 break;
1543 1544 case '-':
1544 1545 add = 0;
1545 1546 break;
1546 1547 default:
1547 1548 return (-1);
1548 1549 }
1549 1550
1550 1551 str = cur + 1;
1551 1552 }
1552 1553 }
1553 1554
1554 1555 static int
1555 1556 popc(core_content_t x)
1556 1557 {
1557 1558 int i;
1558 1559
1559 1560 for (i = 0; x != 0; i++)
1560 1561 x &= x - 1;
1561 1562
1562 1563 return (i);
1563 1564 }
1564 1565
1565 1566 int
1566 1567 proc_content2str(core_content_t content, char *buf, size_t size)
1567 1568 {
1568 1569 int nonecnt, defcnt, allcnt;
1569 1570 core_content_t mask, bit;
1570 1571 int first;
1571 1572 uint_t index;
1572 1573 size_t n, tot = 0;
1573 1574
1574 1575 if (content == 0)
1575 1576 return ((int)strlcpy(buf, "none", size));
1576 1577
1577 1578 if (content & ~CC_CONTENT_ALL)
1578 1579 return ((int)strlcpy(buf, "<invalid>", size));
1579 1580
1580 1581 nonecnt = popc(content);
1581 1582 defcnt = 1 + popc(content ^ CC_CONTENT_DEFAULT);
1582 1583 allcnt = 1 + popc(content ^ CC_CONTENT_ALL);
1583 1584
1584 1585 if (defcnt <= nonecnt && defcnt <= allcnt) {
1585 1586 mask = content ^ CC_CONTENT_DEFAULT;
1586 1587 first = 0;
1587 1588 tot += (n = strlcpy(buf, "default", size));
1588 1589 if (n > size)
1589 1590 n = size;
1590 1591 buf += n;
1591 1592 size -= n;
1592 1593 } else if (allcnt < nonecnt) {
1593 1594 mask = content ^ CC_CONTENT_ALL;
1594 1595 first = 0;
1595 1596 tot += (n = strlcpy(buf, "all", size));
1596 1597 if (n > size)
1597 1598 n = size;
1598 1599 buf += n;
1599 1600 size -= n;
1600 1601 } else {
1601 1602 mask = content;
1602 1603 first = 1;
1603 1604 }
1604 1605
1605 1606 while (mask != 0) {
1606 1607 bit = mask ^ (mask & (mask - 1));
1607 1608
1608 1609 if (!first) {
1609 1610 if (size > 1) {
1610 1611 *buf = (bit & content) ? '+' : '-';
1611 1612 buf++;
1612 1613 size--;
1613 1614 }
1614 1615
1615 1616 tot++;
1616 1617 }
1617 1618 index = popc(bit - 1);
1618 1619 tot += (n = strlcpy(buf, content_str[index], size));
1619 1620 if (n > size)
1620 1621 n = size;
1621 1622 buf += n;
1622 1623 size -= n;
1623 1624
1624 1625 mask ^= bit;
1625 1626 first = 0;
1626 1627 }
1627 1628
1628 1629 return ((int)tot);
1629 1630 }
↓ open down ↓ |
255 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX