Example #1
0
static void diagnose_block(const char *errtype,
			   struct pt_block_decoder *decoder,
			   struct pt_block *block, int errcode)
{
	int err;
	uint64_t pos;

	if (!block) {
		printf("ptxed: internal error");
		return;
	}

	err = pt_blk_get_offset(decoder, &pos);
	if (err < 0) {
		printf("could not determine offset: %s\n",
		       pt_errstr(pt_errcode(err)));
		if (block->ninsn)
			printf("[?, %" PRIx64 "(+%x): %s: %s]\n", block->ip,
			       block->ninsn, errtype,
			       pt_errstr(pt_errcode(errcode)));
		else
			printf("[?, %" PRIx64 ": %s: %s]\n", block->ip, errtype,
			       pt_errstr(pt_errcode(errcode)));
	} else
		diagnose_block_at(errtype, pos, block, errcode);
}
Example #2
0
int pttc_main(const struct pttc_options *options)
{
	int errcode;
	enum { buflen = 1024 };
	uint8_t buf[buflen];
	struct pt_config conf;

	conf.begin = buf;
	conf.end = buf+buflen;

	errcode = pt_configure(&conf);

	/* check if we need to override auto-detected vaule.  */
	if (options->use_cpu)
		conf.cpu = options->cpu;

	if (errcode < 0) {
		fprintf(stderr, "fatal: pt_configure failed %d: %s\n", errcode,
			pt_errstr(pt_errcode(errcode)));
		return errcode;
	}

	errcode = parse(options->pttfile, &conf);
	if (errcode < 0 && errcode != -err_run)
		fprintf(stderr, "fatal: %s\n", errstr[-errcode]);

	return -errcode;

}
Example #3
0
static void diagnose_insn(const char *errtype, struct pt_insn_decoder *decoder,
			  struct pt_insn *insn, int errcode)
{
	int err;
	uint64_t pos;

	err = pt_insn_get_offset(decoder, &pos);
	if (err < 0) {
		printf("could not determine offset: %s\n",
		       pt_errstr(pt_errcode(err)));
		printf("[?, %" PRIx64 ": %s: %s]\n", insn->ip, errtype,
		       pt_errstr(pt_errcode(errcode)));
	} else
		printf("[%" PRIx64 ", %" PRIx64 ": %s: %s]\n", pos,
		       insn->ip, errtype, pt_errstr(pt_errcode(errcode)));
}
Example #4
0
int pttc_main(const struct pttc_options *options)
{
    int errcode;
    enum { buflen = 1024 };
    uint8_t buf[buflen];
    struct pt_config conf;

    pt_config_init(&conf);
    conf.cpu = options->cpu;
    conf.begin = buf;
    conf.end = buf+buflen;

    /* apply errata for the chosen cpu. */
    errcode = pt_cpu_errata(&conf.errata, &conf.cpu);
    if (errcode < 0) {
        fprintf(stderr, "fatal: errata configuration failed %d: %s\n",
                errcode, pt_errstr(pt_errcode(errcode)));
        return errcode;
    }

    errcode = parse(options->pttfile, &conf);
    if (errcode < 0 && errcode != -err_run)
        fprintf(stderr, "fatal: %s\n", errstr[-errcode]);

    return -errcode;

}
Example #5
0
inline static void perf_ptAnalyzePkt(honggfuzz_t * hfuzz, fuzzer_t * fuzzer,
                                     struct pt_packet *packet, struct pt_config *ptc,
                                     struct pt_last_ip *last_ip)
{
    switch (packet->type) {
    case ppt_tip:
    case ppt_fup:
    case ppt_tip_pge:
    case ppt_tip_pgd:
        break;
    default:
        return;
    }

    int errcode = pt_last_ip_update_ip(last_ip, &(packet->payload.ip), ptc);
    if (errcode < 0) {
        LOG_F("pt_last_ip_update_ip() failed: %s", pt_errstr(errcode));
    }

