Esempio n. 1
0
static int
dump_symtab(pgcore_t *pgc, file_info_t *fptr, uint_t index, int dynsym)
{
	sym_tbl_t *sym = dynsym ? &fptr->file_dynsym : &fptr->file_symtab;
	shstrtype_t symname = dynsym ? STR_DYNSYM : STR_SYMTAB;
	shstrtype_t strname = dynsym ? STR_DYNSTR : STR_STRTAB;
	uint_t symtype = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
	size_t size;
	uintptr_t addr = fptr->file_map->map_pmap.pr_vaddr;

	if (sym->sym_data_pri == NULL || sym->sym_symn == 0 ||
	    sym->sym_strs == NULL)
		return (0);

	size = sym->sym_hdr_pri.sh_size;
	if (gc_pwrite64(pgc->pgc_fd, sym->sym_data_pri->d_buf, size,
	    *pgc->pgc_doff) != 0)
		return (-1);

	if (write_shdr(pgc, symname, symtype, 0, addr, *pgc->pgc_doff, size,
	    index + 1, sym->sym_hdr_pri.sh_info, sym->sym_hdr_pri.sh_addralign,
	    sym->sym_hdr_pri.sh_entsize) != 0)
		return (-1);

	*pgc->pgc_doff += roundup(size, 8);

	size = sym->sym_strhdr.sh_size;
	if (gc_pwrite64(pgc->pgc_fd, sym->sym_strs, size, *pgc->pgc_doff) != 0)
		return (-1);

	if (write_shdr(pgc, strname, SHT_STRTAB, SHF_STRINGS, addr,
	    *pgc->pgc_doff, size, 0, 0, 1, 0) != 0)
		return (-1);

	*pgc->pgc_doff += roundup(size, 8);

	return (0);
}
Esempio n. 2
0
int write_elf(struct _asm_context *asm_context, FILE *out)
{
unsigned char e_ident[16] = { 0x7f, 'E','L','F',  1, 1, 1, 0xff,
                              0, 0, 0, 0,  0, 0, 0, 0 };
struct _sections_offset sections_offset;
struct _sections_size sections_size;
struct _shdr shdr;
struct _symtab symtab;
int i;
int e_flags;
int e_shnum;
int e_shstrndx=0;
int text_addr[ELF_TEXT_MAX];
int data_addr[ELF_TEXT_MAX];
int text_count=0;
int data_count=0;

  memset(&sections_offset, 0, sizeof(sections_offset));
  memset(&sections_size, 0, sizeof(sections_size));

  // Fill in blank to minimize text and data sections
  i=0;
  while (i<=asm_context->high_address)
  {
    if (asm_context->debug_line[i]==-2)
    {
      // Fill gaps in data sections
      while(asm_context->debug_line[i]==-2)
      {
        //printf("Found data %02x\n", i);
        while(i<=asm_context->high_address && asm_context->debug_line[i]==-2)
        { i+=2; }
        //printf("End data %02x\n", i);
        if (i==asm_context->high_address) break;
        int marker=i;
        while(i<=asm_context->high_address && asm_context->debug_line[i]==-1)
        { i+=2; }
        if (i==asm_context->high_address) break;

        if (i<=asm_context->high_address && asm_context->debug_line[i]==-2)
        {
          while(marker!=i) { asm_context->debug_line[marker++]=-2; }
        }
        if (i==asm_context->high_address) break;
      }
    }
      else
    if (asm_context->debug_line[i]>=0)
    {
      // Fill gaps in code sections
      while(i<=asm_context->high_address && asm_context->debug_line[i]>=0)
      {
        //printf("Found code %02x %d %d\n", i, asm_context->debug_line[i], asm_context->bin[i]);
        while(i<=asm_context->high_address && (asm_context->debug_line[i]>=0 || asm_context->debug_line[i]==-3))
        { i+=2; }
        if (i==asm_context->high_address) break;
        //printf("End code %02x  %d\n", i, asm_context->debug_line[i]);
        int marker=i;
        while(i<=asm_context->high_address && asm_context->debug_line[i]==-1)
        { i+=2; }
        if (i==asm_context->high_address) break;

        if (asm_context->debug_line[i]>=0)
        {
          while(marker!=i) { asm_context->debug_line[marker++]=-3; }
        }
        if (i==asm_context->high_address) break;
      }
    }

    i+=2;
  }

  // For now we will only have .text, .shstrtab, .symtab, strtab
  // I can't see a use for .data and .bss unless the bootloaders know elf?
  // I'm also not supporting relocations.  I can do it later if requested.

  // Write string table
  char string_table[1024] = {
    "\0"
    //".text\0"
    //".rela.text\0"
    //".data\0"
    //".bss\0"
    ".shstrtab\0"
    ".symtab\0"
    ".strtab\0"
    ".comment\0"
    //".debug_line\0"
    //".rela.debug_line\0"
    //".debug_info\0"
    //".rela.debug_info\0"
    //".debug_abbrev\0"
    //".debug_aranges\0"
    //".rela.debug_aranges\0"
  };

  e_flags=11;  // mspgcc4/build/insight-6.8-1/include/elf/msp430.h

  e_shnum=4;
  //if (asm_context->debug_file==1) { e_shnum+=4; }
  e_shnum++; // Null section to start...

  // Write Ehdr;
  i=fwrite(e_ident, 1, 16, out);
  write_int16_l(out, 0);       // e_type 0=not relocatable 1=msp_32
  write_int16_l(out, 0x69);    // e_machine EM_MSP430=0x69
  write_int32_l(out, 1);       // e_version
  write_int32_l(out, 0);       // e_entry (this could be 16 bit at 0xfffe)
  write_int32_l(out, 0);       // e_phoff (program header offset)
  write_int32_l(out, 0);       // e_shoff (section header offset)
  write_int32_l(out, e_flags); // e_flags (should be set to CPU model)
  write_int16_l(out, 0x34);    // e_ehsize (size of this struct)
  write_int16_l(out, 0);       // e_phentsize (program header size)
  write_int16_l(out, 0);       // e_phnum (number of program headers)
  write_int16_l(out, 40);      // e_shentsize (section header size)
  write_int16_l(out, e_shnum); // e_shnum (number of section headers)
  write_int16_l(out, 2);       // e_shstrndx (section header string table index)

  // .text and .data sections
  i=0;
  while (i<=asm_context->high_address)
  {
    char name[32];

    if (asm_context->debug_line[i]==-2)
    {
      if (data_count>=ELF_TEXT_MAX) { printf("Too many elf .data sections (count=%d).  Internal error.\n", data_count); exit(1); }
      if (data_count==0) { strcpy(name, ".data"); }
      else { sprintf(name, ".data%d", data_count); }
      data_addr[data_count]=i;
      string_table_append(string_table, name);
      sections_offset.data[data_count]=ftell(out);
      while(asm_context->debug_line[i]==-2)
      {
        putc(asm_context->bin[i++], out);
        putc(asm_context->bin[i++], out);
      }
      //i=fwrite(asm_context->bin+asm_context->low_address, 1, asm_context->high_address-asm_context->low_address+1, out);
      sections_size.data[data_count]=ftell(out)-sections_offset.data[data_count];
      data_count++;
      e_shnum++;
    }
      else
    if (asm_context->debug_line[i]!=-1)
    {
      if (text_count>=ELF_TEXT_MAX) { printf("Too many elf .text sections(%d).  Internal error.\n", text_count); exit(1); }
      if (text_count==0) { strcpy(name, ".text"); }
      else { sprintf(name, ".text%d", text_count); }
      text_addr[text_count]=i;
printf("and i=%d  text_count=%d\n", i, text_count);
      string_table_append(string_table, name);
      sections_offset.text[text_count]=ftell(out);
      while(asm_context->debug_line[i]>=0 || asm_context->debug_line[i]==-3)
      {
        putc(asm_context->bin[i++], out);
        putc(asm_context->bin[i++], out);
      }
      //i=fwrite(asm_context->bin+asm_context->low_address, 1, asm_context->high_address-asm_context->low_address+1, out);
      sections_size.text[text_count]=ftell(out)-sections_offset.text[text_count];
      text_count++;
      e_shnum++;
    }

    i++;
  }

  e_shstrndx=data_count+text_count+1;

  // .shstrtab section
  sections_offset.shstrtab=ftell(out);
  i=fwrite(string_table, 1, get_string_table_len(string_table), out);
  putc(0x00, out); // null
  sections_size.shstrtab=ftell(out)-sections_offset.shstrtab;

  {
    struct _address_heap *address_heap=&asm_context->address_heap;
    int symbol_count=0;
    int sym_offset=0;
    int ptr,n;

    // Count symbols
    ptr=0;
    while(ptr<address_heap->ptr)
    {
      int token_len=strlen((char *)address_heap->buffer+ptr)+1;
      //fprintf(out, "%s", address_heap->buffer+ptr);
      ptr=ptr+token_len+sizeof(int);
      symbol_count++;
    }

    int symbol_address[symbol_count];

    // .strtab section
    elf_addr_align(out);
    sections_offset.strtab=ftell(out);
    putc(0x00, out); // none

    fprintf(out, "%s%c", asm_context->filename, 0);
    sym_offset=strlen(asm_context->filename)+2;

    ptr=0;
    n=0;
    while(ptr<address_heap->ptr)
    {
      symbol_address[n++]=sym_offset;
      int token_len=strlen((char *)address_heap->buffer+ptr)+1;
      fprintf(out, "%s%c", address_heap->buffer+ptr, 0);
      ptr=ptr+token_len+sizeof(int);
      sym_offset+=token_len;
    }
    putc(0x00, out); // null
    sections_size.strtab=ftell(out)-sections_offset.strtab;

    // .symtab section
    elf_addr_align(out);
    sections_offset.symtab=ftell(out);

    // symtab text
    memset(&symtab, 0, sizeof(symtab));
    symtab.st_info=3;
    symtab.st_shndx=1;
    write_symtab(out, &symtab);

    // symtab filename
    memset(&symtab, 0, sizeof(symtab));
    symtab.st_name=1;
    symtab.st_info=4;
    write_symtab(out, &symtab);

    // symbols from lookup tables

    ptr=0;
    n=0;
    while(ptr<address_heap->ptr)
    {
      int token_len=strlen((char *)address_heap->buffer+ptr)+1;
      memset(&symtab, 0, sizeof(symtab));
      unsigned char *data=address_heap->buffer+ptr+token_len;
      symtab.st_name=symbol_address[n++];
      symtab.st_value=data[0]|(data[1]<<8)|(data[2]<<16)|(data[3]<<24);
      symtab.st_shndx=1;
      write_symtab(out, &symtab);
      ptr=ptr+token_len+sizeof(int);
    }

    sections_size.symtab=ftell(out)-sections_offset.symtab;
  }

  // .comment section
  sections_offset.comment=ftell(out);
  fprintf(out, "Created with naken430asm.  http://www.mikekohn.net/");
  sections_size.comment=ftell(out)-sections_offset.comment;

  if (asm_context->debug_file==1)
  {
    // insert debug sections
  }

  // A little ex-lax to dump the SHT's
  long marker=ftell(out);
  fseek(out, 32, SEEK_SET);
  write_int32_l(out, marker);     // e_shoff (section header offset)
  fseek(out, 0x30, SEEK_SET);
  write_int16_l(out, e_shnum);    // e_shnum (section count)
  write_int16_l(out, e_shstrndx); // e_shstrndx (string_table index)
  fseek(out, marker, SEEK_SET);

  memset(&shdr, 0, sizeof(shdr));
  write_shdr(out, &shdr);

  // SHT .text
  for (i=0; i<text_count; i++)
  {
    char name[32];
    if (i==0) { strcpy(name, ".text"); }
    else { sprintf(name, ".text%d", i); }
    shdr.sh_name=find_section(string_table, name, sizeof(string_table));
printf("name=%s (%d) %s\n", name, shdr.sh_name, string_table+ shdr.sh_name);
    shdr.sh_type=1;
    shdr.sh_flags=6;
printf("text_addr=%d\n", text_addr[i]);
    shdr.sh_addr=text_addr[i]; //asm_context->low_address;
    shdr.sh_offset=sections_offset.text[i];
    shdr.sh_size=sections_size.text[i];
    shdr.sh_addralign=1;
    write_shdr(out, &shdr);
  }

  // SHT .data
  for (i=0; i<data_count; i++)
  {
    char name[32];
    if (i==0) { strcpy(name, ".data"); }
    else { sprintf(name, ".data%d", i); }
    shdr.sh_name=find_section(string_table, name, sizeof(string_table));
    shdr.sh_type=1;
    shdr.sh_flags=3;
    shdr.sh_addr=data_addr[i]; //asm_context->low_address;
    shdr.sh_offset=sections_offset.data[i];
    shdr.sh_size=sections_size.data[i];
    shdr.sh_addralign=1;
    write_shdr(out, &shdr);
  }

  // SHT .shstrtab
  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_name=find_section(string_table, ".shstrtab", sizeof(string_table));
  shdr.sh_type=3;
  shdr.sh_offset=sections_offset.shstrtab;
  shdr.sh_size=sections_size.shstrtab;
  shdr.sh_addralign=1;
  write_shdr(out, &shdr);

  // SHT .symtab
  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_name=find_section(string_table, ".symtab", sizeof(string_table));
  shdr.sh_type=2;
  shdr.sh_offset=sections_offset.symtab;
  shdr.sh_size=sections_size.symtab;
  shdr.sh_addralign=4;
  shdr.sh_entsize=16;
  write_shdr(out, &shdr);

  // SHT .strtab
  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_name=find_section(string_table, ".strtab", sizeof(string_table));
  shdr.sh_type=3;
  shdr.sh_offset=sections_offset.strtab;
  shdr.sh_size=sections_size.strtab;
  shdr.sh_addralign=1;
  write_shdr(out, &shdr);

  // SHT .comment
  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_name=find_section(string_table, ".comment", sizeof(string_table));
  shdr.sh_type=1;
  shdr.sh_offset=sections_offset.comment;
  shdr.sh_size=sections_size.comment;
  shdr.sh_addralign=1;
  write_shdr(out, &shdr);

  if (asm_context->debug_file==1)
  {
    // insert debug SHT's
  }
 
  return 0;
}
Esempio n. 3
0
int
rewrite_code_section(elf_data_t *elf, inject_data_t *inject, char **err)
{
  Elf_Scn *scn;
  GElf_Shdr shdr;
  char *s;
  size_t shstrndx;

  if(elf_getshdrstrndx(elf->e, &shstrndx) < 0) {
    (*err) = "failed to get string table section index";
    return -1;
  }

  printf("shstrndx : %d\n",shstrndx);

  scn = NULL;
  while((scn = elf_nextscn(elf->e, scn))) {
    if(!gelf_getshdr(scn, &shdr)) {
      (*err) = "failed to get section header";
      return -1;
    }

    s = elf_strptr(elf->e, shstrndx, shdr.sh_name);
    if(!s) {
      (*err) = "failed to get section name";
      return -1;
    }
  	printf("section : %s\n",s);

    if(!strcmp(s, ABITAG_NAME)) {
      shdr.sh_name      = shdr.sh_name;              /* offset into string table */
      shdr.sh_type      = SHT_PROGBITS;              /* type */
      shdr.sh_flags     = SHF_ALLOC | SHF_EXECINSTR; /* flags */
      shdr.sh_addr      = inject->secaddr;           /* address to load section at */
      shdr.sh_offset    = inject->off;               /* file offset to start of section */
      shdr.sh_size      = inject->len;               /* size in bytes */
      shdr.sh_link      = 0;                         /* not used for code section */
      shdr.sh_info      = 0;                         /* not used for code section */
      shdr.sh_addralign = 16;                        /* memory alignment */
      shdr.sh_entsize   = 0;                         /* not used for code section */

      verbose("rewriting section header %lu:", elf_ndxscn(scn));
      verbose("  sh_name      = %u", shdr.sh_name);
      verbose("  sh_type      = SHT_PROGBITS");
      verbose("  sh_flags     = SHF_ALLOC | SHF_EXECINSTR"); 
      verbose("  sh_addr      = 0x%x", shdr.sh_addr);
      verbose("  sh_offset    = %lu", shdr.sh_offset);
      verbose("  sh_size      = %lu", shdr.sh_size);
      verbose("  sh_link      = 0");
      verbose("  sh_info      = 0");
      verbose("  sh_addralign = 0x%x", shdr.sh_addralign);
      verbose("  sh_entsize   = 0");

      inject->sidx = elf_ndxscn(scn);
      inject->scn = scn;
      memcpy(&inject->shdr, &shdr, sizeof(shdr));

      verbose("writing section header to file");

      if(write_shdr(elf, scn, &shdr, elf_ndxscn(scn), err) < 0) {
        return -1;
      }

      if(reorder_shdrs(elf, inject, err) < 0) {
        return -1;
      }

      break;
    }
  }

  if(!scn) {
    (*err) = "cannot find section to rewrite";
    return -1;
  }

  return 0;
}
Esempio n. 4
0
int
reorder_shdrs(elf_data_t *elf, inject_data_t *inject, char **err)
{
  int direction, skip;
  size_t i;
  Elf_Scn *scn;
  GElf_Shdr shdr;

  direction = 0;

  scn = elf_getscn(elf->e, inject->sidx - 1);
  if(scn && !gelf_getshdr(scn, &shdr)) {
    (*err) = "failed to get section header";
    return -1;
  }
  if(scn && shdr.sh_addr > inject->shdr.sh_addr) {
    /* Injected section header must be moved left */
    direction = -1;
  }

  scn = elf_getscn(elf->e, inject->sidx + 1);
  if(scn && !gelf_getshdr(scn, &shdr)) {
    (*err) = "failed to get section header";
    return -1;
  }
  if(scn && shdr.sh_addr < inject->shdr.sh_addr) {
    /* Injected section header must be moved right */
    direction = 1;
  }

  if(direction == 0) {
    /* Section headers are already in order */
    return 0;
  }

  i = inject->sidx;

  /* Order section headers by increasing address */
  skip = 0;
  for(scn = elf_getscn(elf->e, inject->sidx + direction); 
      scn != NULL;
      scn = elf_getscn(elf->e, inject->sidx + direction + skip)) {
    if(!gelf_getshdr(scn, &shdr)) {
      (*err) = "failed to get section header";
      return -1;
    }

    if((direction < 0 && shdr.sh_addr <= inject->shdr.sh_addr)
       || (direction > 0 && shdr.sh_addr >= inject->shdr.sh_addr)) {
      /* The order is okay from this point on */
      break;
    }

    /* Only reorder code section headers */
    if(shdr.sh_type != SHT_PROGBITS) {
      skip += direction;
      continue;
    }

    /* Swap the injected shdr with its neighbor progbits header */
    if(write_shdr(elf, scn, &inject->shdr, elf_ndxscn(scn), err) < 0) {
      return -1;
    }
    if(write_shdr(elf, inject->scn, &shdr, inject->sidx, err) < 0) {
      return -1;
    }

    inject->sidx += direction + skip;
    inject->scn = elf_getscn(elf->e, inject->sidx);
    skip = 0;
  }

  verbose("reordered sections %lu - %lu", i, inject->sidx);

  return 0;
}
Esempio n. 5
0
static int
dump_sections(pgcore_t *pgc)
{
	struct ps_prochandle *P = pgc->P;
	file_info_t *fptr;
	uint_t cnt;
	uint_t index = 1;

	if (!(pgc->pgc_content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)))
		return (0);

	fptr = list_next(&P->file_head);
	for (cnt = P->num_files; cnt > 0; cnt--, fptr = list_next(fptr)) {
		int hit_symtab = 0;

		Pbuild_file_symtab(P, fptr);

		if ((pgc->pgc_content & CC_CONTENT_CTF) &&
		    Pbuild_file_ctf(P, fptr) != NULL) {
			sym_tbl_t *sym;
			uint_t dynsym;
			uint_t symindex = 0;

			/*
			 * Write the symtab out first so we can correctly
			 * set the sh_link field in the CTF section header.
			 * symindex will be 0 if there is no corresponding
			 * symbol table section.
			 */
			if (fptr->file_ctf_dyn) {
				sym = &fptr->file_dynsym;
				dynsym = 1;
			} else {
				sym = &fptr->file_symtab;
				dynsym = 0;
				hit_symtab = 1;
			}

			if (sym->sym_data_pri != NULL && sym->sym_symn != 0 &&
			    sym->sym_strs != NULL) {
				symindex = index;
				if (dump_symtab(pgc, fptr, index, dynsym) != 0)
					return (-1);
				index += 2;
			}

			/*
			 * Write the CTF data that we've read out of the
			 * file itself into the core file.
			 */
			if (gc_pwrite64(pgc->pgc_fd, fptr->file_ctf_buf,
			    fptr->file_ctf_size, *pgc->pgc_doff) != 0)
				return (-1);

			if (write_shdr(pgc, STR_CTF, SHT_PROGBITS, 0,
			    fptr->file_map->map_pmap.pr_vaddr, *pgc->pgc_doff,
			    fptr->file_ctf_size, symindex, 0, 4, 0) != 0)
				return (-1);

			index++;
			*pgc->pgc_doff += roundup(fptr->file_ctf_size, 8);
		}

		if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab &&
		    fptr->file_symtab.sym_data_pri != NULL &&
		    fptr->file_symtab.sym_symn != 0 &&
		    fptr->file_symtab.sym_strs != NULL) {
			if (dump_symtab(pgc, fptr, index, 0) != 0)
				return (-1);
			index += 2;
		}
	}

	return (0);
}
Esempio n. 6
0
/*
 * Don't explicity stop the process; that's up to the consumer.
 */
