Revert r324358, some cruft when in with it, it will be
properly reimported in another commit
This commit is contained in:
parent
cd98c7fb86
commit
f3badd8150
@ -1,11 +0,0 @@
|
||||
|
||||
PROG= ctfdump
|
||||
SRCS= ctfdump.c elf.c
|
||||
|
||||
CFLAGS+= -W -Wall -Wstrict-prototypes -Wno-unused -Wunused-variable
|
||||
|
||||
CFLAGS+= -DZLIB
|
||||
LDADD+= -lz
|
||||
DPADD+= ${LIBZ}
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,53 +0,0 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate$
|
||||
.Dt CTFDUMP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ctfdump
|
||||
.Nd display CTF information
|
||||
.Sh SYNOPSIS
|
||||
.Nm ctfdump
|
||||
.Op Fl dfhlst
|
||||
file ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility display CTF information from the
|
||||
.Dv \.SUNW_ctf
|
||||
section of an
|
||||
.Xr elf 5
|
||||
file or from a raw CTF file.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d
|
||||
Display the object section.
|
||||
.It Fl f
|
||||
Display the function section.
|
||||
.It Fl h
|
||||
Dump the CTF header.
|
||||
.It Fl l
|
||||
Display the label section.
|
||||
.It Fl s
|
||||
Display the string table.
|
||||
.It Fl t
|
||||
Display the type section.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std ctfdump
|
||||
.Sh SEE ALSO
|
||||
.Xr elf 5
|
@ -1,638 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/elf.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ctf.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef ZLIB
|
||||
#include <zlib.h>
|
||||
#endif /* ZLIB */
|
||||
|
||||
#ifndef nitems
|
||||
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
|
||||
#endif
|
||||
|
||||
#ifndef ELF_STRTAB
|
||||
#define ELF_STRTAB ".strtab"
|
||||
#endif
|
||||
#ifndef ELF_CTF
|
||||
#define ELF_CTF ".SUNW_ctf"
|
||||
#endif
|
||||
|
||||
#define DUMP_OBJECT (1 << 0)
|
||||
#define DUMP_FUNCTION (1 << 1)
|
||||
#define DUMP_HEADER (1 << 2)
|
||||
#define DUMP_LABEL (1 << 3)
|
||||
#define DUMP_STRTAB (1 << 4)
|
||||
#define DUMP_STATISTIC (1 << 5)
|
||||
#define DUMP_TYPE (1 << 6)
|
||||
|
||||
int dump(const char *, uint8_t);
|
||||
int isctf(const char *, size_t);
|
||||
__dead2 void usage(void);
|
||||
|
||||
int ctf_dump(const char *, size_t, uint8_t);
|
||||
uint32_t ctf_dump_type(struct ctf_header *, const char *, off_t,
|
||||
uint32_t, uint32_t);
|
||||
const char *ctf_kind2name(uint16_t);
|
||||
const char *ctf_enc2name(uint16_t);
|
||||
const char *ctf_off2name(struct ctf_header *, const char *, off_t,
|
||||
uint32_t);
|
||||
|
||||
int elf_dump(char *, size_t, uint8_t);
|
||||
const char *elf_idx2sym(size_t *, uint8_t);
|
||||
|
||||
/* elf.c */
|
||||
int iself(const char *, size_t);
|
||||
int elf_getshstab(const char *, size_t, const char **, size_t *);
|
||||
ssize_t elf_getsymtab(const char *, const char *, size_t,
|
||||
const Elf_Sym **, size_t *);
|
||||
ssize_t elf_getsection(char *, const char *, const char *,
|
||||
size_t, const char **, size_t *);
|
||||
|
||||
char *decompress(const char *, size_t, size_t);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *filename;
|
||||
uint8_t flags = 0;
|
||||
int ch, error = 0;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
while ((ch = getopt(argc, argv, "dfhlst")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
flags |= DUMP_OBJECT;
|
||||
break;
|
||||
case 'f':
|
||||
flags |= DUMP_FUNCTION;
|
||||
break;
|
||||
case 'h':
|
||||
flags |= DUMP_HEADER;
|
||||
break;
|
||||
case 'l':
|
||||
flags |= DUMP_LABEL;
|
||||
break;
|
||||
case 's':
|
||||
flags |= DUMP_STRTAB;
|
||||
break;
|
||||
case 't':
|
||||
flags |= DUMP_TYPE;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc <= 0)
|
||||
usage();
|
||||
|
||||
/* Dump everything by default */
|
||||
if (flags == 0)
|
||||
flags = 0xff;
|
||||
|
||||
while ((filename = *argv++) != NULL)
|
||||
error |= dump(filename, flags);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
dump(const char *path, uint8_t flags)
|
||||
{
|
||||
struct stat st;
|
||||
int fd, error = 1;
|
||||
char *p;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
warn("open");
|
||||
return 1;
|
||||
}
|
||||
if (fstat(fd, &st) == -1) {
|
||||
warn("fstat");
|
||||
return 1;
|
||||
}
|
||||
if ((uintmax_t)st.st_size > SIZE_MAX) {
|
||||
warnx("file too big to fit memory");
|
||||
return 1;
|
||||
}
|
||||
|
||||
p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (p == MAP_FAILED)
|
||||
err(1, "mmap");
|
||||
|
||||
if (iself(p, st.st_size)) {
|
||||
error = elf_dump(p, st.st_size, flags);
|
||||
} else if (isctf(p, st.st_size)) {
|
||||
error = ctf_dump(p, st.st_size, flags);
|
||||
}
|
||||
|
||||
munmap(p, st.st_size);
|
||||
close(fd);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
const char *strtab;
|
||||
const Elf_Sym *symtab;
|
||||
size_t strtabsz, nsymb;
|
||||
|
||||
const char *
|
||||
elf_idx2sym(size_t *idx, uint8_t type)
|
||||
{
|
||||
const Elf_Sym *st;
|
||||
size_t i;
|
||||
|
||||
for (i = *idx + 1; i < nsymb; i++) {
|
||||
st = &symtab[i];
|
||||
|
||||
if (ELF_ST_TYPE(st->st_info) != type)
|
||||
continue;
|
||||
|
||||
*idx = i;
|
||||
return strtab + st->st_name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
elf_dump(char *p, size_t filesize, uint8_t flags)
|
||||
{
|
||||
Elf_Ehdr *eh = (Elf_Ehdr *)p;
|
||||
Elf_Shdr *sh;
|
||||
const char *shstab;
|
||||
size_t i, shstabsz;
|
||||
|
||||
/* Find section header string table location and size. */
|
||||
if (elf_getshstab(p, filesize, &shstab, &shstabsz))
|
||||
return 1;
|
||||
|
||||
/* Find symbol table location and number of symbols. */
|
||||
if (elf_getsymtab(p, shstab, shstabsz, &symtab, &nsymb) == -1)
|
||||
warnx("symbol table not found");
|
||||
|
||||
/* Find string table location and size. */
|
||||
if (elf_getsection(p, ELF_STRTAB, shstab, shstabsz, &strtab,
|
||||
&strtabsz) == -1)
|
||||
warnx("string table not found");
|
||||
|
||||
/* Find CTF section and dump it. */
|
||||
for (i = 0; i < eh->e_shnum; i++) {
|
||||
sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
|
||||
|
||||
if ((sh->sh_link >= eh->e_shnum) ||
|
||||
(sh->sh_name >= shstabsz))
|
||||
continue;
|
||||
|
||||
if (strncmp(shstab + sh->sh_name, ELF_CTF, strlen(ELF_CTF)))
|
||||
continue;
|
||||
|
||||
if (!isctf(p + sh->sh_offset, sh->sh_size))
|
||||
break;
|
||||
|
||||
return ctf_dump(p + sh->sh_offset, sh->sh_size, flags);
|
||||
}
|
||||
|
||||
warnx("%s section not found", ELF_CTF);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
isctf(const char *p, size_t filesize)
|
||||
{
|
||||
struct ctf_header *cth = (struct ctf_header *)p;
|
||||
size_t dlen;
|
||||
|
||||
if (filesize < sizeof(struct ctf_header)) {
|
||||
warnx("file too small to be CTF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cth->cth_magic != CTF_MAGIC || cth->cth_version != CTF_VERSION)
|
||||
return 0;
|
||||
|
||||
dlen = cth->cth_stroff + cth->cth_strlen;
|
||||
if (dlen > filesize && !(cth->cth_flags & CTF_F_COMPRESS)) {
|
||||
warnx("bogus file size");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((cth->cth_lbloff & 3) || (cth->cth_objtoff & 1) ||
|
||||
(cth->cth_funcoff & 1) || (cth->cth_typeoff & 3)) {
|
||||
warnx("wrongly aligned offset");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((cth->cth_lbloff >= dlen) || (cth->cth_objtoff >= dlen) ||
|
||||
(cth->cth_funcoff >= dlen) || (cth->cth_typeoff >= dlen)) {
|
||||
warnx("truncated file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((cth->cth_lbloff > cth->cth_objtoff) ||
|
||||
(cth->cth_objtoff > cth->cth_funcoff) ||
|
||||
(cth->cth_funcoff > cth->cth_typeoff) ||
|
||||
(cth->cth_typeoff > cth->cth_stroff)) {
|
||||
warnx("corrupted file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
ctf_dump(const char *p, size_t size, uint8_t flags)
|
||||
{
|
||||
struct ctf_header *cth = (struct ctf_header *)p;
|
||||
off_t dlen = cth->cth_stroff + cth->cth_strlen;
|
||||
char *data;
|
||||
|
||||
if (cth->cth_flags & CTF_F_COMPRESS) {
|
||||
data = decompress(p + sizeof(*cth), size - sizeof(*cth), dlen);
|
||||
if (data == NULL)
|
||||
return 1;
|
||||
} else {
|
||||
data = (char *)p + sizeof(*cth);
|
||||
}
|
||||
|
||||
if (flags & DUMP_HEADER) {
|
||||
printf(" cth_magic = 0x%04x\n", cth->cth_magic);
|
||||
printf(" cth_version = %d\n", cth->cth_version);
|
||||
printf(" cth_flags = 0x%02x\n", cth->cth_flags);
|
||||
printf(" cth_parlabel = %s\n",
|
||||
ctf_off2name(cth, data, dlen, cth->cth_parname));
|
||||
printf(" cth_parname = %s\n",
|
||||
ctf_off2name(cth, data, dlen, cth->cth_parname));
|
||||
printf(" cth_lbloff = %d\n", cth->cth_lbloff);
|
||||
printf(" cth_objtoff = %d\n", cth->cth_objtoff);
|
||||
printf(" cth_funcoff = %d\n", cth->cth_funcoff);
|
||||
printf(" cth_typeoff = %d\n", cth->cth_typeoff);
|
||||
printf(" cth_stroff = %d\n", cth->cth_stroff);
|
||||
printf(" cth_strlen = %d\n", cth->cth_strlen);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (flags & DUMP_LABEL) {
|
||||
uint32_t lbloff = cth->cth_lbloff;
|
||||
struct ctf_lblent *ctl;
|
||||
|
||||
while (lbloff < cth->cth_objtoff) {
|
||||
ctl = (struct ctf_lblent *)(data + lbloff);
|
||||
|
||||
printf(" %5u %s\n", ctl->ctl_typeidx,
|
||||
ctf_off2name(cth, data, dlen, ctl->ctl_label));
|
||||
|
||||
lbloff += sizeof(*ctl);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (flags & DUMP_OBJECT) {
|
||||
uint32_t objtoff = cth->cth_objtoff;
|
||||
size_t idx = 0, i = 0;
|
||||
uint16_t *dsp;
|
||||
const char *s;
|
||||
int l;
|
||||
|
||||
while (objtoff < cth->cth_funcoff) {
|
||||
dsp = (uint16_t *)(data + objtoff);
|
||||
|
||||
l = printf(" [%zu] %u", i++, *dsp);
|
||||
if ((s = elf_idx2sym(&idx, STT_OBJECT)) != NULL)
|
||||
printf("%*s %s (%zu)\n", (14 - l), "", s, idx);
|
||||
else
|
||||
printf("\n");
|
||||
|
||||
objtoff += sizeof(*dsp);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (flags & DUMP_FUNCTION) {
|
||||
uint16_t *fsp, kind, vlen;
|
||||
size_t idx = 0, i = -1;
|
||||
const char *s;
|
||||
int l;
|
||||
|
||||
fsp = (uint16_t *)(data + cth->cth_funcoff);
|
||||
while (fsp < (uint16_t *)(data + cth->cth_typeoff)) {
|
||||
kind = CTF_INFO_KIND(*fsp);
|
||||
vlen = CTF_INFO_VLEN(*fsp);
|
||||
s = elf_idx2sym(&idx, STT_FUNC);
|
||||
fsp++;
|
||||
i++;
|
||||
|
||||
if (kind == CTF_K_UNKNOWN && vlen == 0)
|
||||
continue;
|
||||
|
||||
l = printf(" [%zu] FUNC ", i);
|
||||
if (s != NULL)
|
||||
printf("(%s)", s);
|
||||
printf(" returns: %u args: (", *fsp++);
|
||||
while (vlen-- > 0)
|
||||
printf("%u%s", *fsp++, (vlen > 0) ? ", " : "");
|
||||
printf(")\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (flags & DUMP_TYPE) {
|
||||
uint32_t idx = 1, offset = cth->cth_typeoff;
|
||||
|
||||
while (offset < cth->cth_stroff) {
|
||||
offset += ctf_dump_type(cth, data, dlen, offset, idx++);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (flags & DUMP_STRTAB) {
|
||||
uint32_t offset = 0;
|
||||
const char *str;
|
||||
|
||||
while (offset < cth->cth_strlen) {
|
||||
str = ctf_off2name(cth, data, dlen, offset);
|
||||
|
||||
printf(" [%u] ", offset);
|
||||
if (strcmp(str, "(anon)"))
|
||||
offset += printf("%s\n", str);
|
||||
else {
|
||||
printf("\\0\n");
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (cth->cth_flags & CTF_F_COMPRESS)
|
||||
free(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ctf_dump_type(struct ctf_header *cth, const char *data, off_t dlen,
|
||||
uint32_t offset, uint32_t idx)
|
||||
{
|
||||
const char *p = data + offset;
|
||||
const struct ctf_type *ctt = (struct ctf_type *)p;
|
||||
const struct ctf_array *cta;
|
||||
uint16_t *argp, i, kind, vlen, root;
|
||||
uint32_t eob, toff;
|
||||
uint64_t size;
|
||||
const char *name, *kname;
|
||||
|
||||
kind = CTF_INFO_KIND(ctt->ctt_info);
|
||||
vlen = CTF_INFO_VLEN(ctt->ctt_info);
|
||||
root = CTF_INFO_ISROOT(ctt->ctt_info);
|
||||
name = ctf_off2name(cth, data, dlen, ctt->ctt_name);
|
||||
|
||||
if (root)
|
||||
printf(" <%u> ", idx);
|
||||
else
|
||||
printf(" [%u] ", idx);
|
||||
|
||||
if ((kname = ctf_kind2name(kind)) != NULL)
|
||||
printf("%s %s", kname, name);
|
||||
|
||||
if (ctt->ctt_size <= CTF_MAX_SIZE) {
|
||||
size = ctt->ctt_size;
|
||||
toff = sizeof(struct ctf_stype);
|
||||
} else {
|
||||
size = CTF_TYPE_LSIZE(ctt);
|
||||
toff = sizeof(struct ctf_type);
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case CTF_K_UNKNOWN:
|
||||
case CTF_K_FORWARD:
|
||||
break;
|
||||
case CTF_K_INTEGER:
|
||||
eob = *((uint32_t *)(p + toff));
|
||||
toff += sizeof(uint32_t);
|
||||
printf(" encoding=%s offset=%u bits=%u",
|
||||
ctf_enc2name(CTF_INT_ENCODING(eob)), CTF_INT_OFFSET(eob),
|
||||
CTF_INT_BITS(eob));
|
||||
break;
|
||||
case CTF_K_FLOAT:
|
||||
eob = *((uint32_t *)(p + toff));
|
||||
toff += sizeof(uint32_t);
|
||||
printf(" encoding=0x%x offset=%u bits=%u",
|
||||
CTF_FP_ENCODING(eob), CTF_FP_OFFSET(eob), CTF_FP_BITS(eob));
|
||||
break;
|
||||
case CTF_K_ARRAY:
|
||||
cta = (struct ctf_array *)(p + toff);
|
||||
printf(" content: %u index: %u nelems: %u\n", cta->cta_contents,
|
||||
cta->cta_index, cta->cta_nelems);
|
||||
toff += sizeof(struct ctf_array);
|
||||
break;
|
||||
case CTF_K_FUNCTION:
|
||||
argp = (uint16_t *)(p + toff);
|
||||
printf(" returns: %u args: (%u", ctt->ctt_type, *argp);
|
||||
for (i = 1; i < vlen; i++) {
|
||||
argp++;
|
||||
printf(", %u", *argp);
|
||||
}
|
||||
printf(")");
|
||||
toff += (vlen + (vlen & 1)) * sizeof(uint16_t);
|
||||
break;
|
||||
case CTF_K_STRUCT:
|
||||
case CTF_K_UNION:
|
||||
printf(" (%lu bytes)\n", size);
|
||||
|
||||
if (size < CTF_LSTRUCT_THRESH) {
|
||||
for (i = 0; i < vlen; i++) {
|
||||
struct ctf_member *ctm;
|
||||
|
||||
ctm = (struct ctf_member *)(p + toff);
|
||||
toff += sizeof(struct ctf_member);
|
||||
|
||||
printf("\t%s type=%u off=%u\n",
|
||||
ctf_off2name(cth, data, dlen,
|
||||
ctm->ctm_name),
|
||||
ctm->ctm_type, ctm->ctm_offset);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < vlen; i++) {
|
||||
struct ctf_lmember *ctlm;
|
||||
|
||||
ctlm = (struct ctf_lmember *)(p + toff);
|
||||
toff += sizeof(struct ctf_lmember);
|
||||
|
||||
printf("\t%s type=%u off=%zu\n",
|
||||
ctf_off2name(cth, data, dlen,
|
||||
ctlm->ctlm_name),
|
||||
ctlm->ctlm_type, CTF_LMEM_OFFSET(ctlm));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CTF_K_ENUM:
|
||||
printf("\n");
|
||||
for (i = 0; i < vlen; i++) {
|
||||
struct ctf_enum *cte;
|
||||
|
||||
cte = (struct ctf_enum *)(p + toff);
|
||||
toff += sizeof(struct ctf_enum);
|
||||
|
||||
printf("\t%s = %d\n",
|
||||
ctf_off2name(cth, data, dlen, cte->cte_name),
|
||||
cte->cte_value);
|
||||
}
|
||||
break;
|
||||
case CTF_K_POINTER:
|
||||
case CTF_K_TYPEDEF:
|
||||
case CTF_K_VOLATILE:
|
||||
case CTF_K_CONST:
|
||||
case CTF_K_RESTRICT:
|
||||
printf(" refers to %u", ctt->ctt_type);
|
||||
break;
|
||||
default:
|
||||
errx(1, "incorrect type %u at offset %u", kind, offset);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return toff;
|
||||
}
|
||||
|
||||
const char *
|
||||
ctf_kind2name(uint16_t kind)
|
||||
{
|
||||
static const char *kind_name[] = { NULL, "INTEGER", "FLOAT", "POINTER",
|
||||
"ARRAY", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD",
|
||||
"TYPEDEF", "VOLATILE", "CONST", "RESTRICT" };
|
||||
|
||||
if (kind >= nitems(kind_name))
|
||||
return NULL;
|
||||
|
||||
return kind_name[kind];
|
||||
}
|
||||
|
||||
const char *
|
||||
ctf_enc2name(uint16_t enc)
|
||||
{
|
||||
static const char *enc_name[] = { "SIGNED", "CHAR", "SIGNED CHAR",
|
||||
"BOOL", "SIGNED BOOL" };
|
||||
static char invalid[7];
|
||||
|
||||
if (enc == CTF_INT_VARARGS)
|
||||
return "VARARGS";
|
||||
|
||||
if (enc > 0 && enc < nitems(enc_name))
|
||||
return enc_name[enc - 1];
|
||||
|
||||
snprintf(invalid, sizeof(invalid), "0x%x", enc);
|
||||
return invalid;
|
||||
}
|
||||
|
||||
const char *
|
||||
ctf_off2name(struct ctf_header *cth, const char *data, off_t dlen,
|
||||
uint32_t offset)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
if (CTF_NAME_STID(offset) != CTF_STRTAB_0)
|
||||
return "external";
|
||||
|
||||
if (CTF_NAME_OFFSET(offset) >= cth->cth_strlen)
|
||||
return "exceeds strlab";
|
||||
|
||||
if (cth->cth_stroff + CTF_NAME_OFFSET(offset) >= dlen)
|
||||
return "invalid";
|
||||
|
||||
name = data + cth->cth_stroff + CTF_NAME_OFFSET(offset);
|
||||
if (*name == '\0')
|
||||
return "(anon)";
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
char *
|
||||
decompress(const char *buf, size_t size, size_t len)
|
||||
{
|
||||
#ifdef ZLIB
|
||||
z_stream stream;
|
||||
char *data;
|
||||
int error;
|
||||
|
||||
data = malloc(len);
|
||||
if (data == NULL) {
|
||||
warn(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
stream.next_in = (void *)buf;
|
||||
stream.avail_in = size;
|
||||
stream.next_out = (uint8_t *)data;
|
||||
stream.avail_out = len;
|
||||
|
||||
if ((error = inflateInit(&stream)) != Z_OK) {
|
||||
warnx("zlib inflateInit failed: %s", zError(error));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
|
||||
warnx("zlib inflate failed: %s", zError(error));
|
||||
inflateEnd(&stream);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((error = inflateEnd(&stream)) != Z_OK) {
|
||||
warnx("zlib inflateEnd failed: %s", zError(error));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (stream.total_out != len) {
|
||||
warnx("decompression failed: %zu != %zu",
|
||||
stream.total_out, len);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
exit:
|
||||
free(data);
|
||||
#endif /* ZLIB */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__dead2 void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-dfhlst] file ...\n",
|
||||
getprogname());
|
||||
exit(1);
|
||||
}
|
@ -1,287 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/elf.h>
|
||||
|
||||
#include <machine/reloc.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ELF_SYMTAB ".symtab"
|
||||
#define Elf_RelA __CONCAT(__CONCAT(Elf,__ELF_WORD_SIZE),_Rela)
|
||||
|
||||
static int elf_reloc_size(unsigned long);
|
||||
static void elf_reloc_apply(const char *, const char *, size_t, ssize_t,
|
||||
char *, size_t);
|
||||
|
||||
int
|
||||
iself(const char *p, size_t filesize)
|
||||
{
|
||||
Elf_Ehdr *eh = (Elf_Ehdr *)p;
|
||||
|
||||
if (filesize < (off_t)sizeof(Elf_Ehdr)) {
|
||||
warnx("file too small to be ELF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (eh->e_ehsize < sizeof(Elf_Ehdr) || !IS_ELF(*eh))
|
||||
return 0;
|
||||
|
||||
if (eh->e_ident[EI_CLASS] != ELF_CLASS) {
|
||||
warnx("unexpected word size %u", eh->e_ident[EI_CLASS]);
|
||||
return 0;
|
||||
}
|
||||
if (eh->e_ident[EI_VERSION] != ELF_TARG_VER) {
|
||||
warnx("unexpected version %u", eh->e_ident[EI_VERSION]);
|
||||
return 0;
|
||||
}
|
||||
if (eh->e_ident[EI_DATA] > ELFDATA2MSB) {
|
||||
warnx("unexpected data format %u", eh->e_ident[EI_DATA]);
|
||||
return 0;
|
||||
}
|
||||
if (eh->e_shoff > filesize) {
|
||||
warnx("bogus section table offset 0x%lx", (off_t)eh->e_shoff);
|
||||
return 0;
|
||||
}
|
||||
if (eh->e_shentsize < sizeof(Elf_Shdr)) {
|
||||
warnx("bogus section header size %u", eh->e_shentsize);
|
||||
return 0;
|
||||
}
|
||||
if (eh->e_shnum > (filesize - eh->e_shoff) / eh->e_shentsize) {
|
||||
warnx("bogus section header count %u", eh->e_shnum);
|
||||
return 0;
|
||||
}
|
||||
if (eh->e_shstrndx >= eh->e_shnum) {
|
||||
warnx("bogus string table index %u", eh->e_shstrndx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
elf_getshstab(const char *p, size_t filesize, const char **shstab,
|
||||
size_t *shstabsize)
|
||||
{
|
||||
Elf_Ehdr *eh = (Elf_Ehdr *)p;
|
||||
Elf_Shdr *sh;
|
||||
|
||||
sh = (Elf_Shdr *)(p + eh->e_shoff + eh->e_shstrndx * eh->e_shentsize);
|
||||
if (sh->sh_type != SHT_STRTAB) {
|
||||
warnx("unexpected string table type");
|
||||
return -1;
|
||||
}
|
||||
if (sh->sh_offset > filesize) {
|
||||
warnx("bogus string table offset");
|
||||
return -1;
|
||||
}
|
||||
if (sh->sh_size > filesize - sh->sh_offset) {
|
||||
warnx("bogus string table size");
|
||||
return -1;
|
||||
}
|
||||
if (shstab != NULL)
|
||||
*shstab = p + sh->sh_offset;
|
||||
if (shstabsize != NULL)
|
||||
*shstabsize = sh->sh_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
elf_getsymtab(const char *p, const char *shstab, size_t shstabsz,
|
||||
const Elf_Sym **symtab, size_t *nsymb)
|
||||
{
|
||||
Elf_Ehdr *eh = (Elf_Ehdr *)p;
|
||||
Elf_Shdr *sh;
|
||||
size_t snlen;
|
||||
ssize_t i;
|
||||
|
||||
snlen = strlen(ELF_SYMTAB);
|
||||
|
||||
for (i = 0; i < eh->e_shnum; i++) {
|
||||
sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
|
||||
|
||||
if (sh->sh_type != SHT_SYMTAB)
|
||||
continue;
|
||||
|
||||
if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
|
||||
continue;
|
||||
|
||||
if (strncmp(shstab + sh->sh_name, ELF_SYMTAB, snlen) == 0) {
|
||||
if (symtab != NULL)
|
||||
*symtab = (Elf_Sym *)(p + sh->sh_offset);
|
||||
if (nsymb != NULL)
|
||||
*nsymb = (sh->sh_size / sh->sh_entsize);
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
elf_getsection(char *p, const char *sname, const char *shstab,
|
||||
size_t shstabsz, const char **psdata, size_t *pssz)
|
||||
{
|
||||
Elf_Ehdr *eh = (Elf_Ehdr *)p;
|
||||
Elf_Shdr *sh;
|
||||
char *sdata = NULL;
|
||||
size_t snlen, ssz = 0;
|
||||
ssize_t sidx, i;
|
||||
|
||||
snlen = strlen(sname);
|
||||
if (snlen == 0)
|
||||
return -1;
|
||||
|
||||
/* Find the given section. */
|
||||
for (i = 0; i < eh->e_shnum; i++) {
|
||||
sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
|
||||
|
||||
if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
|
||||
continue;
|
||||
|
||||
if (strncmp(shstab + sh->sh_name, sname, snlen) == 0) {
|
||||
sidx = i;
|
||||
sdata = p + sh->sh_offset;
|
||||
ssz = sh->sh_size;
|
||||
elf_reloc_apply(p, shstab, shstabsz, sidx, sdata, ssz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sdata == NULL)
|
||||
return -1;
|
||||
|
||||
if (psdata != NULL)
|
||||
*psdata = sdata;
|
||||
if (pssz != NULL)
|
||||
*pssz = ssz;
|
||||
|
||||
return sidx;
|
||||
}
|
||||
|
||||
static int
|
||||
elf_reloc_size(unsigned long type)
|
||||
{
|
||||
switch (type) {
|
||||
#ifdef R_X86_64_64
|
||||
case R_X86_64_64:
|
||||
return sizeof(uint64_t);
|
||||
#endif
|
||||
#ifdef R_X86_64_32
|
||||
case R_X86_64_32:
|
||||
return sizeof(uint32_t);
|
||||
#endif
|
||||
#ifdef RELOC_32
|
||||
case RELOC_32:
|
||||
return sizeof(uint32_t);
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define ELF_WRITE_RELOC(buf, val, rsize) \
|
||||
do { \
|
||||
if (rsize == 4) { \
|
||||
uint32_t v32 = val; \
|
||||
memcpy(buf, &v32, sizeof(v32)); \
|
||||
} else { \
|
||||
uint64_t v64 = val; \
|
||||
memcpy(buf, &v64, sizeof(v64)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
elf_reloc_apply(const char *p, const char *shstab, size_t shstabsz,
|
||||
ssize_t sidx, char *sdata, size_t ssz)
|
||||
{
|
||||
Elf_Ehdr *eh = (Elf_Ehdr *)p;
|
||||
Elf_Shdr *sh;
|
||||
Elf_Rel *rel = NULL;
|
||||
Elf_RelA *rela = NULL;
|
||||
const Elf_Sym *symtab, *sym;
|
||||
ssize_t symtabidx;
|
||||
size_t nsymb, rsym, rtyp, roff;
|
||||
size_t i, j;
|
||||
uint64_t value;
|
||||
int rsize;
|
||||
|
||||
/* Find symbol table location and number of symbols. */
|
||||
symtabidx = elf_getsymtab(p, shstab, shstabsz, &symtab, &nsymb);
|
||||
if (symtabidx == -1) {
|
||||
warnx("symbol table not found");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Apply possible relocation. */
|
||||
for (i = 0; i < eh->e_shnum; i++) {
|
||||
sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
|
||||
|
||||
if (sh->sh_size == 0)
|
||||
continue;
|
||||
|
||||
if ((sh->sh_info != sidx) || (sh->sh_link != symtabidx))
|
||||
continue;
|
||||
|
||||
switch (sh->sh_type) {
|
||||
case SHT_RELA:
|
||||
rela = (Elf_RelA *)(p + sh->sh_offset);
|
||||
for (j = 0; j < (sh->sh_size / sizeof(Elf_RelA)); j++) {
|
||||
rsym = ELF_R_SYM(rela[j].r_info);
|
||||
rtyp = ELF_R_TYPE(rela[j].r_info);
|
||||
roff = rela[j].r_offset;
|
||||
if (rsym >= nsymb)
|
||||
continue;
|
||||
sym = &symtab[rsym];
|
||||
value = sym->st_value + rela[j].r_addend;
|
||||
|
||||
rsize = elf_reloc_size(rtyp);
|
||||
if (rsize == -1 || roff + rsize >= ssz)
|
||||
continue;
|
||||
|
||||
ELF_WRITE_RELOC(sdata + roff, value, rsize);
|
||||
}
|
||||
break;
|
||||
case SHT_REL:
|
||||
rel = (Elf_Rel *)(p + sh->sh_offset);
|
||||
for (j = 0; j < (sh->sh_size / sizeof(Elf_Rel)); j++) {
|
||||
rsym = ELF_R_SYM(rel[j].r_info);
|
||||
rtyp = ELF_R_TYPE(rel[j].r_info);
|
||||
roff = rel[j].r_offset;
|
||||
if (rsym >= nsymb)
|
||||
continue;
|
||||
sym = &symtab[rsym];
|
||||
value = sym->st_value;
|
||||
|
||||
rsize = elf_reloc_size(rtyp);
|
||||
if (rsize == -1 || roff + rsize >= ssz)
|
||||
continue;
|
||||
|
||||
ELF_WRITE_RELOC(sdata + roff, value, rsize);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
VERSION = 1.14.3
|
||||
VERSION = 1.14.2
|
||||
|
||||
# === LIST OF FILES ====================================================
|
||||
|
||||
|
@ -2,21 +2,6 @@ $Id: NEWS,v 1.26 2017/07/28 14:57:56 schwarze Exp $
|
||||
|
||||
This file lists the most important changes in the mandoc.bsd.lv distribution.
|
||||
|
||||
Changes in version 1.14.3, released on August 5, 2017
|
||||
|
||||
--- BUG FIXES ---
|
||||
* man(7): Do not crash with out-of-bounds read access to a constant
|
||||
array if .sp or a blank line immediately precedes .SS or .SH.
|
||||
* mdoc(7): Do not crash with out-of-bounds read access to a constant
|
||||
array if .sp or a blank line precede the first .Sh macro.
|
||||
* tbl(7): Ignore explicitly specified negative column widths rather than
|
||||
wrapping around to huge numbers and risking memory exhaustion.
|
||||
* man(1): No longer use names that only occur in the SYNOPSIS section.
|
||||
Gets rid of some surprising behaviour and bogus warnings.
|
||||
--- THANKS TO ---
|
||||
Leah Neukirchen (Void Linux), Markus Waldeck (Debian),
|
||||
Peter Bui (nd.edu), and Yuri Pankov (illumos) for bug reports.
|
||||
|
||||
Changes in version 1.14.2, released on July 28, 2017
|
||||
|
||||
--- MAJOR NEW FEATURES ---
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: man_term.c,v 1.209 2017/07/31 15:19:06 schwarze Exp $ */
|
||||
/* $Id: man_term.c,v 1.208 2017/06/25 11:42:02 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -673,7 +673,7 @@ pre_SS(DECL_ARGS)
|
||||
|
||||
do {
|
||||
n = n->prev;
|
||||
} while (n != NULL && n->tok >= MAN_TH &&
|
||||
} while (n != NULL && n->tok != TOKEN_NONE &&
|
||||
termacts[n->tok].flags & MAN_NOTEXT);
|
||||
if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL))
|
||||
break;
|
||||
@ -735,7 +735,7 @@ pre_SH(DECL_ARGS)
|
||||
|
||||
do {
|
||||
n = n->prev;
|
||||
} while (n != NULL && n->tok >= MAN_TH &&
|
||||
} while (n != NULL && n->tok != TOKEN_NONE &&
|
||||
termacts[n->tok].flags & MAN_NOTEXT);
|
||||
if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL))
|
||||
break;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: mansearch.c,v 1.76 2017/08/02 13:29:04 schwarze Exp $ */
|
||||
/* $OpenBSD: mansearch.c,v 1.50 2016/07/09 15:23:36 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -171,9 +171,7 @@ mansearch(const struct mansearch *search,
|
||||
page = dbm_page_get(rp->page);
|
||||
|
||||
if (lstmatch(search->sec, page->sect) == 0 ||
|
||||
lstmatch(search->arch, page->arch) == 0 ||
|
||||
(search->argmode == ARG_NAME &&
|
||||
rp->bits <= (int32_t)(NAME_SYN & NAME_MASK)))
|
||||
lstmatch(search->arch, page->arch) == 0)
|
||||
continue;
|
||||
|
||||
if (res == NULL) {
|
||||
@ -454,28 +452,14 @@ lstlen(const char *cp, size_t sep)
|
||||
{
|
||||
size_t sz;
|
||||
|
||||
for (sz = 0; *cp != '\0'; cp++) {
|
||||
|
||||
/* Skip names appearing only in the SYNOPSIS. */
|
||||
if (*cp <= (char)(NAME_SYN & NAME_MASK)) {
|
||||
while (*cp != '\0')
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip name class markers. */
|
||||
if (*cp < ' ')
|
||||
cp++;
|
||||
|
||||
/* Print a separator before each but the first string. */
|
||||
if (sz)
|
||||
sz += sep;
|
||||
|
||||
/* Copy one string. */
|
||||
while (*cp != '\0') {
|
||||
sz++;
|
||||
cp++;
|
||||
}
|
||||
for (sz = 0;; sz++) {
|
||||
if (cp[0] == '\0') {
|
||||
if (cp[1] == '\0')
|
||||
break;
|
||||
sz += sep - 1;
|
||||
} else if (cp[0] < ' ')
|
||||
sz--;
|
||||
cp++;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
@ -487,34 +471,19 @@ lstlen(const char *cp, size_t sep)
|
||||
static void
|
||||
lstcat(char *buf, size_t *i, const char *cp, const char *sep)
|
||||
{
|
||||
const char *s;
|
||||
size_t i_start;
|
||||
const char *s;
|
||||
|
||||
for (i_start = *i; *cp != '\0'; cp++) {
|
||||
|
||||
/* Skip names appearing only in the SYNOPSIS. */
|
||||
if (*cp <= (char)(NAME_SYN & NAME_MASK)) {
|
||||
while (*cp != '\0')
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip name class markers. */
|
||||
if (*cp < ' ')
|
||||
cp++;
|
||||
|
||||
/* Print a separator before each but the first string. */
|
||||
if (*i > i_start) {
|
||||
for (;;) {
|
||||
if (cp[0] == '\0') {
|
||||
if (cp[1] == '\0')
|
||||
break;
|
||||
s = sep;
|
||||
while (*s != '\0')
|
||||
buf[(*i)++] = *s++;
|
||||
}
|
||||
|
||||
/* Copy one string. */
|
||||
while (*cp != '\0')
|
||||
buf[(*i)++] = *cp++;
|
||||
} else if (cp[0] >= ' ')
|
||||
buf[(*i)++] = cp[0];
|
||||
cp++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: mdoc_validate.c,v 1.352 2017/08/02 13:29:04 schwarze Exp $ */
|
||||
/* $Id: mdoc_validate.c,v 1.350 2017/07/20 12:54:02 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -1137,6 +1137,8 @@ post_fname(POST_ARGS)
|
||||
if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
|
||||
mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
|
||||
n->line, n->pos + pos, n->string);
|
||||
if (n->sec == SEC_SYNOPSIS && mdoc->meta.msec != NULL)
|
||||
mandoc_xr_add(mdoc->meta.msec, n->string, -1, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1203,8 +1205,9 @@ post_nm(POST_ARGS)
|
||||
|
||||
n = mdoc->last;
|
||||
|
||||
if (n->sec == SEC_NAME && n->child != NULL &&
|
||||
n->child->type == ROFFT_TEXT && mdoc->meta.msec != NULL)
|
||||
if ((n->sec == SEC_NAME || n->sec == SEC_SYNOPSIS) &&
|
||||
n->child != NULL && n->child->type == ROFFT_TEXT &&
|
||||
mdoc->meta.msec != NULL)
|
||||
mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1);
|
||||
|
||||
if (n->last != NULL &&
|
||||
@ -1928,7 +1931,7 @@ post_root(POST_ARGS)
|
||||
/* Check that we begin with a proper `Sh'. */
|
||||
|
||||
n = mdoc->first->child;
|
||||
while (n != NULL && n->tok >= MDOC_Dd &&
|
||||
while (n != NULL && n->tok != TOKEN_NONE &&
|
||||
mdoc_macros[n->tok].flags & MDOC_PROLOGUE)
|
||||
n = n->next;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: tbl_html.c,v 1.23 2017/07/31 16:14:10 schwarze Exp $ */
|
||||
/* $Id: tbl_html.c,v 1.22 2017/06/12 20:14:18 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -49,9 +49,6 @@ html_tbl_strlen(const char *p, void *arg)
|
||||
static size_t
|
||||
html_tbl_sulen(const struct roffsu *su, void *arg)
|
||||
{
|
||||
if (su->scale < 0.0)
|
||||
return 0;
|
||||
|
||||
switch (su->unit) {
|
||||
case SCALE_FS: /* 2^16 basic units */
|
||||
return su->scale * 65536.0 / 24.0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: tbl_term.c,v 1.57 2017/07/31 16:14:10 schwarze Exp $ */
|
||||
/* $Id: tbl_term.c,v 1.56 2017/07/08 13:43:15 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -51,10 +51,7 @@ static void tbl_word(struct termp *, const struct tbl_dat *);
|
||||
static size_t
|
||||
term_tbl_sulen(const struct roffsu *su, void *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = term_hen((const struct termp *)arg, su);
|
||||
return i > 0 ? i : 0;
|
||||
return term_hen((const struct termp *)arg, su);
|
||||
}
|
||||
|
||||
static size_t
|
||||
|
Loading…
Reference in New Issue
Block a user