/*
 * Copyright (C) 2013-2025 Intel Corporation
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  * Neither the name of Intel Corporation nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef PARSE_H
#define PARSE_H

#include "yasm.h"

#include "intel-pt.h"

#if defined(FEATURE_PEVENT)
#  include "pevent.h"
#endif /* defined(FEATURE_PEVENT) */

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>


#if defined(FEATURE_SIDEBAND)

/* The sideband format. */
enum sb_format {
	sbf_raw,

#if defined(FEATURE_PEVENT)
	sbf_pevent,
#endif /* defined(FEATURE_PEVENT) */
};

/* A sideband file. */
struct sb_file {
	/* The file name. */
	char *name;

	/* The file pointer. */
	FILE *file;

	/* The sideband format. */
	enum sb_format format;

	/* The number of bytes written into the sideband file. */
	int bytes_written;

	/* Format-specific information. */
	union {
		/* A dummy entry. */
		uint64_t dummy;

#if defined(FEATURE_PEVENT)
		/* format = sbf_pevent. */
		struct {
			/* The perf_event sideband configuration. */
			struct pev_config config;

			/* If set, the configuration can't be changed. */
			uint32_t is_final:1;
		} pevent;
#endif /* defined(FEATURE_PEVENT) */
	} variant;
};

/* A list of sideband files. */
struct sb_filelist {
	/* The next file in the list. */
	struct sb_filelist *next;

	/* The sideband file. */
	struct sb_file sbfile;
};

#endif /* defined(FEATURE_SIDEBAND) */

enum {
	/* The maximal size of a label in characters. */
	l_max	= 256
};

/* Represents the parser.  */
struct parser {
	/* File pointer to the trace output file.  */
	FILE *ptfile;

	/* Filename of the trace output file.  The filename is
	 * determined from the .asm file given during p_alloc.
	 */
	char *ptfilename;

#if defined(FEATURE_SIDEBAND)
	/* A list of open sideband files. */
	struct sb_filelist *sbfiles;

	/* The currently active sideband file. */
	struct sb_file *current_sbfile;
#endif /* defined(FEATURE_SIDEBAND) */

	/* The yasm structure, initialized with pttfile in p_alloc.  */
	struct yasm *y;

	/* Current pt directive.  */
	struct pt_directive *pd;

	/* The encoder configuration, passed during p_alloc.  */
	const struct pt_config *conf;

	/* Labels for @pt or @sb directives.  */
	struct label *pt_labels;

	/* Number of bytes written to pt file.  */
	int pt_bytes_written;
};

/* Instantiates a parser and starts parsing of @pttfile and writes PT
 * stream using @conf.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 */
extern int parse(const char *pttfile, const struct pt_config *conf);

/* Parses an empty payload.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 * Returns -err_parse_trailing_tokens if @payload has non whitespace
 * characters.
 */
extern int parse_empty(char *payload);

/* Parses tnt @payload.  Takens are expressed with 't' and Not-Takens
 * with 'n'.  The t's and n's can be separated with spaces, periods or
 * directly concatenated.
 *
 * On success the TNT bitfield will be stored in the location of @tnt; the
 * number of T's and N's is stored in the location of @size.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 * Returns -err_internal if @payload or @tnt or @size is the NULL
 * pointer.
 * Returns -err_parse_unknown_char if there is an unrecognized character
 * in the payload.
 */
extern int parse_tnt(uint64_t *tnt, uint8_t *size, char *payload);

/* Parses an address and a ipc from @payload and stores it in the
 * location of @ip and @ipc respectively.  The ipc is separated from the
 * address with space or comma.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 * Returns -err_internal if @p or @ip or @ipc is the NULL pointer.
 * Returns -err_parse_int if ip or ipc in the @payload could not be
 * parsed as integer.
 * Returns -err_parse_ipc if the ipc argument is missing or malformed.
 * Returns -err_parse_trailing_tokens if the @payload contains more than
 * 2 arguments.
 */
extern int parse_ip(struct parser *p, uint64_t *ip,
		    enum pt_ip_compression *ipc, char *payload);

/* Parses a uint64_t value from @payload and stores it in the memory
 * location where @x points to.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 * Returns -err_internal if @x is the NULL pointer.
 * Returns -err_parse_no_args if @payload contains no arguments.
 * Returns -err_parse_int if @payload cannot be parsed as integer.
 */
extern int parse_uint64(uint64_t *x, char *payload);

/* Parses a uint8_t value from @payload and stores it in the memory
 * location where @x points to.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 * Returns -err_internal if @x is the NULL pointer.
 * Returns -err_parse_no_args if @payload contains no arguments.
 * Returns -err_parse_int if @payload cannot be parsed as integer.
 * Returns -err_parse_int_too_big if the integer parsed from @payload
 * cannot be represented in uint8_t.
 */
extern int parse_uint8(uint8_t *x, char *payload);

/* Parses a uint16_t value from @payload and stores it in the memory
 * location where @x points to.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 * Returns -err_internal if @x is the NULL pointer.
 * Returns -err_parse_no_args if @payload contains no arguments.
 * Returns -err_parse_int if @payload cannot be parsed as integer.
 * Returns -err_parse_int_too_big if the integer parsed from @payload
 * cannot be represented in uint16_t.
 */
extern int parse_uint16(uint16_t *x, char *payload);

/* Parses a uint32_t value from @payload and stores it in the memory
 * location where @x points to.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 * Returns -err_internal if @x is the NULL pointer.
 * Returns -err_parse_no_args if @payload contains no arguments.
 * Returns -err_parse_int if @payload cannot be parsed as integer.
 * Returns -err_parse_int_too_big if the integer parsed from @payload
 * cannot be represented in uint32_t.
 */
extern int parse_uint32(uint32_t *x, char *payload);

/* Parses the comma-separated ctc and fc arguments of a tma packet.
 *
 * Returns 0 on success; a negative enum errcode otherwise.
 * Returns -err_internal if @ctc or @fc is the NULL pointer.
 * Returns -err_parse_int if ctc or fc in the @payload could not be
 * parsed as integer.
 * Returns -err_parse_trailing_tokens if the @payload contains more than
 * 2 arguments.
 */
extern int parse_tma(uint16_t *ctc, uint16_t *fc, char *payload);

#endif /* PARSE_H */