int
Pfgcore(struct ps_prochandle *P, int fd, core_content_t content)
{
	char plat[SYS_NMLN];
	char zonename[ZONENAME_MAX];
	int platlen = -1;
	pgcore_t pgc;
	off64_t poff, soff, doff, boff;
	struct utsname uts;
	uint_t nphdrs, nshdrs;

	if (ftruncate64(fd, 0) != 0)
		return (-1);

	if (content == CC_CONTENT_INVALID) {
		errno = EINVAL;
		return (-1);
	}

	/*
	 * Cache the mappings and other useful data.
	 */
	(void) Prd_agent(P);
	(void) Ppsinfo(P);

	pgc.P = P;
	pgc.pgc_fd = fd;
	pgc.pgc_poff = &poff;
	pgc.pgc_soff = &soff;
	pgc.pgc_doff = &doff;
	pgc.pgc_content = content;
	pgc.pgc_chunksz = PAGESIZE;
	if ((pgc.pgc_chunk = malloc(pgc.pgc_chunksz)) == NULL)
		return (-1);

	shstrtab_init(&pgc.pgc_shstrtab);

	/*
	 * There are two PT_NOTE program headers for ancillary data, and
	 * one for each mapping.
	 */
	nphdrs = 2 + P->map_count;
	nshdrs = count_sections(&pgc);

	(void) Pplatform(P, plat, sizeof (plat));
	platlen = strlen(plat) + 1;
	Preadauxvec(P);
	(void) Puname(P, &uts);
	if (Pzonename(P, zonename, sizeof (zonename)) == NULL)
		zonename[0] = '\0';

	/*
	 * The core file contents may required zero section headers, but if we
	 * overflow the 16 bits allotted to the program header count in the ELF
	 * header, we'll need that program header at index zero.
	 */
	if (nshdrs == 0 && nphdrs >= PN_XNUM)
		nshdrs = 1;

	/*
	 * Set up the ELF header.
	 */
	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
		Elf32_Ehdr ehdr;

		bzero(&ehdr, sizeof (ehdr));
		ehdr.e_ident[EI_MAG0] = ELFMAG0;
		ehdr.e_ident[EI_MAG1] = ELFMAG1;
		ehdr.e_ident[EI_MAG2] = ELFMAG2;
		ehdr.e_ident[EI_MAG3] = ELFMAG3;
		ehdr.e_type = ET_CORE;

		ehdr.e_ident[EI_CLASS] = ELFCLASS32;
#if defined(__sparc)
		ehdr.e_machine = EM_SPARC;
		ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
#elif defined(__i386) || defined(__amd64)
		ehdr.e_machine = EM_386;
		ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
#else
#error "unknown machine type"
#endif
		ehdr.e_ident[EI_VERSION] = EV_CURRENT;

		ehdr.e_version = EV_CURRENT;
		ehdr.e_ehsize = sizeof (ehdr);

		if (nphdrs >= PN_XNUM)
			ehdr.e_phnum = PN_XNUM;
		else
			ehdr.e_phnum = (unsigned short)nphdrs;

		ehdr.e_phentsize = sizeof (Elf32_Phdr);
		ehdr.e_phoff = ehdr.e_ehsize;

		if (nshdrs > 0) {
			if (nshdrs >= SHN_LORESERVE)
				ehdr.e_shnum = 0;
			else
				ehdr.e_shnum = (unsigned short)nshdrs;

			if (nshdrs - 1 >= SHN_LORESERVE)
				ehdr.e_shstrndx = SHN_XINDEX;
			else
				ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);

			ehdr.e_shentsize = sizeof (Elf32_Shdr);
			ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
		}

		if (gc_pwrite64(fd, &ehdr, sizeof (ehdr), 0) != 0)
			goto err;

		poff = ehdr.e_phoff;
		soff = ehdr.e_shoff;
		doff = boff = ehdr.e_ehsize +
		    ehdr.e_phentsize * nphdrs +
		    ehdr.e_shentsize * nshdrs;

