305 lines
8.4 KiB
C
305 lines
8.4 KiB
C
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
/**
|
|
* \file bgp/vm_dump.c
|
|
*
|
|
* BGP VM bytecode dump.
|
|
*
|
|
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
|
* \author Lorenzo Cogotti
|
|
*/
|
|
|
|
#include "bgp/vmintrin.h"
|
|
|
|
#include "sys/dbg.h"
|
|
#include "numlib.h"
|
|
#include "strlib.h"
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#define LINEDIGS 5
|
|
#define MAXOPCSTRLEN 6
|
|
#define CODELINELEN 50
|
|
#define MAXINDENT 8
|
|
#define INDENTLEN 2
|
|
#define COMMENTLEN 70
|
|
|
|
static const char *OpcString(Bgpvmopc opc)
|
|
{
|
|
// NOTE: Invariant: strlen(return) <= MAXOPCSTRLEN
|
|
switch (opc) {
|
|
case BGP_VMOP_NOP: return "NOP";
|
|
case BGP_VMOP_LOAD: return "LOAD";
|
|
case BGP_VMOP_LOADU: return "LOADU";
|
|
case BGP_VMOP_LOADN: return "LOADN";
|
|
case BGP_VMOP_LOADK: return "LOADK";
|
|
case BGP_VMOP_CALL: return "CALL";
|
|
case BGP_VMOP_BLK: return "BLK";
|
|
case BGP_VMOP_ENDBLK: return "ENDBLK";
|
|
case BGP_VMOP_TAG: return "TAG";
|
|
case BGP_VMOP_NOT: return "NOT";
|
|
case BGP_VMOP_CFAIL: return "CFAIL";
|
|
case BGP_VMOP_CPASS: return "CPASS";
|
|
case BGP_VMOP_ORFAIL: return "ORFAIL";
|
|
case BGP_VMOP_ORPASS: return "ORPASS";
|
|
case BGP_VMOP_JZ: return "JZ";
|
|
case BGP_VMOP_JNZ: return "JNZ";
|
|
case BGP_VMOP_CHKT: return "CHKT";
|
|
case BGP_VMOP_CHKA: return "CHKA";
|
|
case BGP_VMOP_EXCT: return "EXCT";
|
|
case BGP_VMOP_SUPN: return "SUPN";
|
|
case BGP_VMOP_SUBN: return "SUBN";
|
|
case BGP_VMOP_RELT: return "RELT";
|
|
case BGP_VMOP_ASMTCH: return "ASMTCH";
|
|
case BGP_VMOP_COMTCH: return "COMTCH";
|
|
case BGP_VMOP_ACOMTC: return "ACOMTC";
|
|
case BGP_VMOP_END: return "END";
|
|
default: return "???";
|
|
}
|
|
}
|
|
|
|
static const char *BgpTypeString(BgpType typ)
|
|
{
|
|
switch (typ) {
|
|
case BGP_OPEN: return "OPEN";
|
|
case BGP_UPDATE: return "UPDATE";
|
|
case BGP_NOTIFICATION: return "NOTIFICATION";
|
|
case BGP_KEEPALIVE: return "KEEPALIVE";
|
|
case BGP_ROUTE_REFRESH: return "ROUTE_REFRESH";
|
|
case BGP_CLOSE: return "CLOSE";
|
|
default: return NULL;
|
|
}
|
|
}
|
|
|
|
static const char *BgpAttrString(BgpAttrCode code)
|
|
{
|
|
switch (code) {
|
|
case BGP_ATTR_ORIGIN: return "ORIGIN";
|
|
case BGP_ATTR_AS_PATH: return "AS_PATH";
|
|
case BGP_ATTR_NEXT_HOP: return "NEXT_HOP";
|
|
case BGP_ATTR_MULTI_EXIT_DISC: return "MULTI_EXIT_DISC";
|
|
case BGP_ATTR_LOCAL_PREF: return "LOCAL_PREF";
|
|
case BGP_ATTR_ATOMIC_AGGREGATE: return "ATOMIC_AGGREGATE";
|
|
case BGP_ATTR_AGGREGATOR: return "AGGREGATOR";
|
|
case BGP_ATTR_COMMUNITY: return "COMMUNITY";
|
|
case BGP_ATTR_ORIGINATOR_ID: return "ORIGINATOR_ID";
|
|
case BGP_ATTR_CLUSTER_LIST: return "CLUSTER_LIST";
|
|
case BGP_ATTR_DPA: return "DPA";
|
|
case BGP_ATTR_ADVERTISER: return "ADVERTISER";
|
|
case BGP_ATTR_RCID_PATH_CLUSTER_ID: return "RCID_PATH_CLUSTER_ID";
|
|
case BGP_ATTR_MP_REACH_NLRI: return "MP_REACH_NLRI";
|
|
case BGP_ATTR_MP_UNREACH_NLRI: return "MP_UNREACH_NLRI";
|
|
case BGP_ATTR_EXTENDED_COMMUNITY: return "EXTENDED_COMMUNITY";
|
|
case BGP_ATTR_AS4_PATH: return "AS4_PATH";
|
|
case BGP_ATTR_AS4_AGGREGATOR: return "AS4_AGGREGATOR";
|
|
case BGP_ATTR_SAFI_SSA: return "SAFI_SSA";
|
|
case BGP_ATTR_CONNECTOR: return "CONNECTOR";
|
|
case BGP_ATTR_AS_PATHLIMIT: return "AS_PATHLIMIT";
|
|
case BGP_ATTR_PMSI_TUNNEL: return "PMSI_TUNNEL";
|
|
case BGP_ATTR_TUNNEL_ENCAPSULATION: return "TUNNEL_ENCAPSULATION";
|
|
case BGP_ATTR_TRAFFIC_ENGINEERING: return "TRAFFIC_ENGINEERING";
|
|
case BGP_ATTR_IPV6_ADDRESS_SPECIFIC_EXTENDED_COMMUNITY: return "IPV6_ADDRESS_SPECIFIC_EXTENDED_COMMUNITY";
|
|
case BGP_ATTR_AIGP: return "AIGP";
|
|
case BGP_ATTR_PE_DISTINGUISHER_LABELS: return "PE_DISTINGUISHER_LABELS";
|
|
case BGP_ATTR_ENTROPY_LEVEL_CAPABILITY: return "ENTROPY_LEVEL_CAPABILITY";
|
|
case BGP_ATTR_LS: return "LS";
|
|
case BGP_ATTR_LARGE_COMMUNITY: return "LARGE_COMMUNITY";
|
|
case BGP_ATTR_BGPSEC_PATH: return "BGPSEC_PATH";
|
|
case BGP_ATTR_COMMUNITY_CONTAINER: return "COMMUNITY_CONTAINER";
|
|
case BGP_ATTR_PREFIX_SID: return "PREFIX_SID";
|
|
case BGP_ATTR_SET: return "SET";
|
|
default: return NULL;
|
|
}
|
|
}
|
|
|
|
static const char *NetOpArgString(Uint8 opa)
|
|
{
|
|
switch (opa) {
|
|
case BGP_VMOPA_NLRI: return "NLRI";
|
|
case BGP_VMOPA_MPREACH: return "MP_REACH_NLRI";
|
|
case BGP_VMOPA_ALL_NLRI: return "ALL_NLRI";
|
|
case BGP_VMOPA_WITHDRAWN: return "WITHDRAWN";
|
|
case BGP_VMOPA_MPUNREACH: return "MP_UNREACH_NLRI";
|
|
case BGP_VMOPA_ALL_WITHDRAWN: return "ALL_WITHDRAWN";
|
|
default: return NULL;
|
|
}
|
|
}
|
|
|
|
static char *ExplainJump(char *buf, Uint32 ip, Uint8 disp, Uint32 progLen)
|
|
{
|
|
char *p = buf;
|
|
|
|
strcpy(p, "to line: "); p += 9;
|
|
|
|
Uint32 target = ip + 1;
|
|
target += 1 + disp;
|
|
|
|
p = Utoa(target, p);
|
|
if (target > progLen)
|
|
strcpy(p, " (JUMP TARGET OUT OF BOUNDS!)");
|
|
|
|
return buf;
|
|
}
|
|
|
|
static char *Indent(char *p, Bgpvmopc opc, int level)
|
|
{
|
|
int n = CLAMP(level, 0, MAXINDENT);
|
|
int last = n - 1;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
*p++ = (opc == BGP_VMOP_ENDBLK && i == last) ? '+' : '|';
|
|
for (int j = 1; j < INDENTLEN; j++)
|
|
*p++ = (opc == BGP_VMOP_ENDBLK && i == last) ? '-' : ' ';
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static char *CommentCodeLine(char *line, const char *comment)
|
|
{
|
|
char *p = line;
|
|
|
|
p += Df_strpadr(p, ' ', CODELINELEN);
|
|
|
|
*p++ = ' ';
|
|
*p++ = ';'; *p++ = ' ';
|
|
|
|
size_t n = strlen(comment);
|
|
if (3 + n >= COMMENTLEN) {
|
|
n = COMMENTLEN - 3 - 3;
|
|
|
|
memcpy(p, comment, n);
|
|
p += n;
|
|
*p++ = '.'; *p++ = '.'; *p++ = '.';
|
|
} else {
|
|
memcpy(p, comment, n);
|
|
p += n;
|
|
}
|
|
|
|
*p = '\0';
|
|
return p;
|
|
}
|
|
|
|
void Bgp_VmDumpProgram(Bgpvm *vm, void *streamp, const StmOps *ops)
|
|
{
|
|
char explainbuf[64];
|
|
char buf[256];
|
|
|
|
int indent = 0;
|
|
|
|
// NOTE: <= so it includes trailing END
|
|
for (Uint32 ip = 0; ip <= vm->progLen; ip++) {
|
|
Bgpvmbytec ir = vm->prog[ip];
|
|
Bgpvmopc opc = BGP_VMOPC(ir);
|
|
Uint8 opa = BGP_VMOPARG(ir);
|
|
|
|
const char *opcnam = OpcString(opc);
|
|
assert(strlen(opcnam) <= MAXOPCSTRLEN);
|
|
|
|
char *p = buf;
|
|
|
|
// Line number
|
|
Utoa(ip+1, p);
|
|
p += Df_strpadl(p, '0', LINEDIGS);
|
|
|
|
*p++ = ':';
|
|
*p++ = ' ';
|
|
|
|
// Instruction hex dump
|
|
*p++ = '0';
|
|
*p++ = 'x';
|
|
Xtoa(ir, p);
|
|
p += Df_strpadl(p, '0', XDIGS(ir));
|
|
*p++ = ' ';
|
|
|
|
// Code indent
|
|
p = Indent(p, opc, indent);
|
|
|
|
// Opcode
|
|
strcpy(p, opcnam);
|
|
p += Df_strpadr(p, ' ', MAXOPCSTRLEN);
|
|
|
|
// Instruction argument
|
|
const char *opastr = NULL;
|
|
switch (opc) {
|
|
case BGP_VMOP_LOAD:
|
|
*p++ = ' ';
|
|
|
|
p = Itoa((Sint8) opa, p);
|
|
|
|
break;
|
|
case BGP_VMOP_LOADU:
|
|
case BGP_VMOP_JZ:
|
|
case BGP_VMOP_JNZ:
|
|
*p++ = ' ';
|
|
|
|
p = Utoa(opa, p);
|
|
if (opc == BGP_VMOP_JZ || opc == BGP_VMOP_JNZ)
|
|
opastr = ExplainJump(explainbuf, ip, opa, vm->progLen);
|
|
|
|
break;
|
|
case BGP_VMOP_TAG:
|
|
case BGP_VMOP_CHKT:
|
|
case BGP_VMOP_CHKA:
|
|
case BGP_VMOP_EXCT:
|
|
case BGP_VMOP_SUBN:
|
|
case BGP_VMOP_SUPN:
|
|
case BGP_VMOP_RELT:
|
|
*p++ = ' ';
|
|
*p++ = '0'; *p++ = 'x';
|
|
|
|
Xtoa(opa, p);
|
|
p += Df_strpadl(p, '0', XDIGS(opa));
|
|
|
|
if (opc == BGP_VMOP_CHKT)
|
|
opastr = BgpTypeString(opa);
|
|
else if (opc == BGP_VMOP_CHKA)
|
|
opastr = BgpAttrString(opa);
|
|
else
|
|
opastr = NetOpArgString(opa);
|
|
|
|
break;
|
|
case BGP_VMOP_LOADK:
|
|
*p++ = ' ';
|
|
*p++ = 'K';
|
|
*p++ = '[';
|
|
p = Utoa(opa, p);
|
|
*p++ = ']';
|
|
*p = '\0';
|
|
break;
|
|
case BGP_VMOP_CALL:
|
|
*p++ = ' ';
|
|
*p++ = 'F';
|
|
*p++ = 'N';
|
|
*p++ = '[';
|
|
p = Utoa(opa, p);
|
|
*p++ = ']';
|
|
*p = '\0';
|
|
|
|
if (opa < vm->nfuncs) {
|
|
Funsym fsym;
|
|
|
|
fsym.func = (void (*)(void)) vm->funcs[opa];
|
|
opastr = Sys_GetSymbolName(fsym.sym);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Optional comment after CODELINELEN columns
|
|
if (opastr)
|
|
p = CommentCodeLine(buf, opastr);
|
|
|
|
// Flush line (no need for '\0')
|
|
*p++ = '\n';
|
|
ops->Write(streamp, buf, p - buf);
|
|
|
|
// Update indent
|
|
if (opc == BGP_VMOP_BLK)
|
|
indent++;
|
|
if (opc == BGP_VMOP_ENDBLK)
|
|
indent--;
|
|
}
|
|
}
|