    /* Update only on TIP, other packets don't indicate a branch */
    if (packet->type == ppt_tip) {
        uint64_t ip;
        errcode = pt_last_ip_query(&ip, last_ip);
        if (errcode == 0) {
            ip &= _HF_PERF_BITMAP_BITSZ_MASK;
            register uint8_t prev = ATOMIC_BTS(hfuzz->feedback->bbMapPc, ip);
            if (!prev) {
                fuzzer->linux.hwCnts.newBBCnt++;
            }
        }
    }
    return;
}
Example #6
0
static void diagnose_block_at(const char *errtype, uint64_t pos,
			      struct pt_block *block, int errcode)
{
	if (!block) {
		printf("ptxed: internal error");
		return;
	}

	if (block->ninsn)
		printf("[%" PRIx64 ", %" PRIx64 "(+%x): %s: %s]\n", pos,
		       block->ip, block->ninsn, errtype,
		       pt_errstr(pt_errcode(errcode)));
	else
		printf("[%" PRIx64 ", %" PRIx64 ": %s: %s]\n", pos,
		       block->ip, errtype,
		       pt_errstr(pt_errcode(errcode)));
}
Example #7
0
void arch_ptAnalyze(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
{
    struct perf_event_mmap_page *pem = (struct perf_event_mmap_page *)fuzzer->linux.perfMmapBuf;

    struct pt_config ptc;
    pt_config_init(&ptc);
    ptc.begin = &fuzzer->linux.perfMmapAux[pem->aux_tail];
    ptc.end = &fuzzer->linux.perfMmapAux[pem->aux_head - 1];

    int errcode = pt_cpu_errata(&ptc.errata, &ptc.cpu);
    if (errcode < 0) {
        LOG_F("pt_errata() failed: %s", pt_errstr(errcode));
    }

    struct pt_packet_decoder *ptd = pt_pkt_alloc_decoder(&ptc);
    if (ptd == NULL) {
        LOG_F("pt_pkt_alloc_decoder() failed");
    }
    defer {
        pt_pkt_free_decoder(ptd);
    };

    errcode = pt_pkt_sync_forward(ptd);
    if (errcode < 0) {
        LOG_W("pt_pkt_sync_forward() failed: %s", pt_errstr(errcode));
        return;
    }

    struct pt_last_ip last_ip;
    pt_last_ip_init(&last_ip);
    for (;;) {
        struct pt_packet packet;
        errcode = pt_pkt_next(ptd, &packet, sizeof(packet));
        if (errcode == -pte_eos) {
            break;
        }
        if (errcode < 0) {
            LOG_W("pt_pkt_next() failed: %s", pt_errstr(errcode));
            break;
        }
        perf_ptAnalyzePkt(hfuzz, fuzzer, &packet, &ptc, &last_ip);
    }
}
Example #8
0
static int load_raw(struct pt_image_section_cache *iscache,
		    struct pt_image *image, char *arg, const char *prog)
{
	uint64_t base, foffset, fsize;
	int isid, errcode, has_base;

	has_base = extract_base(arg, &base);
	if (has_base <= 0)
		return -1;

	errcode = preprocess_filename(arg, &foffset, &fsize);
	if (errcode < 0) {
		fprintf(stderr, "%s: bad file %s: %s.\n", prog, arg,
			pt_errstr(pt_errcode(errcode)));
		return -1;
	}

	if (!fsize)
		fsize = UINT64_MAX;

	isid = pt_iscache_add_file(iscache, arg, foffset, fsize, base);
	if (isid < 0) {
		fprintf(stderr, "%s: failed to add %s at 0x%" PRIx64 ": %s.\n",
			prog, arg, base, pt_errstr(pt_errcode(isid)));
		return -1;
	}

	errcode = pt_image_add_cached(image, iscache, isid, NULL);
	if (errcode < 0) {
		fprintf(stderr, "%s: failed to add %s at 0x%" PRIx64 ": %s.\n",
			prog, arg, base, pt_errstr(pt_errcode(errcode)));
		return -1;
	}

	return 0;
}
Example #9
0
static int load_pt(struct pt_config *config, char *arg, const char *prog)
{
	uint64_t foffset, fsize;
	uint8_t *buffer;
	size_t size;
	int errcode;

	errcode = preprocess_filename(arg, &foffset, &fsize);
	if (errcode < 0) {
		fprintf(stderr, "%s: bad file %s: %s.\n", prog, arg,
			pt_errstr(pt_errcode(errcode)));
		return -1;
	}

	errcode = load_file(&buffer, &size, arg, foffset, fsize, prog);
	if (errcode < 0)
		return errcode;

	config->begin = buffer;
	config->end = buffer + size;

	return 0;
}
Example #10
0
static void print_block(struct pt_block *block,
			struct pt_image_section_cache *iscache,
			const struct ptxed_options *options,
			const struct ptxed_stats *stats,
			uint64_t offset, uint64_t time)
{
	xed_machine_mode_enum_t mode;
	xed_state_t xed;
	uint64_t last_ip;

	if (!block || !options) {
		printf("[internal error]\n");
		return;
	}

	if (block->resynced)
		printf("[overflow]\n");

	if (block->enabled)
		printf("[enabled]\n");

	if (block->resumed)
		printf("[resumed]\n");

	if (options->track_blocks) {
		printf("[block");
		if (stats)
			printf(" %" PRIx64, stats->blocks);
		printf("]\n");
	}

	mode = translate_mode(block->mode);
	xed_state_init2(&xed, mode, XED_ADDRESS_WIDTH_INVALID);

	last_ip = 0ull;
	for (; block->ninsn; --block->ninsn) {
		xed_decoded_inst_t inst;
		xed_error_enum_t xederrcode;
		uint8_t raw[pt_max_insn_size], *praw;
		int size, errcode;

		/* For truncated block, the last instruction is provided in the
		 * block since it can't be read entirely from the image section
		 * cache.
		 */
		if (block->truncated && (block->ninsn == 1)) {
			praw = block->raw;
			size = block->size;
		} else {
			praw = raw;
			size = pt_iscache_read(iscache, raw, sizeof(raw),
					       block->isid, block->ip);
			if (size < 0) {
				printf(" [error reading insn: (%d) %s]\n", size,
				       pt_errstr(pt_errcode(size)));
				break;
			}
		}

		xed_decoded_inst_zero_set_mode(&inst, &xed);

		if (block->speculative)
			printf("? ");

		if (options->print_offset)
			printf("%016" PRIx64 "  ", offset);

		if (options->print_time)
			printf("%016" PRIx64 "  ", time);

		printf("%016" PRIx64, block->ip);

		xederrcode = xed_decode(&inst, praw, size);
		if (xederrcode != XED_ERROR_NONE) {
			printf(" [xed decode error: (%u) %s]\n", xederrcode,
			       xed_error_enum_t2str(xederrcode));
			break;
		}

		if (!options->dont_print_insn)
			xed_print_insn(&inst, block->ip, options);

		printf("\n");

		last_ip = block->ip;

		errcode = xed_next_ip(&block->ip, &inst, last_ip);
		if (errcode < 0) {
			diagnose_block_at("reconstruct error", offset, block,
					  errcode);
			break;
		}
	}

	/* Decode should have brought us to @block->end_ip. */
	if (last_ip != block->end_ip)
		diagnose_block_at("reconstruct error", offset, block,
				  -pte_nosync);

	if (block->interrupted)
		printf("[interrupt]\n");

	if (block->aborted)
		printf("[aborted]\n");

	if (block->committed)
		printf("[committed]\n");

	if (block->disabled)
		printf("[disabled]\n");

	if (block->stopped)
		printf("[stopped]\n");
}
Example #11
0
extern int main(int argc, char *argv[])
{
	struct pt_image_section_cache *iscache;
	struct ptxed_decoder decoder;
	struct ptxed_options options;
	struct ptxed_stats stats;
	struct pt_config config;
	struct pt_image *image;
	const char *prog;
	int errcode, i;

	if (!argc) {
		help("");
		return 1;
	}

	prog = argv[0];
	iscache = NULL;
	image = NULL;

	memset(&decoder, 0, sizeof(decoder));
	decoder.type = pdt_block_decoder;

	memset(&options, 0, sizeof(options));
	memset(&stats, 0, sizeof(stats));

	pt_config_init(&config);

	iscache = pt_iscache_alloc(NULL);
	if (!iscache) {
		fprintf(stderr,
			"%s: failed to allocate image section cache.\n", prog);
		goto err;
	}

	image = pt_image_alloc(NULL);
	if (!image) {
		fprintf(stderr, "%s: failed to allocate image.\n", prog);
		goto err;
	}

	for (i = 1; i < argc;) {
		char *arg;

		arg = argv[i++];

		if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
			help(prog);
			goto out;
		}
		if (strcmp(arg, "--version") == 0) {
			version(prog);
			goto out;
		}
		if (strcmp(arg, "--pt") == 0) {
			if (argc <= i) {
				fprintf(stderr,
					"%s: --pt: missing argument.\n", prog);
				goto out;
			}
			arg = argv[i++];

			if (ptxed_have_decoder(&decoder)) {
				fprintf(stderr,
					"%s: duplicate pt sources: %s.\n",
					prog, arg);
				goto err;
			}

			errcode = pt_cpu_errata(&config.errata, &config.cpu);
			if (errcode < 0)
				goto err;

			errcode = load_pt(&config, arg, prog);
			if (errcode < 0)
				goto err;

			switch (decoder.type) {
			case pdt_insn_decoder:
				decoder.variant.insn =
					pt_insn_alloc_decoder(&config);
				if (!decoder.variant.insn) {
					fprintf(stderr, "%s: failed to create "
						"decoder.\n", prog);
					goto err;
				}

				errcode =
					pt_insn_set_image(decoder.variant.insn,
							  image);
				if (errcode < 0) {
					fprintf(stderr,
						"%s: failed to set image.\n",
						prog);
					goto err;
				}
				break;

			case pdt_block_decoder:
				decoder.variant.block =
					pt_blk_alloc_decoder(&config);
				if (!decoder.variant.block) {
					fprintf(stderr, "%s: failed to create "
						"decoder.\n", prog);
					goto err;
				}

				errcode =
					pt_blk_set_image(decoder.variant.block,
							 image);
				if (errcode < 0) {
					fprintf(stderr,
						"%s: failed to set image.\n",
						prog);
					goto err;
				}
				break;
			}

			continue;
		}
		if (strcmp(arg, "--raw") == 0) {
			if (argc <= i) {
				fprintf(stderr,
					"%s: --raw: missing argument.\n", prog);
				goto out;
			}
			arg = argv[i++];

			errcode = load_raw(iscache, image, arg, prog);
			if (errcode < 0)
				goto err;

			continue;
		}
#if defined(FEATURE_ELF)
		if (strcmp(arg, "--elf") == 0) {
			uint64_t base;

			if (argc <= i) {
				fprintf(stderr,
					"%s: --elf: missing argument.\n", prog);
				goto out;
			}
			arg = argv[i++];
			base = 0ull;
			errcode = extract_base(arg, &base);
			if (errcode < 0)
				goto err;

			errcode = load_elf(iscache, image, arg, base, prog,
					   options.track_image);
			if (errcode < 0)
				goto err;

			continue;
		}
#endif /* defined(FEATURE_ELF) */
		if (strcmp(arg, "--att") == 0) {
			options.att_format = 1;
			continue;
		}
		if (strcmp(arg, "--no-inst") == 0) {
			options.dont_print_insn = 1;
			continue;
		}
		if (strcmp(arg, "--quiet") == 0 || strcmp(arg, "-q") == 0) {
			options.quiet = 1;
			continue;
		}
		if (strcmp(arg, "--offset") == 0) {
			options.print_offset = 1;
			continue;
		}
		if (strcmp(arg, "--time") == 0) {
			options.print_time = 1;
			continue;
		}
		if (strcmp(arg, "--raw-insn") == 0) {
			options.print_raw_insn = 1;
			continue;
		}
		if (strcmp(arg, "--stat") == 0) {
			options.print_stats = 1;
			continue;
		}
		if (strcmp(arg, "--stat:insn") == 0) {
			stats.flags |= ptxed_stat_insn;
			continue;
		}
		if (strcmp(arg, "--stat:blocks") == 0) {
			stats.flags |= ptxed_stat_blocks;
			continue;
		}
		if (strcmp(arg, "--cpu") == 0) {
			/* override cpu information before the decoder
			 * is initialized.
			 */
			if (ptxed_have_decoder(&decoder)) {
				fprintf(stderr,
					"%s: please specify cpu before the pt source file.\n",
					prog);
				goto err;
			}
			if (argc <= i) {
				fprintf(stderr,
					"%s: --cpu: missing argument.\n", prog);
				goto out;
			}
			arg = argv[i++];

			if (strcmp(arg, "auto") == 0) {
				errcode = pt_cpu_read(&config.cpu);
				if (errcode < 0) {
					fprintf(stderr,
						"%s: error reading cpu: %s.\n",
						prog,
						pt_errstr(pt_errcode(errcode)));
					return 1;
				}
				continue;
			}

			if (strcmp(arg, "none") == 0) {
				memset(&config.cpu, 0, sizeof(config.cpu));
				continue;
			}

			errcode = pt_cpu_parse(&config.cpu, arg);
			if (errcode < 0) {
				fprintf(stderr,
					"%s: cpu must be specified as f/m[/s]\n",
					prog);
				goto err;
			}
			continue;
		}
		if (strcmp(arg, "--mtc-freq") == 0) {
			if (!get_arg_uint8(&config.mtc_freq, "--mtc-freq",
					   argv[i++], prog))
				goto err;

			continue;
		}
		if (strcmp(arg, "--nom-freq") == 0) {
			if (!get_arg_uint8(&config.nom_freq, "--nom-freq",
					   argv[i++], prog))
				goto err;

			continue;
		}
		if (strcmp(arg, "--cpuid-0x15.eax") == 0) {
			if (!get_arg_uint32(&config.cpuid_0x15_eax,
					    "--cpuid-0x15.eax", argv[i++],
					    prog))
				goto err;

			continue;
		}
		if (strcmp(arg, "--cpuid-0x15.ebx") == 0) {
			if (!get_arg_uint32(&config.cpuid_0x15_ebx,
					    "--cpuid-0x15.ebx", argv[i++],
					    prog))
				goto err;

			continue;
		}
		if (strcmp(arg, "--verbose") == 0 || strcmp(arg, "-v") == 0) {
			options.track_image = 1;
			continue;
		}

		if (strcmp(arg, "--insn-decoder") == 0) {
			if (ptxed_have_decoder(&decoder)) {
				fprintf(stderr,
					"%s: please specify %s before the pt "
					"source file.\n", arg, prog);
				goto err;
			}

			decoder.type = pdt_insn_decoder;
			continue;
		}

		if (strcmp(arg, "--block-decoder") == 0) {
			if (ptxed_have_decoder(&decoder)) {
				fprintf(stderr,
					"%s: please specify %s before the pt "
					"source file.\n", arg, prog);
				goto err;
			}

			decoder.type = pdt_block_decoder;
			continue;
		}

		if (strcmp(arg, "--block:show-blocks") == 0) {
			options.track_blocks = 1;
			continue;
		}

		if (strcmp(arg, "--block:end-on-call") == 0) {
			config.flags.variant.block.end_on_call = 1;
			continue;
		}

		fprintf(stderr, "%s: unknown option: %s.\n", prog, arg);
		goto err;
	}

	if (!ptxed_have_decoder(&decoder)) {
		fprintf(stderr, "%s: no pt file.\n", prog);
		goto err;
	}

	xed_tables_init();

	/* If we didn't select any statistics, select them all depending on the
	 * decoder type.
	 */
	if (options.print_stats && !stats.flags) {
		stats.flags |= ptxed_stat_insn;

		if (decoder.type == pdt_block_decoder)
			stats.flags |= ptxed_stat_blocks;
	}

	decode(&decoder, iscache, &options,
	       options.print_stats ? &stats : NULL);

	if (options.print_stats)
		print_stats(&stats);

out:
	ptxed_free_decoder(&decoder);
	pt_image_free(image);
	pt_iscache_free(iscache);
	return 0;

err:
	ptxed_free_decoder(&decoder);
	pt_image_free(image);
	pt_iscache_free(iscache);
	return 1;
}
Example #12
0
/* Processes the current directive.
 * If the encoder returns an error, a message including current file and
 * line number together with the pt error string is printed on stderr.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 * Returns -err_internal if @p or @e is the NULL pointer.
 * Returns -err_parse_missing_directive if there was a pt directive marker,
 * but no directive.
 * Returns -stop_process if the .exp directive was encountered.
 * Returns -err_pt_lib if the pt encoder returned an error.
 * Returns -err_parse if a general parsing error was encountered.
 * Returns -err_parse_unknown_directive if there was an unknown pt directive.
 */