#ifdef _LP64
	} else {
		Elf64_Ehdr ehdr;

		bzero(&ehdr, sizeof (ehdr));
		ehdr.e_ident[EI_MAG0] = ELFMAG0;
		ehdr.e_ident[EI_MAG1] = ELFMAG1;
		ehdr.e_ident[EI_MAG2] = ELFMAG2;
		ehdr.e_ident[EI_MAG3] = ELFMAG3;
		ehdr.e_type = ET_CORE;

		ehdr.e_ident[EI_CLASS] = ELFCLASS64;
#if defined(__sparc)
		ehdr.e_machine = EM_SPARCV9;
		ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
#elif defined(__i386) || defined(__amd64)
		ehdr.e_machine = EM_AMD64;
		ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
#else
#error "unknown machine type"
#endif
		ehdr.e_ident[EI_VERSION] = EV_CURRENT;

		ehdr.e_version = EV_CURRENT;
		ehdr.e_ehsize = sizeof (ehdr);

		if (nphdrs >= PN_XNUM)
			ehdr.e_phnum = PN_XNUM;
		else
			ehdr.e_phnum = (unsigned short)nphdrs;

		ehdr.e_phentsize = sizeof (Elf64_Phdr);
		ehdr.e_phoff = ehdr.e_ehsize;

		if (nshdrs > 0) {
			if (nshdrs >= SHN_LORESERVE)
				ehdr.e_shnum = 0;
			else
				ehdr.e_shnum = (unsigned short)nshdrs;

			if (nshdrs - 1 >= SHN_LORESERVE)
				ehdr.e_shstrndx = SHN_XINDEX;
			else
				ehdr.e_shstrndx = (unsigned short)(nshdrs - 1);

			ehdr.e_shentsize = sizeof (Elf64_Shdr);
			ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs;
		}

		if (gc_pwrite64(fd, &ehdr, sizeof (ehdr), 0) != 0)
			goto err;

		poff = ehdr.e_phoff;
		soff = ehdr.e_shoff;
		doff = boff = ehdr.e_ehsize +
		    ehdr.e_phentsize * nphdrs +
		    ehdr.e_shentsize * nshdrs;

#endif	/* _LP64 */
	}

	/*
	 * Write the zero indexed section if it exists.
	 */
	if (nshdrs > 0 && write_shdr(&pgc, STR_NONE, 0, 0, 0, 0,
	    nshdrs >= SHN_LORESERVE ? nshdrs : 0,
	    nshdrs - 1 >= SHN_LORESERVE ? nshdrs - 1 : 0,
	    nphdrs >= PN_XNUM ? nphdrs : 0, 0, 0) != 0)
		goto err;

	/*
	 * Construct the old-style note header and section.
	 */

	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
		prpsinfo_t prpsinfo;

		mkprpsinfo(P, &prpsinfo);
		if (write_note(fd, NT_PRPSINFO, &prpsinfo, sizeof (prpsinfo_t),
		    &doff) != 0) {
			goto err;
		}
		if (write_note(fd, NT_AUXV, P->auxv,
		    P->nauxv * sizeof (P->auxv[0]), &doff) != 0) {
			goto err;
		}
