/* Chrysalide - Outil d'analyse de fichiers binaires
 * symbol.c - gestion des symboles dans un binaire
 *
 * Copyright (C) 2009-2012 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 Foobar.  If not, see .
 */
#include "symbol.h"
#include 
#include 
#include "../glibext/linegen-int.h"
/* --------------------- FONCTIONNALITES BASIQUES POUR SYMBOLES --------------------- */
/* Symbole d'exécutable (instance) */
struct _GBinSymbol
{
    GObject parent;                         /* A laisser en premier        */
    SymbolType type;                        /* Type du symbole             */
    bool block_start;                       /* Début d'un bloc ?           */
    char *alt;                              /* Nom alternatif              */
    union
    {
        GArchInstruction *instr;            /* Instruction correspondante  */
        GBinRoutine *routine;               /* Compléments pour fonction   */
    } extra;
    GDbComment *comment;                    /* Eventuel commentaire lié    */
};
/* Symbole d'exécutable (classe) */
struct _GBinSymbolClass
{
    GObjectClass parent;                    /* A laisser en premier        */
};
/* Initialise la classe des symboles d'exécutables. */
static void g_binary_symbol_class_init(GBinSymbolClass *);
/* Initialise une instance de symbole d'exécutable. */
static void g_binary_symbol_init(GBinSymbol *);
/* Procède à l'initialisation de l'interface de génération. */
static void g_binary_symbol_interface_init(GLineGeneratorInterface *);
/* Supprime toutes les références externes. */
static void g_binary_symbol_dispose(GBinSymbol *);
/* Procède à la libération totale de la mémoire. */
static void g_binary_symbol_finalize(GBinSymbol *);
/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
/* Indique le nombre de ligne prêtes à être générées. */
static size_t g_binary_symbol_count_lines(const GBinSymbol *);
/* Retrouve l'emplacement correspondant à une position donnée. */
static void g_binary_symbol_compute_addr(const GBinSymbol *, gint, vmpa2t *, size_t, size_t);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
static int g_binary_symbol_contains_addr(const GBinSymbol *, const vmpa2t *, size_t, size_t);
/* Renseigne sur les propriétés liées à un générateur. */
static BufferLineFlags g_binary_symbol_get_flags(const GBinSymbol *, size_t, size_t);
/* Imprime dans une ligne de rendu le contenu représenté. */
static void g_binary_symbol_print(GBinSymbol *, GBufferLine *, size_t, size_t);
/* ---------------------------------------------------------------------------------- */
/*                       FONCTIONNALITES BASIQUES POUR SYMBOLES                       */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour un symbole d'exécutable. */
G_DEFINE_TYPE_WITH_CODE(GBinSymbol, g_binary_symbol, G_TYPE_OBJECT,
                        G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_binary_symbol_interface_init));
/******************************************************************************
*                                                                             *
*  Paramètres  : klass = classe à initialiser.                                *
*                                                                             *
*  Description : Initialise la classe des symboles d'exécutables.             *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_binary_symbol_class_init(GBinSymbolClass *klass)
{
    GObjectClass *object;                   /* Autre version de la classe  */
    object = G_OBJECT_CLASS(klass);
    object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_symbol_dispose;
    object->finalize = (GObjectFinalizeFunc)g_binary_symbol_finalize;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = instance à initialiser.                             *
