Blob Blame History Raw
/**********************************************************/
/*  apimagic: cparser-based API normalization utility     */
/*  Copyright (C) 2015--2021  Z. Gilboa                   */
/*  Released under GPLv2 and GPLv3; see COPYING.APIMAGIC. */
/**********************************************************/

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>


#include <cparser/driver/driver.h>
#include <cparser/driver/c_driver.h>

#include <apimagic/apimagic.h>
#include "apimagic_driver_impl.h"
#include "apimagic_errinfo_impl.h"

static int amgc_free_unit_ctx_impl(struct amgc_unit_ctx_impl * ctx, int ret)
{
	if (ctx) {
		if (ctx->entities)
			amgc_free_unit_entities(ctx->entities);

		free(ctx);
	}

	return ret;
}

static int amgc_stdin_to_tmp(const struct amgc_driver_ctx * dctx)
{
	struct amgc_driver_ctx_impl *	ictx;
	uintptr_t			addr;
	int				fdtmp;

	ssize_t ret;
	ssize_t cnt;
	char *	ch;
	char	buf[4096];
	char	template[] = "/tmp/amgc_stdin_to_tmp_XXXXXX";

	addr = (uintptr_t)dctx - offsetof(struct amgc_driver_ctx_impl,ctx);
	ictx = (struct amgc_driver_ctx_impl *)addr;

	if (ictx->fdtmpin >= 0)
		return dup(ictx->fdtmpin);

	if ((fdtmp = mkstemp(template)) < 0)
		return -1;

	if ((ictx->fdtmpin = dup(fdtmp)) < 0) {
		close(fdtmp);
		return -1;
	}

	for (;;) {
		ret = read(0,buf,sizeof(buf)-1);

		while ((ret < 0) && (errno == EINTR))
			ret = read(0,buf,sizeof(buf)-1);

		if (ret < 0) {
			close(fdtmp);
			return -1;

		} else if (ret == 0) {
			return fdtmp;

		} else {
			ch  = buf;
			cnt = ret;
			ret = 0;

			for (; cnt; ) {
				ret = write(fdtmp,ch,cnt);

				while ((ret < 0) && (errno == EINTR))
					ret = write(fdtmp,ch,cnt);

				if (ret < 0) {
					close(fdtmp);
					return -1;
				}

				ch  += ret;
				cnt -= ret;
			}
		}
	}
}

static bool amgc_cparser_no_op(
	compilation_env_t *	env,
	compilation_unit_t *	unit)
{
	(void)env;
	(void)unit;
	return true;
}

static void amgc_init_cparser_unit(void)
{
	set_default_handlers();

	/* parse only */
	set_unit_handler(COMPILATION_UNIT_AST,
			build_firm_ir,true);

	/* assign no-op handler */
	set_unit_handler(COMPILATION_UNIT_PREPROCESSED_ASSEMBLER,
			amgc_cparser_no_op,true);

	set_unit_handler(COMPILATION_UNIT_OBJECT,
			amgc_cparser_no_op,true);
}

int amgc_get_unit_ctx(
	const struct amgc_driver_ctx *	dctx,
	const char *			path,
	struct amgc_unit_ctx **		pctx)
{
	struct amgc_unit_ctx_impl *	ctx;
	int				fd;

	amgc_init_cparser_unit();

	if (!dctx)
		return AMGC_CUSTOM_ERROR(
			dctx,AMGC_ERR_NULL_CONTEXT);

	else if (!(ctx = calloc(1,sizeof(*ctx))))
		return AMGC_SYSTEM_ERROR(dctx);

	amgc_driver_set_ectx(
		dctx,0,path);

	if (strcmp(path,"-"))
		fd = -1;

	else if ((fd = amgc_stdin_to_tmp(dctx)) < 0)
		return amgc_free_unit_ctx_impl(
			ctx,AMGC_SYSTEM_ERROR(dctx));

	else if (lseek(fd,0,SEEK_SET < 0))
		return amgc_free_unit_ctx_impl(
			ctx,AMGC_NESTED_ERROR(dctx));

	else if (!(ctx->ccunit.input = fdopen(fd,"r")))
		return amgc_free_unit_ctx_impl(
			ctx,AMGC_FILE_ERROR(dctx));

	/* compilation unit */
	ctx->ccunit.name		= path;
	ctx->ccunit.original_name	= path;
	ctx->ccunit.type		= COMPILATION_UNIT_C;
	ctx->ccunit.standard		= dctx->cctx->std;

	/* parse, generate ast, generate ir */
	if ((process_unit(ctx->cctx.ccenv,&ctx->ccunit)) == false) {
		if (ctx->ccunit.input)
			fclose(ctx->ccunit.input);
		return amgc_free_unit_ctx_impl(
			ctx,AMGC_CUSTOM_ERROR(dctx,AMGC_ERR_FLOW_ERROR));
	}

	memcpy(&ctx->cctx,dctx->cctx,
		sizeof(ctx->cctx));

	ctx->dctx	    = dctx;
	ctx->path	    = path;
	ctx->uctx.path	    = &ctx->path;
	ctx->uctx.cctx	    = &ctx->cctx;
	ctx->uctx.meta	    = &ctx->meta;
	ctx->uctx.ccunit    = &ctx->ccunit;

	if (amgc_get_unit_entities(&ctx->uctx,&ctx->meta,&ctx->entities))
		return amgc_free_unit_ctx_impl(
			ctx,AMGC_CUSTOM_ERROR(dctx,AMGC_ERR_FLOW_ERROR));

	ctx->uctx.entities  = ctx->entities;
	*pctx = &ctx->uctx;
	return 0;
}

void amgc_free_unit_ctx(struct amgc_unit_ctx * ctx)
{
	struct amgc_unit_ctx_impl *	ictx;
	uintptr_t			addr;

	if (ctx) {
		addr = (uintptr_t)ctx - offsetof(struct amgc_unit_ctx_impl,uctx);
		ictx = (struct amgc_unit_ctx_impl *)addr;
		amgc_free_unit_ctx_impl(ictx,0);
	}
}