#ifdef _LP64
	} else {
		prpsinfo32_t pi32;
		auxv32_t *av32;
		size_t size = sizeof (auxv32_t) * P->nauxv;
		int i;

		mkprpsinfo32(P, &pi32);
		if (write_note(fd, NT_PRPSINFO, &pi32, sizeof (prpsinfo32_t),
		    &doff) != 0) {
			goto err;
		}

		if ((av32 = malloc(size)) == NULL)
			goto err;

		for (i = 0; i < P->nauxv; i++) {
			auxv_n_to_32(&P->auxv[i], &av32[i]);
		}

		if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) {
			free(av32);
			goto err;
		}

		free(av32);
#endif	/* _LP64 */
	}

	if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0)
		goto err;

	if (Plwp_iter_all(P, old_per_lwp, &pgc) != 0)
		goto err;

	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
		Elf32_Phdr phdr;

		bzero(&phdr, sizeof (phdr));
		phdr.p_type = PT_NOTE;
		phdr.p_flags = PF_R;
		phdr.p_offset = (Elf32_Off)boff;
		phdr.p_filesz = doff - boff;
		boff = doff;

		if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0)
			goto err;
		poff += sizeof (phdr);
#ifdef _LP64
	} else {
		Elf64_Phdr phdr;

		bzero(&phdr, sizeof (phdr));
		phdr.p_type = PT_NOTE;
		phdr.p_flags = PF_R;
		phdr.p_offset = boff;
		phdr.p_filesz = doff - boff;
		boff = doff;

		if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0)
			goto err;
		poff += sizeof (phdr);