static int p_process(struct parser *p, struct pt_encoder *e)
{
	int bytes_written;
	int errcode;
	char *directive, *payload, *pt_label_name, *tmp;
	struct pt_directive *pd;
	struct pt_packet packet;

	if (bug_on(!p))
		return -err_internal;

	if (bug_on(!e))
		return -err_internal;

	pd = p->pd;
	if (!pd)
		return -err_internal;

	directive = pd->name;
	payload = pd->payload;

	pt_label_name = NULL;
	bytes_written = 0;
	errcode = 0;

	/* find a label name.  */
	tmp = strchr(directive, ':');
	if (tmp) {
		uint64_t x;

		pt_label_name = directive;
		directive = tmp+1;
		*tmp = '\0';

		/* ignore whitespace between label and directive. */
		while (isspace(*directive))
			directive += 1;

		/* if we can lookup a yasm label with the same name, the
		 * current pt directive label is invalid.  */
		errcode = yasm_lookup_label(p->y, &x, pt_label_name);
		if (errcode == 0)
			errcode = -err_label_not_unique;

		if (errcode != -err_no_label)
			return yasm_print_err(p->y, "label lookup",
					      errcode);

		/* if we can lookup a pt directive label with the same
		 * name, the current pt directive label is invalid.  */
		errcode = l_lookup(p->pt_labels, &x, pt_label_name);
		if (errcode == 0)
			errcode = -err_label_not_unique;

		if (errcode != -err_no_label)
			return yasm_print_err(p->y, "label lookup",
					      -err_label_not_unique);
	}

	/* now try to match the directive string and call the
	 * corresponding function that parses the payload and emits an
	 * according packet.
	 */
	if (strcmp(directive, "") == 0)
		return yasm_print_err(p->y, "invalid syntax",
				      -err_parse_missing_directive);
	else if (strcmp(directive, ".exp") == 0) {
		/* this is the end of processing pt directives, so we
		 * add a p_last label to the pt directive labels.
		 */
		errcode = l_append(p->pt_labels, "eos", p->pt_bytes_written);
		if (errcode < 0)
			return yasm_print_err(p->y, "append label", errcode);

		return -stop_process;
	}

	if (strcmp(directive, "psb") == 0) {
		errcode = parse_empty(payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "psb: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_psb;
	} else if (strcmp(directive, "psbend") == 0) {
		errcode = parse_empty(payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "psbend: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_psbend;
	} else if (strcmp(directive, "pad") == 0) {
		errcode = parse_empty(payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "pad: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_pad;
	} else if (strcmp(directive, "ovf") == 0) {
		errcode = parse_empty(payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "ovf: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_ovf;
	} else if (strcmp(directive, "tnt") == 0) {
		errcode = parse_tnt(&packet.payload.tnt.payload,
				    &packet.payload.tnt.bit_size, payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "tnt: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_tnt_8;
	} else if (strcmp(directive, "tnt64") == 0) {
		errcode = parse_tnt(&packet.payload.tnt.payload,
				    &packet.payload.tnt.bit_size, payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "tnt64: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_tnt_64;
	} else if (strcmp(directive, "tip") == 0) {
		errcode = parse_ip(p, &packet.payload.ip.ip,
				   &packet.payload.ip.ipc, payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "tip: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_tip;
	} else if (strcmp(directive, "tip.pge") == 0) {
		errcode = parse_ip(p, &packet.payload.ip.ip,
				   &packet.payload.ip.ipc, payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "tip.pge: parsing failed",
				       errcode);
			goto error;
		}
		packet.type = ppt_tip_pge;
	} else if (strcmp(directive, "tip.pgd") == 0) {
		errcode = parse_ip(p, &packet.payload.ip.ip,
				   &packet.payload.ip.ipc, payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "tip.pgd: parsing failed",
				       errcode);
			goto error;
		}
		packet.type = ppt_tip_pgd;
	} else if (strcmp(directive, "fup") == 0) {
		errcode = parse_ip(p, &packet.payload.ip.ip,
				   &packet.payload.ip.ipc, payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "fup: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_fup;
	} else if (strcmp(directive, "mode.exec") == 0) {
		if (strcmp(payload, "16bit") == 0) {
			packet.payload.mode.bits.exec.csl = 0;
			packet.payload.mode.bits.exec.csd = 0;
		} else if (strcmp(payload, "64bit") == 0) {
			packet.payload.mode.bits.exec.csl = 1;
			packet.payload.mode.bits.exec.csd = 0;
		} else if (strcmp(payload, "32bit") == 0) {
			packet.payload.mode.bits.exec.csl = 0;
			packet.payload.mode.bits.exec.csd = 1;
		} else {
			errcode = yasm_print_err(p->y,
						 "mode.exec: argument must be one of \"16bit\", \"64bit\" or \"32bit\"",
						 -err_parse);
			goto error;
		}
		packet.payload.mode.leaf = pt_mol_exec;
		packet.type = ppt_mode;
	} else if (strcmp(directive, "mode.tsx") == 0) {
		if (strcmp(payload, "begin") == 0) {
			packet.payload.mode.bits.tsx.intx = 1;
			packet.payload.mode.bits.tsx.abrt = 0;
		} else if (strcmp(payload, "abort") == 0) {
			packet.payload.mode.bits.tsx.intx = 0;
			packet.payload.mode.bits.tsx.abrt = 1;
		} else if (strcmp(payload, "commit") == 0) {
			packet.payload.mode.bits.tsx.intx = 0;
			packet.payload.mode.bits.tsx.abrt = 0;
		} else {
			errcode = yasm_print_err(p->y,
						 "mode.tsx: argument must be one of \"begin\", \"abort\" or \"commit\"",
						 -err_parse);
			goto error;
		}
		packet.payload.mode.leaf = pt_mol_tsx;
		packet.type = ppt_mode;
	} else if (strcmp(directive, "pip") == 0) {
		errcode = parse_uint64(&packet.payload.pip.cr3, payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "pip: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_pip;
	} else if (strcmp(directive, "tsc") == 0) {
		errcode = parse_uint64(&packet.payload.tsc.tsc, payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "tsc: parsing failed", errcode);
			goto error;
		}
		packet.type = ppt_tsc;
	} else if (strcmp(directive, "cbr") == 0) {
		errcode = parse_uint8(&packet.payload.cbr.ratio, payload);
		if (errcode < 0) {
			yasm_print_err(p->y, "cbr: parsing cbr failed",
				       errcode);
			goto error;
		}
		packet.type = ppt_cbr;
	} else {
		errcode = yasm_print_err(p->y, "invalid syntax",
					 -err_parse_unknown_directive);
		goto error;
	}

	bytes_written = pt_enc_next(e, &packet);
	if (bytes_written < 0) {
		const char *errstr, *format;
		char *msg;
		size_t n;

		errstr = pt_errstr(pt_errcode(bytes_written));
		format = "encoder error in directive %s (status %s)";
		/* the length of format includes the "%s" (-2)
		 * characters, we add errstr (+-0) and then we need
		 * space for a terminating null-byte (+1).
		 */
		n = strlen(format)-4 + strlen(directive) + strlen(errstr) + 1;

		msg = malloc(n);
		if (!msg)
			errcode = yasm_print_err(p->y,
				       "encoder error not enough memory to show error code",
				       -err_pt_lib);
		else {
			sprintf(msg, format, directive, errstr);
			errcode = yasm_print_err(p->y, msg, -err_pt_lib);
			free(msg);
		}
	} else {
		if (pt_label_name) {
			errcode = l_append(p->pt_labels, pt_label_name,
					   p->pt_bytes_written);
			if (errcode < 0)
				goto error;
		}
		p->pt_bytes_written += bytes_written;
	}

error:
	if (errcode < 0)
		bytes_written = errcode;
	return bytes_written;
}