*                                                                             *
*  Description : Initialise une instance de symbole d'exécutable.             *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_binary_symbol_init(GBinSymbol *symbol)
{
}
/******************************************************************************
*                                                                             *
*  Paramètres  : iface = interface GLib à initialiser.                        *
*                                                                             *
*  Description : Procède à l'initialisation de l'interface de génération.     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_binary_symbol_interface_init(GLineGeneratorInterface *iface)
{
    iface->count = (linegen_count_lines_fc)g_binary_symbol_count_lines;
    iface->compute = (linegen_compute_fc)g_binary_symbol_compute_addr;
    iface->contains = (linegen_contains_fc)g_binary_symbol_contains_addr;
    iface->get_flags = (linegen_get_flags_fc)g_binary_symbol_get_flags;
    iface->print = (linegen_print_fc)g_binary_symbol_print;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = instance d'objet GLib à traiter.                    *
*                                                                             *
*  Description : Supprime toutes les références externes.                     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_binary_symbol_dispose(GBinSymbol *symbol)
{
    /* TODO... */
    G_OBJECT_CLASS(g_binary_symbol_parent_class)->dispose(G_OBJECT(symbol));
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = instance d'objet GLib à traiter.                    *
*                                                                             *
*  Description : Procède à la libération totale de la mémoire.                *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_binary_symbol_finalize(GBinSymbol *symbol)
{
    free(symbol->alt);
    G_OBJECT_CLASS(g_binary_symbol_parent_class)->finalize(G_OBJECT(symbol));
}
/******************************************************************************
*                                                                             *
*  Paramètres  : type = type de symbole à créer.                              *
*                                                                             *
*  Description : Crée un nouveau symbole d'exécutable.                        *
*                                                                             *
*  Retour      : Adresse de l'instance mise en place ou NULL en cas d'échec.  *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
GBinSymbol *g_binary_symbol_new(SymbolType type)
{
    GBinSymbol *result;                     /* Nouveau symbole à renvoyer  */
    result = g_object_new(G_TYPE_BIN_SYMBOL, NULL);
    result->type = type;
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : a = premier symbole à analyser.                              *
*                b = second symbole à analyser.                               *
*                                                                             *
*  Description : Compare deux symboles d'exécutable selon leurs propriétés.   *
*                                                                             *
*  Retour      : Bilan de la comparaison : -1, 0 ou 1 (-1 par défaut).        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
int g_binary_symbol_cmp(const GBinSymbol **a, const GBinSymbol **b)
{
    int result;                             /* Bilan à retourner           */
	const mrange_t *ra;						/* Emplacement du symbole A	   */
	const mrange_t *rb;						/* Emplacement du symbole B	   */
	ra = g_binary_symbol_get_range(*a);
	rb = g_binary_symbol_get_range(*b);
	if (ra == NULL && rb == NULL)
		result = 0;
	else if (ra != NULL && rb == NULL)
		result = 1;
	else if (ra == NULL && rb != NULL)
		result = -1;
	else
        result = cmp_mrange(ra, rb);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à analyser.                                 *
*                addr   = localisation à venir comparer à celle du symbole.   *
*                                                                             *
*  Description : Compare un symbole et une localisation.                      *
*                                                                             *
*  Retour      : Bilan de la comparaison : -1, 0 ou 1 (-1 par défaut).        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
int g_binary_symbol_cmp_with_vmpa(const GBinSymbol *symbol, const vmpa2t *addr)
{
    int result;                             /* Bilan à retourner           */
    const mrange_t *range;                  /* Emplacement du symbole      */
    range = g_binary_symbol_get_range(symbol);
    if (range == NULL)
        result = 1;
    else
        result = cmp_mrange_with_vmpa(range, addr);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir consulter.                          *
*                                                                             *
*  Description : Fournit le type du symbole.                                  *
*                                                                             *
*  Retour      : Type de symbole représenté.                                  *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
SymbolType g_binary_symbol_get_target_type(const GBinSymbol *symbol)
{
    return symbol->type;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir compléter.                          *
*                start  = indication quant à la nature du symbole.            *
*                                                                             *
*  Description : Définit si un symbole est susceptible de démarrer un bloc.   *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_binary_symbol_define_as_block_start(GBinSymbol *symbol, bool start)
{
    symbol->block_start = start;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir consulter.                          *
*                                                                             *
*  Description : Indique si un symbole est susceptible de démarrer un bloc.   *
*                                                                             *
*  Retour      : Capacité de rassemblement du symbole.                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool g_binary_symbol_is_block_start(GBinSymbol *symbol)
{
    bool result;                            /* Statut à retourner          */
    switch (g_binary_symbol_get_target_type(symbol))
    {
        case STP_ROUTINE:
        case STP_OBJECT:
        case STP_FUNCTION:
        case STP_ENTRY_POINT:
        case STP_STRING:
        case STP_RO_STRING:
            result = true;
            break;
        default:
            result = false;
            break;
    }
    result |= symbol->block_start;
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir consulter.                          *
*                                                                             *
*  Description : Fournit un étiquette pour viser un symbole.                  *
*                                                                             *
*  Retour      : Chaîne de caractères renvoyant au symbole.                   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
const char *g_binary_symbol_get_label(const GBinSymbol *symbol)
{
    const char *result;                     /* Etiquette à retourner       */
    if (symbol->alt != NULL)
        return symbol->alt;
    result = NULL;
    switch (symbol->type)
    {
        case STP_ROUTINE:
        case STP_ENTRY_POINT:
        case STP_CODE_LABEL:
            result = g_binary_routine_get_declarator(symbol->extra.routine, false);
            break;
        default:
            result = NULL;
            break;
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir consulter.                          *
*                alt    = désignation humaine alternative à favoriser.        *
*                                                                             *
*  Description : Définit un autre nom pour le symbole.                        *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_binary_symbol_set_alt_label(GBinSymbol *symbol, const char *alt)
{
    if (symbol->alt != NULL)
        free(symbol->alt);
    if (alt == NULL)
        symbol->alt = NULL;
    else
        symbol->alt = strdup(alt);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir mettre à jour.                      *
*                full   = adresse dont la définition est complète.            *
*                                                                             *
*  Description : Raffine la définition de l'emplacement d'un symbole.         *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_binary_symbol_fix_range(GBinSymbol *symbol, const vmpa2t *full)
{
    GArchInstruction *instr;                /* Instruction associée        */
    mrange_t range;                         /* Plage à manipuler           */
    GBinRoutine *routine;                   /* Routine associée            */
    switch (symbol->type)
    {
        case STP_DATA:
        case STP_RO_STRING:
            instr = g_binary_symbol_get_instruction(symbol);
            copy_mrange(&range, g_arch_instruction_get_range(instr));
            assert(cmp_vmpa(get_mrange_addr(&range), full) == 0);
            copy_vmpa(get_mrange_addr(&range), full);
            g_arch_instruction_set_range(instr, &range);
            break;
        case STP_ROUTINE:
        case STP_ENTRY_POINT:
        case STP_CODE_LABEL:
            routine = g_binary_symbol_get_routine(symbol);
            copy_mrange(&range, g_binary_routine_get_range(routine));
            assert(cmp_vmpa(get_mrange_addr(&range), full) == 0);
            copy_vmpa(get_mrange_addr(&range), full);
            g_binary_routine_set_range(routine, &range);
            break;
        default:
            break;
    }
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir consulter.                          *
*                                                                             *
*  Description : Fournit l'emplacement où se situe un symbole.                *
*                                                                             *
*  Retour      : Zone mémoire couverte par le symbole.                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
const mrange_t *g_binary_symbol_get_range(const GBinSymbol *symbol)
{
    const mrange_t *result;                 /* Plage à retourner           */
    result = NULL;
    switch (symbol->type)
    {
        case STP_DATA:
        case STP_RO_STRING:
            result = g_arch_instruction_get_range(symbol->extra.instr);
            break;
        case STP_ROUTINE:
        case STP_ENTRY_POINT:
        case STP_CODE_LABEL:
            result = g_binary_routine_get_range(symbol->extra.routine);
            break;
        default:
            /* FIXME : assert(0); */
            result = NULL;
            break;
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol  = symbole à venir consulter.                         *
*                routine = prototype de la fonction représentée.              *
*                type    = (nouveau) type du symbole attaché.                 *
*                                                                             *
*  Description : Attache la routine associée au symbole.                      *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void _g_binary_symbol_attach_routine(GBinSymbol *symbol, GBinRoutine *routine, SymbolType type)
{
    if (symbol->extra.routine != NULL)
        g_object_unref(G_OBJECT(symbol->extra.routine));
    symbol->type = type;
    symbol->extra.routine = routine;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol  = symbole à venir consulter.                         *
*                routine = prototype de la fonction représentée.              *
*                                                                             *
*  Description : Attache la routine associée au symbole.                      *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_binary_symbol_attach_routine(GBinSymbol *symbol, GBinRoutine *routine)
{
    _g_binary_symbol_attach_routine(symbol, routine, symbol->type);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir manipuler.                          *
*                instr  = représentation du symbole associé.                  *
*                                                                             *
*  Description : Attache l'instruction associée au symbole.                   *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_binary_symbol_attach_instruction(GBinSymbol *symbol, GArchInstruction *instr)
{
    if (symbol->type != STP_RO_STRING)
    symbol->type = STP_DATA;
    symbol->extra.instr = instr;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir consulter.                          *
*                                                                             *
*  Description : Fournit l'éventuelle routine associée au symbole.            *
*                                                                             *
*  Retour      : Instance GLib en place ou NULL si aucune.                    *
*                                                                             *
*  Remarques   : Il n'y a pas de transfert de propriété ici !                 *
*                                                                             *
******************************************************************************/
GBinRoutine *g_binary_symbol_get_routine(const GBinSymbol *symbol)
{
    /* TODO : rajouter des assert() sur le type de symbole */
    return symbol->extra.routine;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir consulter.                          *
*                                                                             *
*  Description : Fournit l'éventuelle instruction associée au symbole.        *
*                                                                             *
*  Retour      : Instance GLib en place ou NULL si aucune.                    *
*                                                                             *
*  Remarques   : Il n'y a pas de transfert de propriété ici !                 *
*                                                                             *
******************************************************************************/
GArchInstruction *g_binary_symbol_get_instruction(const GBinSymbol *symbol)
{
    /* TODO : rajouter des assert() sur le type de symbole */
    return symbol->extra.instr;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol  = symbole à venir manipuler.                         *
*                comment = commentaire construit à propos du symbole.         *
*                                                                             *
*  Description : Ajoute un commentaire facultatif au symbole.                 *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_binary_symbol_set_comment(GBinSymbol *symbol, GDbComment *comment)
{
#ifndef NDEBUG
    const vmpa2t *saddr;                    /* Adresse du symbole          */
    const vmpa2t *caddr;                    /* Adresse du commentaire      */
#endif
#ifndef NDEBUG
    saddr = get_mrange_addr(g_binary_symbol_get_range(symbol));
    caddr = g_db_comment_get_address(comment);
    assert(cmp_vmpa(saddr, caddr) == 0);
#endif
    symbol->comment = comment;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = symbole à venir consulter.                          *
*                                                                             *
*  Description : Fournit l'éventuel commentaire associé au symbole.           *
*                                                                             *
*  Retour      : Instance GLib en place ou NULL si aucune.                    *
*                                                                             *
*  Remarques   : Il n'y a pas de transfert de propriété ici !                 *
*                                                                             *
******************************************************************************/
GDbComment *g_binary_symbol_get_comment(const GBinSymbol *symbol)
{
    return symbol->comment;
}
/* ---------------------------------------------------------------------------------- */
/*                          OFFRE DE CAPACITES DE GENERATION                          */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = générateur à consulter pour futur usage.            *
*                                                                             *
*  Description : Détermine si un symbole pour faire office de générateur.     *
*                                                                             *
*  Retour      : Instance de générateur si les capacités sont là.             *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
GLineGenerator *g_binary_symbol_produce_label(GBinSymbol *symbol)
{
    GLineGenerator *result;                 /* Instance à retourner        */
    const char *label;                      /* Etiquette à insérer         */
    label = g_binary_symbol_get_label(symbol);
    result = (label != NULL ? G_LINE_GENERATOR(symbol) : NULL);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = générateur à consulter.                             *
*                                                                             *
*  Description : Indique le nombre de ligne prêtes à être générées.           *
*                                                                             *
*  Retour      : Nombre de lignes devant apparaître au final.                 *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static size_t g_binary_symbol_count_lines(const GBinSymbol *symbol)
{
    return 1;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = générateur à consulter.                             *
*                x      = position géographique sur la ligne concernée.       *
*                addr   = position en mémoire à analyser.                     *
*                index  = indice de cette même ligne dans le tampon global.   *
*                repeat = indice d'utilisations successives du générateur.    *
*                                                                             *
*  Description : Retrouve l'emplacement correspondant à une position donnée.  *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_binary_symbol_compute_addr(const GBinSymbol *symbol, gint x, vmpa2t *addr, size_t index, size_t repeat)
{
    const mrange_t *range;                  /* Emplacement à manipuler     */
    range = g_binary_symbol_get_range(symbol);
    copy_vmpa(addr, get_mrange_addr(range));
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = générateur à consulter.                             *
*                addr   = position en mémoire à analyser.                     *
*                index  = indice de cette même ligne dans le tampon global.   *
*                repeat = indice d'utilisations successives du générateur.    *
*                                                                             *
*  Description : Détermine si le conteneur s'inscrit dans une plage donnée.   *
*                                                                             *
*  Retour      : Bilan de la détermination, utilisable en comparaisons.       *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static int g_binary_symbol_contains_addr(const GBinSymbol *symbol, const vmpa2t *addr, size_t index, size_t repeat)
{
    int result;                             /* Conclusion à retourner      */
    const mrange_t *range;                  /* Emplacement à manipuler     */
    range = g_binary_symbol_get_range(symbol);
    result = cmp_mrange_with_vmpa(range, addr);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = générateur à consulter.                             *
*                index  = indice de cette même ligne dans le tampon global.   *
*                repeat = indice d'utilisations successives du générateur.    *
*                                                                             *
*  Description : Renseigne sur les propriétés liées à un générateur.          *
*                                                                             *
*  Retour      : Propriétés particulières associées.                          *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static BufferLineFlags g_binary_symbol_get_flags(const GBinSymbol *symbol, size_t index, size_t repeat)
{
    return BLF_IS_LABEL;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : symbol = générateur à utiliser pour l'impression.            *
*                line   = ligne de rendu à compléter.                         *
*                index  = indice de cette même ligne dans le tampon global.   *
*                repeat = indice d'utilisations successives du générateur.    *
*                                                                             *
*  Description : Imprime dans une ligne de rendu le contenu représenté.       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_binary_symbol_print(GBinSymbol *symbol, GBufferLine *line, size_t index, size_t repeat)
{
    const mrange_t *range;                  /* Emplacement à manipuler     */
    const char *label;                      /* Etiquette à insérer         */
    range = g_binary_symbol_get_range(symbol);
    g_buffer_line_fill_vmpa(line, get_mrange_addr(range), MDS_32_BITS_UNSIGNED, MDS_32_BITS_UNSIGNED);
    label = g_binary_symbol_get_label(symbol);
    g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
    g_buffer_line_append_text(line, BLC_ASSEMBLY_HEAD, SL(label), RTT_LABEL, NULL);
    g_buffer_line_append_text(line, BLC_ASSEMBLY_HEAD, ":", 1, RTT_PUNCT, NULL);
}