#endif	/* _LP64 */
	}

	/*
	 * Construct the new-style note header and section.
	 */

	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
		if (write_note(fd, NT_PSINFO, &P->psinfo, sizeof (psinfo_t),
		    &doff) != 0) {
			goto err;
		}
		if (write_note(fd, NT_PSTATUS, &P->status, sizeof (pstatus_t),
		    &doff) != 0) {
			goto err;
		}
		if (write_note(fd, NT_AUXV, P->auxv,
		    P->nauxv * sizeof (P->auxv[0]), &doff) != 0) {
			goto err;
		}
#ifdef _LP64
	} else {
		psinfo32_t pi32;
		pstatus32_t ps32;
		auxv32_t *av32;
		size_t size = sizeof (auxv32_t) * P->nauxv;
		int i;

		psinfo_n_to_32(&P->psinfo, &pi32);
		if (write_note(fd, NT_PSINFO, &pi32, sizeof (psinfo32_t),
		    &doff) != 0) {
			goto err;
		}
		pstatus_n_to_32(&P->status, &ps32);
		if (write_note(fd, NT_PSTATUS, &ps32, sizeof (pstatus32_t),
		    &doff) != 0) {
			goto err;
		}
		if ((av32 = malloc(size)) == NULL)
			goto err;

		for (i = 0; i < P->nauxv; i++) {
			auxv_n_to_32(&P->auxv[i], &av32[i]);
		}

		if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) {
			free(av32);
			goto err;
		}

		free(av32);
