<commit_before>/* Copyright 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <ccan/array_size/array_size.h>
#include <unistd.h>

#include "target.h"
#include "operations.h"
#include "bitutils.h"
#include "debug.h"

static uint64_t mfspr(uint64_t reg, uint64_t spr)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MFSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6);
}

static uint64_t mtspr(uint64_t spr, uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MTSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6);
}

static uint64_t mfocrf(uint64_t reg, uint64_t cr)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");
	if (cr > 7)
		PR_ERROR("Invalid register specified\n");

	return MFOCRF_OPCODE | (reg << 21) | (1U << (12 + cr));
}

static uint64_t mfnia(uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MFNIA_OPCODE | (reg << 21);
}

static uint64_t mtnia(uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MTNIA_OPCODE | (reg << 21);
}

static uint64_t mfmsr(uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MFMSR_OPCODE | (reg << 21);
}

static uint64_t mtmsr(uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MTMSR_OPCODE | (reg << 21);
}

static uint64_t ld(uint64_t rt, uint64_t ds, uint64_t ra)
{
	if ((rt > 31) | (ra > 31) | (ds > 0x3fff))
		PR_ERROR("Invalid register specified\n");

	return LD_OPCODE | (rt << 21) | (ra << 16) | (ds << 2);
}

struct thread_state thread_status(struct pdbg_target *target)
{
	struct thread *thread;

	assert(!strcmp(target->class, "thread"));
	thread = target_to_thread(target);
	return thread->status;
}

/*
 * Single step the thread count instructions.
 */
int ram_step_thread(struct pdbg_target *thread_target, int count)
{
	struct thread *thread;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);
	return thread->step(thread, count);
}

int ram_start_thread(struct pdbg_target *thread_target)
{
	struct thread *thread;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);
	return thread->start(thread);
}

int ram_stop_thread(struct pdbg_target *thread_target)
{
	struct thread *thread;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);
	return thread->stop(thread);
}

int ram_sreset_thread(struct pdbg_target *thread_target)
{
	struct thread *thread;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);
	return thread->sreset(thread);
}

/*
 * RAMs the opcodes in *opcodes and store the results of each opcode
 * into *results. *results must point to an array the same size as
 * *opcodes. Each entry from *results is put into SCR0 prior to
 * executing an opcode so that it may also be used to pass in
 * data. Note that only register r0 is saved and restored so opcodes
 * must not touch other registers.
 */
static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes,
			    uint64_t *results, int len, unsigned int lpar)
{
	uint64_t opcode = 0, r0 = 0, r1 = 0, scratch = 0;
	int i;
	int exception = 0;
	struct thread *thread;
	bool did_setup = false;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);

	if (!thread->ram_is_setup) {
		CHECK_ERR(thread->ram_setup(thread));
		did_setup = true;
	}

	/* RAM instructions */
	for (i = -2; i < len + 2; i++) {
		if (i == -2)
			opcode = mtspr(277, 1);
		else if (i == -1)
			/* Save r0 (assumes opcodes don't touch other registers) */
			opcode = mtspr(277, 0);
		else if (i < len) {
			scratch = results[i];
			opcode = opcodes[i];
		} else if (i == len) {
			/* Restore r0 */
			scratch = r0;
			opcode = mfspr(0, 277);
		} else if (i == len + 1) {
			/* Restore r1 */
			scratch = r1;
			opcode = mfspr(1, 277);
		}

		if (thread->ram_instruction(thread, opcode, &scratch)) {
			PR_DEBUG("%s: %d\n", __FUNCTION__, __LINE__);
			exception = 1;
			break;
		}

		if (i == -2)
			r1 = scratch;
		else if (i == -1)
			r0 = scratch;
		else if (i < len)
			results[i] = scratch;
	}

	if (did_setup)
		CHECK_ERR(thread->ram_destroy(thread));<commit_msg>libpdbg: Attempt to restore registers that we clobbered on failure<commit_after>/* Copyright 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <ccan/array_size/array_size.h>
#include <unistd.h>

#include "target.h"
#include "operations.h"
#include "bitutils.h"
#include "debug.h"

static uint64_t mfspr(uint64_t reg, uint64_t spr)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MFSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6);
}

static uint64_t mtspr(uint64_t spr, uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MTSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6);
}

static uint64_t mfocrf(uint64_t reg, uint64_t cr)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");
	if (cr > 7)
		PR_ERROR("Invalid register specified\n");

	return MFOCRF_OPCODE | (reg << 21) | (1U << (12 + cr));
}

static uint64_t mfnia(uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MFNIA_OPCODE | (reg << 21);
}

static uint64_t mtnia(uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MTNIA_OPCODE | (reg << 21);
}

static uint64_t mfmsr(uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MFMSR_OPCODE | (reg << 21);
}

static uint64_t mtmsr(uint64_t reg)
{
	if (reg > 31)
		PR_ERROR("Invalid register specified\n");

	return MTMSR_OPCODE | (reg << 21);
}

static uint64_t ld(uint64_t rt, uint64_t ds, uint64_t ra)
{
	if ((rt > 31) | (ra > 31) | (ds > 0x3fff))
		PR_ERROR("Invalid register specified\n");

	return LD_OPCODE | (rt << 21) | (ra << 16) | (ds << 2);
}

struct thread_state thread_status(struct pdbg_target *target)
{
	struct thread *thread;

	assert(!strcmp(target->class, "thread"));
	thread = target_to_thread(target);
	return thread->status;
}

/*
 * Single step the thread count instructions.
 */
