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); }
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; }
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))); }
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; }
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; }
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))); }
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); } }
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; }
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; }
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"); }
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; }
/* 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; }