#endif	/* _LP64 */
	}

	if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0 ||
	    write_note(fd, NT_UTSNAME, &uts, sizeof (uts), &doff) != 0 ||
	    write_note(fd, NT_CONTENT, &content, sizeof (content), &doff) != 0)
		goto err;

	{
		prcred_t cred, *cp;
		size_t size = sizeof (prcred_t);

		if (Pcred(P, &cred, 0) != 0)
			goto err;

		if (cred.pr_ngroups > 0)
			size += sizeof (gid_t) * (cred.pr_ngroups - 1);
		if ((cp = malloc(size)) == NULL)
			goto err;

		if (Pcred(P, cp, cred.pr_ngroups) != 0 ||
		    write_note(fd, NT_PRCRED, cp, size, &doff) != 0) {
			free(cp);
			goto err;
		}

		free(cp);
	}

	{
		prpriv_t *ppriv = NULL;
		const priv_impl_info_t *pinfo;
		size_t pprivsz, pinfosz;

		if (Ppriv(P, &ppriv) == -1)
			goto err;
		pprivsz = PRIV_PRPRIV_SIZE(ppriv);

		if (write_note(fd, NT_PRPRIV, ppriv, pprivsz, &doff) != 0) {
			Ppriv_free(P, ppriv);
			goto err;
		}
		Ppriv_free(P, ppriv);

		if ((pinfo = getprivimplinfo()) == NULL)
			goto err;
		pinfosz = PRIV_IMPL_INFO_SIZE(pinfo);

		if (write_note(fd, NT_PRPRIVINFO, pinfo, pinfosz, &doff) != 0)
			goto err;
	}

	if (write_note(fd, NT_ZONENAME, zonename, strlen(zonename) + 1,
	    &doff) != 0)
		goto err;

	{
		fditer_t iter;
		iter.fd_fd = fd;
		iter.fd_doff = &doff;

		if (Pfdinfo_iter(P, iter_fd, &iter) != 0)
			goto err;
	}


	{
		prsecflags_t *psf = NULL;

		if (Psecflags(P, &psf) != 0)
			goto err;

		if (write_note(fd, NT_SECFLAGS, psf,
		    sizeof (prsecflags_t), &doff) != 0) {
			Psecflags_free(psf);
			goto err;
		}

		Psecflags_free(psf);
	}