int ram_step_thread(struct pdbg_target *thread_target, int count)
{
	struct thread *thread;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);
	return thread->step(thread, count);
}

int ram_start_thread(struct pdbg_target *thread_target)
{
	struct thread *thread;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);
	return thread->start(thread);
}

int ram_stop_thread(struct pdbg_target *thread_target)
{
	struct thread *thread;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);
	return thread->stop(thread);
}

int ram_sreset_thread(struct pdbg_target *thread_target)
{
	struct thread *thread;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);
	return thread->sreset(thread);
}

/*
 * RAMs the opcodes in *opcodes and store the results of each opcode
 * into *results. *results must point to an array the same size as
 * *opcodes. Each entry from *results is put into SCR0 prior to
 * executing an opcode so that it may also be used to pass in
 * data. Note that only register r0 is saved and restored so opcodes
 * must not touch other registers.
 */
static int ram_instructions(struct pdbg_target *thread_target, uint64_t *opcodes,
			    uint64_t *results, int len, unsigned int lpar)
{
	uint64_t opcode = 0, r0 = 0, r1 = 0, scratch = 0;
	int i;
	int exception = 0;
	struct thread *thread;
	bool did_setup = false;

	assert(!strcmp(thread_target->class, "thread"));
	thread = target_to_thread(thread_target);

	if (!thread->ram_is_setup) {
		CHECK_ERR(thread->ram_setup(thread));
		did_setup = true;
	}

	/* RAM instructions */
	for (i = -2; i < len + 2; i++) {
		if (i == -2)
			opcode = mtspr(277, 1);
		else if (i == -1)
			/* Save r0 (assumes opcodes don't touch other registers) */
			opcode = mtspr(277, 0);
		else if (i < len) {
			scratch = results[i];
			opcode = opcodes[i];
		} else if (i == len) {
			/* Restore r0 */
			scratch = r0;
			opcode = mfspr(0, 277);
		} else if (i == len + 1) {
			/* Restore r1 */
			scratch = r1;
			opcode = mfspr(1, 277);
		}

		if (thread->ram_instruction(thread, opcode, &scratch)) {
			PR_DEBUG("%s: %d, %016" PRIx64 "\n", __FUNCTION__, __LINE__, opcode);
			exception = 1;
			if (i >= 0 || i < len)
				/* skip the rest and attempt to restore r0 and r1 */
				i = len - 1;
			else
				break;
		}

		if (i == -2)
			r1 = scratch;
		else if (i == -1)
			r0 = scratch;
		else if (i < len)
			results[i] = scratch;
	}

	if (did_setup)
		CHECK_ERR(thread->ram_destroy(thread));
{'fraction_non_alphanumeric': 0.13632766125840917, 'fraction_numerical': 0.031559161060546105, 'mean_word_length': 4.03938185443669, 'pattern_counts': {'":': 0, '<': 84, '<?xml version=': 0, '>': 70, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '567329', 'n_tokens_mistral': 4017, 'n_tokens_neox': 3641, 'n_words': 1093}