/* Chrysalide - Outil d'analyse de fichiers binaires
* break.c - manipulation des points d'arrêt
*
* Copyright (C) 2010-2018 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* Chrysalide is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Chrysalide is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Chrysalide. If not, see .
*/
#include "break.h"
#include
#include
#include "break-int.h"
/******************************************************************************
* *
* Paramètres : bp = point d'arrêt à initialiser. *
* addr = adresse d'action du point d'arrêt. *
* *
* Description : Initialise le coeur d'un point d'arrêt. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void init_raw_breakpoint(raw_breakpoint *bp, virt_t addr)
{
bp->addr = addr;
bp->count = 0;
}
/******************************************************************************
* *
* Paramètres : bp = point d'arrêt à traiter. *
* *
* Description : Libère le coeur d'un point d'arrêt. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void fini_raw_breakpoint(raw_breakpoint *bp)
{
if (bp->count > 1)
free(bp->sources);
free(bp);
}
/******************************************************************************
* *
* Paramètres : bp = point d'arrêt à consulter. *
* *
* Description : Indique l'adresse du point d'arrêt dans la mémoire ciblée. *
* *
* Retour : Adresse associée au point d'arrêt. *
* *
* Remarques : - *
* *
******************************************************************************/
virt_t get_raw_breakpoint_addr(const raw_breakpoint *bp)
{
return bp->addr;
}
/******************************************************************************
* *
* Paramètres : bp = point d'arrêt à consulter. *
* *
* Description : Fournit l'adresse d'origine d'un point d'arrêt de pas à pas. *
* *
* Retour : - *
* *
* Remarques : Un appel à cette fonction n'est valide que pour un point *
* d'arrêt de type RBO_STEP. *
* *
******************************************************************************/
virt_t get_raw_breakpoint_prev_addr(const raw_breakpoint *bp)
{
virt_t result; /* Localisation à retourner */
bool found; /* Valide une obtention */
size_t i; /* Boucle de parcours */
switch (bp->count)
{
case 1:
assert(bp->source.origin == RBO_INTERNAL || bp->source.origin == RBO_STEP);
result = bp->source.previous;
break;
default:
result = VMPA_NO_VIRTUAL;
found = false;
for (i = 0; i < bp->count && !found; i++)
if (bp->sources[i].origin == RBO_INTERNAL || bp->sources[i].origin == RBO_STEP)
{
result = bp->sources[i].previous;
found = true;
}
assert(found);
break;
}
return result;
}
/******************************************************************************
* *
* Paramètres : addr = adresse à consulter. *
* bp = point d'arrêt à consulter. *
* *
* Description : Effectue une comparaison entre adresse et point d'arrêt. *
* *
* Retour : Bilan de la comparaison. *
* *
* Remarques : - *
* *
******************************************************************************/
int compare_raw_breakpoint_with_addr(const virt_t *addr, const raw_breakpoint **bp)
{
int result; /* Bilan à retourner */
if (*addr < (*bp)->addr)
result = -1;
else if (*addr == (*bp)->addr)
result = 0;
else
result = 1;
return result;
}
/******************************************************************************
* *
* Paramètres : a = premier point d'arrêt à consulter. *
* b = second point d'arrêt à consulter. *
* *
* Description : Effectue une comparaison entre deux points d'arrêt. *
* *
* Retour : Bilan de la comparaison. *
* *
* Remarques : - *
* *
******************************************************************************/
int compare_raw_breakpoints(const raw_breakpoint **a, const raw_breakpoint **b)
{
int result; /* Bilan à retourner */
result = compare_raw_breakpoint_with_addr(&(*a)->addr, b);
return result;
}
/******************************************************************************
* *
* Paramètres : bp = point d'arrêt à manipuler. *
* origin = origine de la création du point d'arrêt. *
* tid = identifiant du thread concerné. *
* previous = éventuelle adresse précédent celle du point. *
* *
* Description : Enregistre la source d'un point d'arrêt posé. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void set_raw_breakpoint_origin(raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid, virt_t previous)
{
#ifndef NDEBUG
size_t i; /* Boucle de parcours */
#endif
bp_source *src; /* Source à définir */
bp_source tmp; /* Copie temporaire */
#ifndef NDEBUG
if (bp->count == 1)
assert(bp->source.tid != tid || (bp->source.origin & origin) == 0);
else
for (i = 0; i < bp->count; i++)
if (bp->source.tid == tid)
{
assert((bp->sources[i].origin & origin) == 0);
break;
}
#endif
bp->count++;
switch (bp->count)
{
case 1:
src = &bp->source;
break;
case 2:
tmp = bp->source;
bp->sources = (bp_source *)calloc(2, sizeof(bp_source));
bp->sources[0] = tmp;
src = &bp->sources[1];
break;
default:
bp->sources = (bp_source *)realloc(bp->sources, bp->count * sizeof(bp_source));
src = &bp->sources[bp->count - 1];
break;
}
src->origin = origin;
src->tid = tid;
src->previous = previous;
}
/******************************************************************************
* *
* Paramètres : bp = point d'arrêt à manipuler. *
* origin = origine de la création du point d'arrêt. *
* tid = identifiant du thread concerné. *
* previous = éventuelle adresse précédent celle du point. *
* *
* Description : Oublie la source d'un point d'arrêt posé. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void unset_raw_breakpoint_origin(raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid)
{
size_t i; /* Boucle de parcours #1 */
bp_source tmp; /* Copie temporaire */
#ifndef NDEBUG
size_t j; /* Boucle de parcours #2 */
#endif
bool has_same_origin(bp_source *src)
{
bool result;
result = (src->origin == origin && src->tid == tid);
return result;
}
switch (bp->count)
{
case 1:
if (has_same_origin(&bp->source))
bp->count = 0;
break;
case 2:
if (has_same_origin(&bp->sources[0]))
{
assert(!has_same_origin(&bp->sources[1]));
tmp = bp->sources[1];
bp->count = 1;
free(bp->sources);
bp->source = tmp;
}
else if (has_same_origin(&bp->sources[1]))
{
assert(!has_same_origin(&bp->sources[0]));
tmp = bp->sources[0];
bp->count = 1;
free(bp->sources);
bp->source = tmp;
}
break;
default:
for (i = 0; i < bp->count; i++)
{
if (has_same_origin(&bp->sources[i]))
{
if ((i + 1) < bp->count)
memmove(&bp->sources[i], &bp->sources[i + 1], (bp->count - i - 1) * sizeof(bp_source));
bp->sources = (bp_source *)realloc(bp->sources, --bp->count * sizeof(bp_source));
#ifndef NDEBUG
for (j = i; j < bp->count; j++)
assert(!has_same_origin(&bp->sources[j]));
#endif
break;
}
}
break;
}
}
/******************************************************************************
* *
* Paramètres : bp = point d'arrêt à manipuler. *
* origin = origine de la création du point d'arrêt. *
* tid = identifiant du thread concerné. *
* *
* Description : Indique si le point d'arrêt correspond à une source donnée. *
* *
* Retour : Bilan de l'analyse. *
* *
* Remarques : - *
* *
******************************************************************************/
bool has_raw_breakpoint_origin(const raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid)
{
bool result; /* Conclusion à retourner */
size_t i; /* Boucle de parcours */
if (bp->count == 1)
result = (bp->source.tid == tid && (bp->source.origin & origin) != 0);
else
{
result = false;
for (i = 0; i < bp->count && !result; i++)
result = (bp->sources[i].tid == tid && (bp->sources[i].origin & origin) != 0);
}
return result;
}
/******************************************************************************
* *
* Paramètres : bp = point d'arrêt à manipuler. *
* origin = origine de la création du point d'arrêt. *
* tid = identifiant du thread concerné. *
* prev = adresse d'instruction qui a conduit à des poses. *
* *
* Description : Indique si le point d'arrêt correspond à une origine donnée. *
* *
* Retour : Bilan de l'analyse. *
* *
* Remarques : - *
* *
******************************************************************************/
bool has_raw_breakpoint_previous_address(const raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid, virt_t prev)
{
bool result; /* Conclusion à retourner */
size_t i; /* Boucle de parcours */
if (bp->count == 1)
result = (bp->source.tid == tid && (bp->source.origin & origin) != 0 && bp->source.previous == prev);
else
{
result = false;
for (i = 0; i < bp->count && !result; i++)
result = (bp->sources[i].tid == tid && (bp->sources[i].origin & origin) != 0 && bp->sources[i].previous == prev);
}
return result;
}
/******************************************************************************
* *
* Paramètres : bp = point d'arrêt à consulter. *
* *
* Description : Indique si un point d'arrêt a encore une utilité. *
* *
* Retour : true si le point peut être retiré, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
bool is_breakpoint_useless(const raw_breakpoint *bp)
{
bool result; /* Conclusion à faire remonter */
result = (bp->count == 0);
return result;
}