#if defined(__i386) || defined(__amd64)
	/* CSTYLED */
	{
		struct ssd *ldtp;
		size_t size;
		int nldt;

		/*
		 * Only dump out non-zero sized LDT notes.
		 */
		if ((nldt = Pldt(P, NULL, 0)) != 0) {
			size = sizeof (struct ssd) * nldt;
			if ((ldtp = malloc(size)) == NULL)
				goto err;

			if (Pldt(P, ldtp, nldt) == -1 ||
			    write_note(fd, NT_LDT, ldtp, size, &doff) != 0) {
				free(ldtp);
				goto err;
			}

			free(ldtp);
		}
	}
#endif	/* __i386 || __amd64 */

	if (Plwp_iter_all(P, new_per_lwp, &pgc) != 0)
		goto err;

	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
		Elf32_Phdr phdr;

		bzero(&phdr, sizeof (phdr));
		phdr.p_type = PT_NOTE;
		phdr.p_flags = PF_R;
		phdr.p_offset = (Elf32_Off)boff;
		phdr.p_filesz = doff - boff;
		boff = doff;

		if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0)
			goto err;
		poff += sizeof (phdr);
#ifdef _LP64
	} else {
		Elf64_Phdr phdr;

		bzero(&phdr, sizeof (phdr));
		phdr.p_type = PT_NOTE;
		phdr.p_flags = PF_R;
		phdr.p_offset = boff;
		phdr.p_filesz = doff - boff;
		boff = doff;

		if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0)
			goto err;
		poff += sizeof (phdr);
#endif	/* _LP64 */
	}

	/*
	 * Construct the headers for each mapping and write out its data
	 * if the content parameter indicates that it should be present
	 * in the core file.
	 */
	if (Pmapping_iter(P, dump_map, &pgc) != 0)
		goto err;

	if (dump_sections(&pgc) != 0)
		goto err;

	if (write_shstrtab(P, &pgc) != 0)
		goto err;

	free(pgc.pgc_chunk);

	return (0);

err:
	/*
	 * Wipe out anything we may have written if there was an error.
	 */
	(void) ftruncate64(fd, 0);
	free(pgc.pgc_chunk);

	return (-1);
}