From 91f1acd85f735f310291fcce891feae9235a21d2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 6 Oct 2019 13:24:21 -0400 Subject: [PATCH] Add --protect-ids to obscure information in objects, bug1521. --- Changes | 2 + bin/verilator | 49 +++++++ src/V3Ast.cpp | 5 + src/V3Ast.h | 7 +- src/V3AstNodes.cpp | 10 +- src/V3AstNodes.h | 1 + src/V3Clock.cpp | 1 + src/V3EmitC.cpp | 200 ++++++++++++++------------- src/V3EmitCBase.h | 10 +- src/V3EmitCSyms.cpp | 74 +++++----- src/V3Error.h | 3 +- src/V3File.cpp | 121 ++++++++++++++++ src/V3File.h | 20 ++- src/V3LinkLevel.cpp | 2 + src/V3Name.cpp | 1 + src/V3Options.cpp | 36 +++++ src/V3Options.h | 7 + src/V3Os.cpp | 13 ++ src/V3Os.h | 1 + src/V3Task.cpp | 20 ++- src/Verilator.cpp | 3 + test_regress/t/t_dpi_accessors.cpp | 4 +- test_regress/t/t_protect_ids.pl | 52 +++++++ test_regress/t/t_protect_ids.v | 61 ++++++++ test_regress/t/t_protect_ids_bad.out | 8 ++ test_regress/t/t_protect_ids_bad.pl | 23 +++ test_regress/t/t_protect_ids_bad.v | 7 + test_regress/t/t_protect_ids_c.cpp | 51 +++++++ test_regress/t/t_protect_ids_key.out | 42 ++++++ test_regress/t/t_protect_ids_key.pl | 27 ++++ 30 files changed, 723 insertions(+), 138 deletions(-) create mode 100755 test_regress/t/t_protect_ids.pl create mode 100644 test_regress/t/t_protect_ids.v create mode 100644 test_regress/t/t_protect_ids_bad.out create mode 100755 test_regress/t/t_protect_ids_bad.pl create mode 100644 test_regress/t/t_protect_ids_bad.v create mode 100644 test_regress/t/t_protect_ids_c.cpp create mode 100644 test_regress/t/t_protect_ids_key.out create mode 100755 test_regress/t/t_protect_ids_key.pl diff --git a/Changes b/Changes index 1bb71a385..10285fb52 100644 --- a/Changes +++ b/Changes @@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Examples have been renamed. +*** Add --protect-ids to obscure information in objects, bug1521. [Todd Strader] + * Verilator 4.020 2019-10-06 diff --git a/bin/verilator b/bin/verilator index 29f375989..b08308446 100755 --- a/bin/verilator +++ b/bin/verilator @@ -352,6 +352,8 @@ detailed descriptions in L for more information. --prefix Name of top level class --prof-cfuncs Name functions for profiling --prof-threads Enable generating gantt chart data for threads + --protect-key Key for symbol protection + --protect-ids Hash identifier names for obscurity --private Debugging; see docs --public Debugging; see docs --public-flat-rw Mark all variables, etc as public_flat_rw @@ -1153,6 +1155,42 @@ When profiling is enabled, the runtime will emit a blurb of profiling data in non-human-friendly form. The C script will transform this into a nicer visual format and produce some related statistics. +=item --protect-key I + +Specifies the private key for --protect-ids. For best security this key +should be 16 or more random bytes, a reasonable medium-security choice is +the output of uuidgen. Typically, a key would be created by the user once +for a given protected design library, then every Verilator run for +subsequent versions of that library would be passed the same +--protect-key. Thus, if the input Verilog is similar between library +versions (Verilator runs), the Verilated code will likewise be mostly +similar. + +If --protect-key is not specified and a key is needed, Verilator will +generate a new key for every Verilator run. As the key is not saved, this +is best for security, but means every Verilator run will give vastly +different output even for identical input, perhaps harming compile times +(and certainly thrashing any I). + +=item --protect-ids + +Hash any private identifiers (variable, module, and assertion block names +that are not on the top level) into hashed random-looking identifiers, +resulting after compilation in protected library binaries that expose less +design information. This hashing uses the provided or default +--protect-key, see important details there. + +Verilator will also create a {prefix}__idmap.xml file which contains the +mapping from the hashed identifiers back to the original identifiers. This +idmap file is to be kept private, and is to assist mapping any runtime +design assertions, coverage, or trace information, which will report the +hashed identifiers, back to the original design's identifier names. + +Using DPI imports/exports is allowed and generally relatively safe in terms +of information disclosed, which is limited to the DPI function prototyptes. +Use of the VPI is not recommended as many design details may be exposed, +and an INSECURE warning will be issued. + =item --private Opposite of --public. Is the default; this option exists for backwards @@ -1910,6 +1948,7 @@ In certain debug and other modes, it also creates: {prefix}__Trace{__n}.cpp // Wave file generation code (--trace) {prefix}__cdc.txt // Clock Domain Crossing checks (--cdc) {prefix}__stats.txt // Statistics (--stats) + {prefix}__idmap.txt // Symbol demangling (--protect-ids) It also creates internal files that can be mostly ignored: @@ -3714,6 +3753,16 @@ non-delayed assignment. See also the COMBDLY warning. Ignoring this warning may make Verilator simulations differ from other simulators. +=item INSECURE + +Warns that the combination of options selected may be defeating the attempt +to protect/obscure identifiers or hide information in the model. Correct +the options provided, or inspect the output code to see if the information +exposed is acceptable. + +Ignoring this warning will only suppress the lint check, it will simulate +correctly. + =item LITENDIAN Warns that a packed vector is declared with little endian bit numbering diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 30e10b309..5b1ea5ddc 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -81,6 +81,7 @@ void AstNode::init() { // Attributes m_didWidth = false; m_doingWidth = false; + m_protect = true; m_user1u = VNUser(0); m_user1Cnt = 0; m_user2u = VNUser(0); @@ -133,6 +134,10 @@ string AstNode::encodeNumber(vlsint64_t num) { } } +string AstNode::nameProtect() const { + return VIdProtect::protectIf(name(), protect()); +} + string AstNode::shortName() const { string pretty = name(); string::size_type pos; diff --git a/src/V3Ast.h b/src/V3Ast.h index 94824d919..f318f9262 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1165,6 +1165,7 @@ class AstNode { // Attributes bool m_didWidth:1; // Did V3Width computation bool m_doingWidth:1; // Inside V3Width + bool m_protect:1; // Protect name if protection is on // // Space for more bools here // This member ordering both allows 64 bit alignment and puts associated data together @@ -1278,6 +1279,7 @@ public: virtual void tag(const string& text) {} virtual string tag() const { return ""; } virtual string verilogKwd() const { return ""; } + string nameProtect() const; // Name with --protect-id applied string shortName() const; // Name with __PVT__ removed for concatenating scopes static string dedotName(const string& namein); // Name with dots removed static string prettyName(const string& namein); // Name for printing out to the user @@ -1297,8 +1299,10 @@ public: void didWidth(bool flag) { m_didWidth = flag; } bool didWidth() const { return m_didWidth; } bool didWidthAndSet() { if (didWidth()) return true; didWidth(true); return false; } - void doingWidth(bool flag) { m_doingWidth = flag; } bool doingWidth() const { return m_doingWidth; } + void doingWidth(bool flag) { m_doingWidth = flag; } + bool protect() const { return m_protect; } + void protect(bool flag) { m_protect = flag; } //TODO stomp these width functions out, and call via dtypep() instead int width() const; @@ -1845,6 +1849,7 @@ public: AstVarScope* varScopep() const { return m_varScopep; } void varScopep(AstVarScope* varscp) { m_varScopep = varscp; } string hiername() const { return m_hiername; } + string hiernameProtect() const; void hiername(const string& hn) { m_hiername = hn; } bool hierThis() const { return m_hierThis; } void hierThis(bool flag) { m_hierThis = flag; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index b98f9331d..f15853914 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -56,6 +56,10 @@ void AstNodeVarRef::cloneRelink() { if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep(); } } +string AstNodeVarRef::hiernameProtect() const { + return VIdProtect::protectWordsIf(hiername(), protect()); +} + int AstNodeSel::bitConst() const { AstConst* constp = VN_CAST(bitp(), Const); return (constp ? constp->toSInt() : 0); @@ -269,7 +273,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const { oname += "&"; mayparen = true; } - if (named) oname += " "+name(); + if (named) oname += " "+VIdProtect::protectIf(name(), protect()); string oarray; if (isDpiOpenArray() || direction().isRefOrConstRef()) { @@ -594,6 +598,10 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variabl return nodep; } +string AstCCall::hiernameProtect() const { + return VIdProtect::protectWordsIf(hiername(), protect()); +} + const char* AstScope::broken() const { BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists()); BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists()); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 7be02cc65..516fc9033 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -6094,6 +6094,7 @@ public: AstCFunc* funcp() const { return m_funcp; } string hiername() const { return m_hiername; } void hiername(const string& hn) { m_hiername = hn; } + string hiernameProtect() const; void argTypes(const string& str) { m_argTypes = str; } string argTypes() const { return m_argTypes; } // diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index 17b4033ee..66594fbc3 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -226,6 +226,7 @@ private: funcp->slow(true); funcp->isStatic(false); funcp->entryPoint(true); + funcp->protect(false); funcp->addInitsp(new AstCStmt (nodep->fileline(), EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n")); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index a9d2d6beb..f90ba3c59 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -128,12 +128,12 @@ public: if (const AstEnumDType* adtypep = VN_CAST(nodep->dtypep()->skipRefToEnump(), EnumDType)) { if (adtypep->width()>64) { - putsDecoration("// enum "+nodep->name()+" // Ignored: Too wide for C++\n"); + putsDecoration("// enum "+nodep->nameProtect()+" // Ignored: Too wide for C++\n"); } else { puts("enum "+nodep->name()+" {\n"); for (AstEnumItem* itemp = adtypep->itemsp(); itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) { - puts(itemp->name()); + puts(itemp->nameProtect()); puts(" = "); iterateAndNextNull(itemp->valuep()); if (VN_IS(itemp->nextp(), EnumItem)) puts(","); @@ -214,8 +214,8 @@ public: virtual void visit(AstAlwaysPublic*) { } virtual void visit(AstCCall* nodep) { - puts(nodep->hiername()); - puts(nodep->funcp()->name()); + puts(nodep->hiernameProtect()); + puts(nodep->funcp()->nameProtect()); puts("("); puts(nodep->argTypes()); bool comma = (nodep->argTypes() != ""); @@ -237,8 +237,14 @@ public: } virtual void visit(AstComment* nodep) { string at; - if (nodep->showAt()) at = " at "+nodep->fileline()->ascii(); - putsDecoration(string("// ")+nodep->name()+at+"\n"); + if (nodep->showAt()) { + at = " at "+nodep->fileline()->ascii(); + // If protecting, passthru less information about the design + if (!v3Global.opt.protectIds()) return; + } + if (!(nodep->protect() && v3Global.opt.protectIds())) { + putsDecoration(string("// ")+nodep->name()+at+"\n"); + } iterateChildren(nodep); } virtual void visit(AstCoverDecl* nodep) { @@ -251,12 +257,13 @@ public: // hierarchies itself, and if verilator_cov also did it, you'd end up // with (number-of-instant) times too many counts in this bin. puts(", first"); // Enable, passed from __Vconfigure parameter - puts(", "); putsQuoted(nodep->fileline()->filename()); + puts(", "); putsQuoted(protect(nodep->fileline()->filename())); puts(", "); puts(cvtToStr(nodep->fileline()->lineno())); puts(", "); puts(cvtToStr(nodep->column())); - puts(", "); putsQuoted((nodep->hier()!=""?".":"")+nodep->hier()); - puts(", "); putsQuoted(nodep->page()); - puts(", "); putsQuoted(nodep->comment()); + puts(", "); putsQuoted((!nodep->hier().empty() ? "." : "") + +protectWordsIf(nodep->hier(), nodep->protect())); + puts(", "); putsQuoted(protectWordsIf(nodep->page(), nodep->protect())); + puts(", "); putsQuoted(protectWordsIf(nodep->comment(), nodep->protect())); puts(");\n"); } virtual void visit(AstCoverInc* nodep) { @@ -280,7 +287,7 @@ public: if (!nodep->dpiExport()) { // this is where the DPI import context scope is set string scope = nodep->scopeDpiName(); - putbs("(&(vlSymsp->__Vscope_"+scope+"))"); + putbs("(&(vlSymsp->"+protect("__Vscope_"+scope)+"))"); } } virtual void visit(AstSFormat* nodep) { @@ -520,14 +527,14 @@ public: } virtual void visit(AstStop* nodep) { puts("VL_STOP_MT("); - putsQuoted(nodep->fileline()->filename()); + putsQuoted(protect(nodep->fileline()->filename())); puts(","); puts(cvtToStr(nodep->fileline()->lineno())); puts(",\"\");\n"); } virtual void visit(AstFinish* nodep) { puts("VL_FINISH_MT("); - putsQuoted(nodep->fileline()->filename()); + putsQuoted(protect(nodep->fileline()->filename())); puts(","); puts(cvtToStr(nodep->fileline()->lineno())); puts(",\"\");\n"); @@ -555,13 +562,13 @@ public: iterateAndNextNull(nodep->bodysp()); } virtual void visit(AstUCStmt* nodep) { - putsDecoration("// $c statement at "+nodep->fileline()->ascii()+"\n"); + putsDecoration(ifNoProtect("// $c statement at "+nodep->fileline()->ascii()+"\n")); iterateAndNextNull(nodep->bodysp()); puts("\n"); } virtual void visit(AstUCFunc* nodep) { puts("\n"); - putsDecoration("// $c function at "+nodep->fileline()->ascii()+"\n"); + putsDecoration(ifNoProtect("// $c function at "+nodep->fileline()->ascii()+"\n")); iterateAndNextNull(nodep->bodysp()); puts("\n"); } @@ -701,8 +708,8 @@ public: } // Terminals virtual void visit(AstVarRef* nodep) { - puts(nodep->hiername()); - puts(nodep->varp()->name()); + puts(nodep->hiernameProtect()); + puts(nodep->varp()->nameProtect()); } void emitCvtPackStr(AstNode* nodep) { if (const AstConst* constp = VN_CAST(nodep, Const)) { @@ -756,8 +763,8 @@ public: if (!assigntop) { puts(assignString); } else if (VN_IS(assigntop, VarRef)) { - puts(assigntop->hiername()); - puts(assigntop->varp()->name()); + puts(assigntop->hiernameProtect()); + puts(assigntop->varp()->nameProtect()); } else { iterateAndNextNull(assigntop); } @@ -779,8 +786,8 @@ public: if (!assigntop) { puts(assignString); } else if (VN_IS(assigntop, VarRef)) { - puts(assigntop->hiername()); - puts(assigntop->varp()->name()); + puts(assigntop->hiernameProtect()); + puts(assigntop->varp()->nameProtect()); } else { iterateAndNextNull(assigntop); } @@ -1090,7 +1097,7 @@ class EmitCImp : EmitCStmts { ExecMTask* mtp = nodep->execMTaskp(); puts("\n"); puts("void "); - puts(modClassName(m_modp)+"::"+mtp->cFuncName()); + puts(modClassName(m_modp)+"::"+protect(mtp->cFuncName())); puts("(bool even_cycle, void* symtab) {\n"); // Declare and set vlSymsp @@ -1119,13 +1126,13 @@ class EmitCImp : EmitCStmts { if (nodep->ifdef()!="") puts("#ifdef "+nodep->ifdef()+"\n"); if (nodep->isInline()) puts("VL_INLINE_OPT "); puts(nodep->rtnTypeVoid()); puts(" "); - puts(modClassName(m_modp)+"::"+nodep->name() + puts(modClassName(m_modp)+"::"+nodep->nameProtect() +"("+cFuncArgs(nodep)+") {\n"); // "+" in the debug indicates a print from the model puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ "); for (int i=0; ilevel(); ++i) { puts(" "); } - puts(modClassName(m_modp)+"::"+nodep->name() + puts(modClassName(m_modp)+"::"+nodep->nameProtect() +"\\n\"); );\n"); // Declare and set vlTOPp @@ -1172,8 +1179,8 @@ class EmitCImp : EmitCStmts { doubleOrDetect(changep, gotOne); } } - if (gotOne) { - puts(");\n"); + if (gotOne) puts(");\n"); + if (gotOne && !v3Global.opt.protectIds()) { //puts("VL_DEBUG_IF( if (__req) cout<<\"- CLOCKREQ );"); for (std::vector::iterator it = m_blkChangeDetVec.begin(); it != m_blkChangeDetVec.end(); ++it) { @@ -1232,14 +1239,14 @@ class EmitCImp : EmitCStmts { if (runInline) { // The thread calling eval() will run this mtask inline, // along with its packed successors. - puts(execMTasks[i]->cFuncName() + puts(protect(execMTasks[i]->cFuncName()) + "(vlTOPp->__Vm_even_cycle, vlSymsp);\n"); puts("Verilated::mtaskId(0);\n"); } else { // The other N-1 go to the thread pool. puts("vlTOPp->__Vm_threadPoolp->workerp(" + cvtToStr(i)+")->addTask(" - + execMTasks[i]->cFuncName() + + protect(execMTasks[i]->cFuncName()) + ", vlTOPp->__Vm_even_cycle, vlSymsp);\n"); } } @@ -1307,7 +1314,7 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) { puts(nodep->scType()); puts("> "); } - puts(nodep->name()); + puts(nodep->nameProtect()); emitDeclArrayBrackets(nodep); puts(";\n"); } else if (basicp && basicp->isOpaque()) { @@ -1326,7 +1333,7 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) { else if (nodep->widthMin() <= 16) puts("16"); else if (nodep->isWide()) puts("W"); - puts("("+nodep->name()); + puts("("+nodep->nameProtect()); emitDeclArrayBrackets(nodep); // If it's a packed struct/array then nodep->width is the whole // thing, msb/lsb is just lowest dimension @@ -1357,7 +1364,7 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) { puts("SIGW("); } if (prefixIfImp!="") { puts(prefixIfImp); puts("::"); } - puts(nodep->name()); + puts(nodep->nameProtect()); emitDeclArrayBrackets(nodep); // If it's a packed struct/array then nodep->width is the whole // thing, msb/lsb is just lowest dimension @@ -1387,12 +1394,12 @@ void EmitCStmts::emitVarCtors(bool* firstp) { bool isArray = !VN_CAST(varp->dtypeSkipRefp(), BasicDType); if (isArray) { puts("// Skipping array: "); - puts(varp->name()); + puts(varp->nameProtect()); puts("\n"); } else { emitCtorSep(firstp); - puts(varp->name()); - puts("("); putsQuoted(varp->name()); puts(")"); + puts(varp->nameProtect()); + puts("("); putsQuoted(varp->nameProtect()); puts(")"); } } puts("\n#endif\n"); @@ -1456,8 +1463,8 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format, UASSERT_OBJ(m_wideTempRefp, nodep, "Wide Op w/ no temp, perhaps missing op in V3EmitC?"); COMMA; - puts(m_wideTempRefp->hiername()); - puts(m_wideTempRefp->varp()->name()); + puts(m_wideTempRefp->hiernameProtect()); + puts(m_wideTempRefp->varp()->nameProtect()); m_wideTempRefp = NULL; needComma = true; } @@ -1727,7 +1734,7 @@ void EmitCImp::emitVarReset(AstVar* varp) { UASSERT_OBJ(varp->valuep(), varp, "No init for a param?"); // If a simple CONST value we initialize it using an enum // If an ARRAYINIT we initialize it using an initial block similar to a signal - //puts("// parameter "+varp->name()+" = "+varp->valuep()->name()+"\n"); + //puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n"); } else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) { if (AstUnpackArrayDType* arrayp = VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType)) { @@ -1736,7 +1743,8 @@ void EmitCImp::emitVarReset(AstVar* varp) { puts("{ int __Vi=0;"); puts(" for (; __Vi<"+cvtToStr(arrayp->elementsConst())); puts("; ++__Vi) {\n"); - emitSetVarConstant(varp->name()+"[__Vi]", VN_CAST(initarp->defaultp(), Const)); + emitSetVarConstant(varp->nameProtect()+"[__Vi]", + VN_CAST(initarp->defaultp(), Const)); puts("}}\n"); } int pos = 0; @@ -1744,7 +1752,8 @@ void EmitCImp::emitVarReset(AstVar* varp) { int index = initarp->posIndex(pos); UASSERT_OBJ(initarp->defaultp() || index==pos, initarp, "Not enough values in array initialization"); - emitSetVarConstant(varp->name()+"["+cvtToStr(index)+"]", VN_CAST(itemp, Const)); + emitSetVarConstant(varp->nameProtect() + +"["+cvtToStr(index)+"]", VN_CAST(itemp, Const)); } } else { varp->v3fatalSrc("InitArray under non-arrayed var"); @@ -1780,11 +1789,11 @@ void EmitCImp::emitVarReset(AstVar* varp) { else puts("VL_RAND_RESET_W("); puts(cvtToStr(varp->widthMin())); puts(","); - puts(varp->name()); + puts(varp->nameProtect()); for (int v=0; vname()); + puts(varp->nameProtect()); for (int v=0; visTop() && v3Global.opt.mtasks()) { @@ -1907,11 +1916,12 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { } void EmitCImp::emitConfigureImp(AstNodeModule* modp) { - puts("\nvoid "+modClassName(modp)+"::__Vconfigure("+symClassName()+"* vlSymsp, bool first) {\n"); + puts("\nvoid "+modClassName(modp)+"::"+protect("__Vconfigure") + +"("+symClassName()+"* vlSymsp, bool first) {\n"); puts( "if (0 && first) {} // Prevent unused\n"); puts( "this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it. if (v3Global.opt.coverage() ) { - puts("this->_configure_coverage(vlSymsp, first);\n"); + puts(protect("_configure_coverage")+"(vlSymsp, first);\n"); } puts("}\n"); splitSizeInc(10); @@ -1962,7 +1972,7 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) { string funcname = de ? "__Vdeserialize" : "__Vserialize"; string op = de ? ">>" : "<<"; // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - puts("void "+modClassName(modp)+"::"+funcname+"("+classname+"& os) {\n"); + puts("void "+modClassName(modp)+"::"+protect(funcname)+"("+classname+"& os) {\n"); // Place a computed checksum to insure proper structure save/restore formatting // OK if this hash includes some things we won't dump, since // just looking for loading the wrong model @@ -2019,7 +2029,7 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) { puts(" for (; "+ivar+"<"+cvtToStr(elementp->widthWords())); puts("; ++"+ivar+") {\n"); } - puts("os"+op+varp->name()); + puts("os"+op+varp->nameProtect()); for (int v=0; visTop()) { // Save the children - puts( "__VlSymsp->"+funcname+"(os);\n"); + puts( "__VlSymsp->"+protect(funcname)+"(os);\n"); } puts("}\n"); } @@ -2051,10 +2061,8 @@ void EmitCImp::emitTextSection(AstType type) { if (last_line < 0) { puts("\n//*** Below code from `systemc in Verilog file\n"); } - ofp()->putsNoTracking("//#line "+cvtToStr(nodep->fileline()->lineno()) - +" "); - ofp()->putsQuoted(nodep->fileline()->filename()); - ofp()->putsNoTracking("\n"); + putsDecoration(ifNoProtect("// From `systemc at " + +nodep->fileline()->ascii()+"\n")); last_line = nodep->fileline()->lineno(); } ofp()->putsNoTracking(textp->text()); @@ -2075,7 +2083,7 @@ void EmitCImp::emitCellCtors(AstNodeModule* modp) { } for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (AstCell* cellp = VN_CAST(nodep, Cell)) { - puts("VL_CELL("+cellp->name()+", "+modClassName(cellp->modp())+");\n"); + puts("VL_CELL("+cellp->nameProtect()+", "+modClassName(cellp->modp())+");\n"); } } } @@ -2105,7 +2113,7 @@ void EmitCImp::emitSensitives() { puts(" for (; "+ivar+"<="+cvtToStr(arrayp->msb())); puts("; ++"+ivar+") {\n"); } - puts("sensitive << "+varp->name()); + puts("sensitive << "+varp->nameProtect()); for (int v=0; v__Vm_didInit)) _eval_initial_loop(vlSymsp);\n"); + puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) " + +protect("_eval_initial_loop")+"(vlSymsp);\n"); if (v3Global.opt.inhibitSim()) { puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n"); } @@ -2201,7 +2210,7 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { emitSettleLoop( (string("VL_DEBUG_IF(VL_DBG_MSGF(\"+ Clock loop\\n\"););\n") + (v3Global.opt.trace() ? "vlSymsp->__Vm_activity = true;\n" : "") - + "_eval(vlSymsp);"), false); + + protect("_eval")+"(vlSymsp);"), false); if (v3Global.opt.threads() == 1) { puts("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);\n"); } @@ -2212,14 +2221,15 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) { splitSizeInc(10); // - puts("\nvoid "+modClassName(modp)+"::_eval_initial_loop("+EmitCBaseVisitor::symClassVar()+") {\n"); + puts("\nvoid "+modClassName(modp)+"::"+protect("_eval_initial_loop") + +"("+EmitCBaseVisitor::symClassVar()+") {\n"); puts("vlSymsp->__Vm_didInit = true;\n"); - puts("_eval_initial(vlSymsp);\n"); + puts(protect("_eval_initial")+"(vlSymsp);\n"); if (v3Global.opt.trace()) { puts("vlSymsp->__Vm_activity = true;\n"); } - emitSettleLoop((string("_eval_settle(vlSymsp);\n") - +"_eval(vlSymsp);"), true); + emitSettleLoop((protect("_eval_settle")+"(vlSymsp);\n" + +protect("_eval")+"(vlSymsp);"), true); puts("}\n"); splitSizeInc(10); } @@ -2428,7 +2438,8 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) { if (funcp->ifdef()!="") puts("#ifdef "+funcp->ifdef()+"\n"); if (funcp->isStatic().trueU()) puts("static "); puts(funcp->rtnTypeVoid()); puts(" "); - puts(funcp->name()); puts("("+cFuncArgs(funcp)+")"); + puts(funcp->nameProtect()); + puts("("+cFuncArgs(funcp)+")"); if (funcp->slow()) puts(" VL_ATTR_COLD"); puts(";\n"); if (funcp->ifdef()!="") puts("#endif // "+funcp->ifdef()+"\n"); @@ -2446,7 +2457,7 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) { if (mtp->threadRoot()) { // Emit function declaration for this mtask ofp()->putsPrivate(true); - puts("static void "); puts(mtp->cFuncName()); + puts("static void "); puts(protect(mtp->cFuncName())); puts("(bool even_cycle, void* symtab);\n"); } } @@ -2558,7 +2569,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) { if (modp->isTop()) puts("// Public to allow access to /*verilator_public*/ items;\n"); if (modp->isTop()) puts("// otherwise the application code can consider these internals.\n"); } - puts(modClassName(cellp->modp())+"* "+cellp->name()+";\n"); + puts(modClassName(cellp->modp())+"* "+cellp->nameProtect()+";\n"); } } } @@ -2604,16 +2615,16 @@ void EmitCImp::emitInt(AstNodeModule* modp) { // These should be static const values, however microsloth VC++ doesn't // support them. They also cause problems with GDB under GCC2.95. if (varp->isWide()) { // Unsupported for output - putsDecoration("// enum WData "+varp->name()+" //wide"); + putsDecoration("// enum WData "+varp->nameProtect()+" //wide"); } else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output - //putsDecoration("// enum ..... "+varp->name() + //putsDecoration("// enum ..... "+varp->nameProtect() // +"not simple value, see variable above instead"); } else if (VN_IS(varp->dtypep(), BasicDType) && VN_CAST(varp->dtypep(), BasicDType)->isOpaque()) { // Can't put out e.g. doubles } else { puts("enum "); puts(varp->isQuad()?"_QData":"_IData"); - puts(""+varp->name()+" { "+varp->name()+" = "); + puts(""+varp->nameProtect()+" { "+varp->nameProtect()+" = "); iterateAndNextNull(varp->valuep()); puts("};"); } @@ -2672,27 +2683,28 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("\n// INTERNAL METHODS\n"); if (modp->isTop()) { ofp()->putsPrivate(true); // private: - puts("static void _eval_initial_loop("+EmitCBaseVisitor::symClassVar()+");\n"); + puts("static void "+protect("_eval_initial_loop") + +"("+EmitCBaseVisitor::symClassVar()+");\n"); } ofp()->putsPrivate(false); // public: - puts("void __Vconfigure("+symClassName()+"* symsp, bool first);\n"); + puts("void "+protect("__Vconfigure")+"("+symClassName()+"* symsp, bool first);\n"); emitIntFuncDecls(modp); if (v3Global.opt.trace()) { ofp()->putsPrivate(false); // public: - puts("static void traceInit("+v3Global.opt.traceClassBase() + puts("static void "+protect("traceInit")+"("+v3Global.opt.traceClassBase() +"* vcdp, void* userthis, uint32_t code);\n"); - puts("static void traceFull("+v3Global.opt.traceClassBase() + puts("static void "+protect("traceFull")+"("+v3Global.opt.traceClassBase() +"* vcdp, void* userthis, uint32_t code);\n"); - puts("static void traceChg("+v3Global.opt.traceClassBase() + puts("static void "+protect("traceChg")+"("+v3Global.opt.traceClassBase() +"* vcdp, void* userthis, uint32_t code);\n"); } if (v3Global.opt.savable()) { ofp()->putsPrivate(false); // public: - puts("void __Vserialize(VerilatedSerialize& os);\n"); - puts("void __Vdeserialize(VerilatedDeserialize& os);\n"); + puts("void "+protect("__Vserialize")+"(VerilatedSerialize& os);\n"); + puts("void "+protect("__Vdeserialize")+"(VerilatedDeserialize& os);\n"); puts("\n"); } @@ -2703,10 +2715,10 @@ void EmitCImp::emitInt(AstNodeModule* modp) { if (v3Global.opt.savable() && modp->isTop()) { puts("inline VerilatedSerialize& operator<<(VerilatedSerialize& os, " +modClassName(modp)+"& rhs) {\n" - "Verilated::quiesce(); rhs.__Vserialize(os); return os; }\n"); + "Verilated::quiesce(); rhs."+protect("__Vserialize")+"(os); return os; }\n"); puts("inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, " +modClassName(modp)+"& rhs) {\n" - "Verilated::quiesce(); rhs.__Vdeserialize(os); return os; }\n"); + "Verilated::quiesce(); rhs."+protect("__Vdeserialize")+"(os); return os; }\n"); puts("\n"); } @@ -2838,8 +2850,8 @@ class EmitCTrace : EmitCStmts { // METHODS void newOutCFile(int filenum) { - string filename = (v3Global.opt.makeDir()+"/"+ topClassName() - +"__Trace"); + string filename = (v3Global.opt.makeDir()+"/" + +topClassName()+"_"+protect("_Trace")); if (filenum) filename += "__"+cvtToStr(filenum); filename += (m_slow ? "__Slow":""); filename += ".cpp"; @@ -2868,13 +2880,13 @@ class EmitCTrace : EmitCStmts { puts("void "+topClassName()+"::trace("); puts(v3Global.opt.traceClassBase()+"C* tfp, int, int) {\n"); puts( "tfp->spTrace()->addCallback(" - "&"+topClassName()+"::traceInit" - +", &"+topClassName()+"::traceFull" - +", &"+topClassName()+"::traceChg, this);\n"); + "&"+topClassName()+"::"+protect("traceInit") + +", &"+topClassName()+"::"+protect("traceFull") + +", &"+topClassName()+"::"+protect("traceChg")+", this);\n"); puts("}\n"); splitSizeInc(10); - puts("void "+topClassName()+"::traceInit(" + puts("void "+topClassName()+"::"+protect("traceInit")+"(" +v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n"); putsDecoration("// Callback from vcd->open()\n"); puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n"); @@ -2883,17 +2895,17 @@ class EmitCTrace : EmitCStmts { puts( "VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n"); puts("}\n"); puts("vcdp->scopeEscape(' ');\n"); - puts("t->traceInitThis(vlSymsp, vcdp, code);\n"); + puts("t->"+protect("traceInitThis")+"(vlSymsp, vcdp, code);\n"); puts("vcdp->scopeEscape('.');\n"); // Restore so later traced files won't break puts("}\n"); splitSizeInc(10); - puts("void "+topClassName()+"::traceFull(" + puts("void "+topClassName()+"::"+protect("traceFull")+"(" +v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n"); putsDecoration("// Callback from vcd->dump()\n"); puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n"); puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); - puts("t->traceFullThis(vlSymsp, vcdp, code);\n"); + puts("t->"+protect("traceFullThis")+"(vlSymsp, vcdp, code);\n"); puts("}\n"); splitSizeInc(10); @@ -2903,13 +2915,13 @@ class EmitCTrace : EmitCStmts { void emitTraceFast() { puts("\n//======================\n\n"); - puts("void "+topClassName()+"::traceChg(" + puts("void "+topClassName()+"::"+protect("traceChg")+"(" +v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n"); putsDecoration("// Callback from vcd->dump()\n"); puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n"); puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); puts("if (vlSymsp->getClearActivity()) {\n"); - puts("t->traceChgThis(vlSymsp, vcdp, code);\n"); + puts("t->"+protect("traceChgThis")+"(vlSymsp, vcdp, code);\n"); puts("}\n"); puts("}\n"); splitSizeInc(10); @@ -2954,7 +2966,7 @@ class EmitCTrace : EmitCStmts { puts("(c+"+cvtToStr(nodep->code())); if (nodep->arrayRange().ranged()) puts("+i*"+cvtToStr(nodep->widthWords())); puts(","); - putsQuoted(nodep->showname()); + putsQuoted(VIdProtect::protectWordsIf(nodep->showname(), nodep->protect())); // Direction if (v3Global.opt.traceFormat().fstFlavor()) { puts(","+cvtToStr(enumNum)); @@ -3033,7 +3045,7 @@ class EmitCTrace : EmitCStmts { enump->user1(enumNum); int nvals = 0; puts("{\n"); - puts("const char* __VenumItemNames[]\n"); + puts("const char* "+protect("__VenumItemNames")+"[]\n"); puts("= {"); for (AstEnumItem* itemp = enump->itemsp(); itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) { @@ -3042,7 +3054,7 @@ class EmitCTrace : EmitCStmts { } puts("};\n"); nvals = 0; - puts("const char* __VenumItemValues[]\n"); + puts("const char* "+protect("__VenumItemValues")+"[]\n"); puts("= {"); for (AstEnumItem* itemp = enump->itemsp(); itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) { @@ -3055,7 +3067,9 @@ class EmitCTrace : EmitCStmts { +", \""+enump->prettyName()+"\", " +cvtToStr(nvals) +", "+cvtToStr(enump->widthMin()) - +", __VenumItemNames, __VenumItemValues);\n"); + +", "+protect("__VenumItemNames") + +", "+protect("__VenumItemValues") + +");\n"); puts("}\n"); } return enumNum; @@ -3146,7 +3160,7 @@ class EmitCTrace : EmitCStmts { puts("\n"); puts(nodep->rtnTypeVoid()); puts(" "); - puts(topClassName()+"::"+nodep->name() + puts(topClassName()+"::"+nodep->nameProtect() +"("+cFuncArgs(nodep)+") {\n"); if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n"); diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 731232d06..9e09f81c5 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -46,7 +46,13 @@ public: void putsDecoration(const string& str) { if (v3Global.opt.decoration()) puts(str); } void putsQuoted(const string& str) { ofp()->putsQuoted(str); } bool optSystemC() { return v3Global.opt.systemC(); } - static string symClassName() { return v3Global.opt.prefix()+"__Syms"; } + static string protect(const string& name) { return VIdProtect::protectIf(name, true); } + static string protectIf(const string& name, bool doIt) { + return VIdProtect::protectIf(name, doIt); } + static string protectWordsIf(const string& name, bool doIt) { + return VIdProtect::protectWordsIf(name, doIt); } + static string ifNoProtect(const string& in) { return v3Global.opt.protectIds() ? "" : in; } + static string symClassName() { return v3Global.opt.prefix()+"_"+protect("_Syms"); } static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; } static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; } @@ -54,7 +60,7 @@ public: if (modp->isTop()) { return v3Global.opt.prefix(); } else { - return v3Global.opt.modPrefix() + "_" + modp->name(); + return v3Global.opt.modPrefix()+"_"+protect(modp->name()); } } static string topClassName() { // Return name of top wrapper module diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 468afb936..6d8525680 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -405,7 +405,7 @@ void EmitCSyms::emitSymHdr() { for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) { AstCFunc* funcp = it->second.m_funcp; if (funcp->dpiExport()) { - string cbtype = v3Global.opt.prefix()+"__Vcb_"+funcp->cname()+"_t"; + string cbtype = protect(v3Global.opt.prefix()+"__Vcb_"+funcp->cname()+"_t"); types["typedef void (*"+cbtype+") ("+cFuncArgs(funcp)+");\n"] = 1; } } @@ -430,11 +430,11 @@ void EmitCSyms::emitSymHdr() { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (modp->isTop()) { ofp()->printf("%-30s ", (modClassName(modp)+"*").c_str()); - puts(scopep->nameDotless()+"p;\n"); + puts(protectIf(scopep->nameDotless()+"p", scopep->protect())+";\n"); } else { ofp()->printf("%-30s ", (modClassName(modp)+"").c_str()); - puts(scopep->nameDotless()+";\n"); + puts(protectIf(scopep->nameDotless(), scopep->protect())+";\n"); } } @@ -446,7 +446,7 @@ void EmitCSyms::emitSymHdr() { if (!m_scopeNames.empty()) { // Scope names puts("\n// SCOPE NAMES\n"); for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) { - puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n"); + puts("VerilatedScope "+protect("__Vscope_"+it->second.m_symName)+";\n"); } } @@ -476,8 +476,8 @@ void EmitCSyms::emitSymHdr() { puts("inline bool getClearActivity() { bool r=__Vm_activity; __Vm_activity=false; return r; }\n"); } if (v3Global.opt.savable() ) { - puts("void __Vserialize(VerilatedSerialize& os);\n"); - puts("void __Vdeserialize(VerilatedDeserialize& os);\n"); + puts("void "+protect("__Vserialize")+"(VerilatedSerialize& os);\n"); + puts("void "+protect("__Vdeserialize")+"(VerilatedDeserialize& os);\n"); } puts("\n"); puts("} VL_ATTR_ALIGNED(64);\n"); @@ -558,7 +558,7 @@ void EmitCSyms::emitSymImp() { string funcname = de ? "__Vdeserialize" : "__Vserialize"; string op = de ? ">>" : "<<"; // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n"); + puts("void "+symClassName()+"::"+protect(funcname)+"("+classname+"& os) {\n"); puts( "// LOCAL STATE\n"); // __Vm_namep presumably already correct if (v3Global.opt.trace()) { @@ -570,7 +570,8 @@ void EmitCSyms::emitSymImp() { it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (!modp->isTop()) { - puts( scopep->nameDotless()+"."+funcname+"(os);\n"); + puts(protectIf(scopep->nameDotless(), scopep->protect()) + +"."+protect(funcname)+"(os);\n"); } } puts("}\n"); @@ -593,10 +594,10 @@ void EmitCSyms::emitSymImp() { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (modp->isTop()) { } else { - puts(string(" ")+comma+" "+scopep->nameDotless()); + puts(string(" ")+comma+" "+protect(scopep->nameDotless())); puts("(Verilated::catName(topp->name(),"); // The "." is added by catName - putsQuoted(scopep->prettyName()); + putsQuoted(protectWordsIf(scopep->prettyName(), scopep->protect())); puts("))\n"); comma = ','; ++m_numStmts; @@ -617,15 +618,16 @@ void EmitCSyms::emitSymImp() { arrow.replace(pos, 1, "->"); } if (arrow.substr(0, 5) == "TOP->") arrow.replace(0, 5, "TOPp->"); - ofp()->printf("%-30s ", arrow.c_str()); + string arrowProt = protectWordsIf(arrow, scopep->protect()); + ofp()->printf("%-30s ", arrowProt.c_str()); puts(" = &"); - puts(scopep->nameDotless()+";\n"); + puts(protectIf(scopep->nameDotless(), scopep->protect())+";\n"); ++m_numStmts; } } puts("// Setup each module's pointer back to symbol table (for public functions)\n"); - puts("TOPp->__Vconfigure(this, true);\n"); + puts("TOPp->"+protect("__Vconfigure")+"(this, true);\n"); for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (!modp->isTop()) { @@ -633,7 +635,8 @@ void EmitCSyms::emitSymImp() { // first is used by AstCoverDecl's call to __vlCoverInsert bool first = !modp->user1(); modp->user1(true); - puts(scopep->nameDotless()+".__Vconfigure(this, " + puts(protectIf(scopep->nameDotless(), scopep->protect()) + +"."+protect("__Vconfigure")+"(this, " +(first?"true":"false") +");\n"); ++m_numStmts; @@ -644,10 +647,11 @@ void EmitCSyms::emitSymImp() { puts("// Setup scopes\n"); for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) { checkSplit(false); - puts("__Vscope_"+it->second.m_symName+".configure(this,name(),"); - putsQuoted(it->second.m_prettyName); + puts(protect("__Vscope_"+it->second.m_symName) + +".configure(this, name(), "); + putsQuoted(protectWordsIf(it->second.m_prettyName, true)); puts(", "); - putsQuoted(scopeDecodeIdentifier(it->second.m_prettyName)); + putsQuoted(protect(scopeDecodeIdentifier(it->second.m_prettyName))); puts(", VerilatedScope::"+it->second.m_type+");\n"); ++m_numStmts; } @@ -661,7 +665,7 @@ void EmitCSyms::emitSymImp() { if (it->first == "TOP") continue; name = name.replace(0, 4, ""); // Remove the "TOP." if ((name.find(".") == string::npos) && (it->second.m_type == "SCOPE_MODULE")) { - puts("__Vhier.add(0, &__Vscope_" + it->second.m_symName + ");\n"); + puts("__Vhier.add(0, &"+protect("__Vscope_"+it->second.m_symName)+");\n"); } } @@ -676,8 +680,8 @@ void EmitCSyms::emitSymImp() { UASSERT(from != m_scopeNames.end(), fromname+" not in m_scopeNames"); UASSERT(to != m_scopeNames.end(), toname+" not in m_scopeNames"); puts("__Vhier.add("); - puts("&__Vscope_"+from->second.m_symName+", "); - puts("&__Vscope_"+to->second.m_symName+");\n"); + puts("&"+protect("__Vscope_"+from->second.m_symName)+", "); + puts("&"+protect("__Vscope_"+to->second.m_symName)+");\n"); } } puts("\n"); @@ -695,12 +699,12 @@ void EmitCSyms::emitSymImp() { AstNodeModule* modp = it->second.m_modp; if (funcp->dpiExport()) { checkSplit(true); - puts("__Vscope_"+scopep->scopeSymName()+".exportInsert(__Vfinal,"); - putsQuoted(funcp->cname()); + puts(protect("__Vscope_"+scopep->scopeSymName())+".exportInsert(__Vfinal, "); + putsQuoted(funcp->cname()); // Not protected - user asked for import/export puts(", (void*)(&"); puts(modClassName(modp)); puts("::"); - puts(funcp->name()); + puts(funcp->nameProtect()); puts("));\n"); ++m_numStmts; } @@ -738,17 +742,17 @@ void EmitCSyms::emitSymImp() { if (pdim>1 || udim>1) { puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays } - puts("__Vscope_"+it->second.m_scopeName+".varInsert(__Vfinal,"); - putsQuoted(it->second.m_varBasePretty); + puts(protect("__Vscope_"+it->second.m_scopeName)+".varInsert(__Vfinal,"); + putsQuoted(protect(it->second.m_varBasePretty)); puts(", &("); if (modp->isTop()) { - puts(scopep->nameDotless()); - puts("p->"); + puts(protectIf(scopep->nameDotless()+"p", scopep->protect())); + puts("->"); } else { - puts(scopep->nameDotless()); + puts(protectIf(scopep->nameDotless(), scopep->protect())); puts("."); } - puts(varp->name()); + puts(varp->nameProtect()); puts("), "); puts(varp->vlEnumType()); // VLVT_UINT32 etc puts(","); @@ -796,13 +800,15 @@ void EmitCSyms::emitDpiHdr() { AstCFunc* nodep = *it; if (nodep->dpiExportWrapper()) { if (!firstExp++) puts("\n// DPI EXPORTS\n"); - puts("// DPI export at "+nodep->fileline()->ascii()+"\n"); - puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+");\n"); + puts("// DPI export"+ifNoProtect(" at "+nodep->fileline()->ascii())+"\n"); + puts("extern "+nodep->rtnTypeVoid()+" "+nodep->nameProtect() + +"("+cFuncArgs(nodep)+");\n"); } else if (nodep->dpiImport()) { if (!firstImp++) puts("\n// DPI IMPORTS\n"); - puts("// DPI import at "+nodep->fileline()->ascii()+"\n"); - puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+");\n"); + puts("// DPI import"+ifNoProtect(" at "+nodep->fileline()->ascii())+"\n"); + puts("extern "+nodep->rtnTypeVoid()+" "+nodep->nameProtect() + +"("+cFuncArgs(nodep)+");\n"); } } @@ -846,7 +852,7 @@ void EmitCSyms::emitDpiImp() { puts("#ifndef _VL_DPIDECL_"+nodep->name()+"\n"); puts("#define _VL_DPIDECL_"+nodep->name()+"\n"); puts(nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+") {\n"); - puts("// DPI Export at "+nodep->fileline()->ascii()+"\n"); + puts("// DPI export"+ifNoProtect(" at "+nodep->fileline()->ascii())+"\n"); puts("return "+topClassName()+"::"+nodep->name()+"("); string args; for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) { diff --git a/src/V3Error.h b/src/V3Error.h index 73a9518a9..70f6903df 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -88,6 +88,7 @@ public: INCABSPATH, // Include has absolute path INFINITELOOP, // Infinite loop INITIALDLY, // Initial delayed statement + INSECURE, // Insecure options LITENDIAN, // Little bit endian vector MODDUP, // Duplicate module MULTIDRIVEN, // Driven from multiple blocks @@ -145,7 +146,7 @@ public: "ENDLABEL", "GENCLK", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE", - "INCABSPATH", "INFINITELOOP", "INITIALDLY", + "INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE", "LITENDIAN", "MODDUP", "MULTIDRIVEN", "MULTITOP", "PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE", diff --git a/src/V3File.cpp b/src/V3File.cpp index b348750f4..3c4f1da9f 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -917,3 +917,124 @@ void V3OutFile::putsForceIncs() { puts("#include \""+*it+"\"\n"); } } + +//###################################################################### +// VIdProtect + +class VIdProtectImp { + // MEMBERS + typedef std::map IdMap; + IdMap m_nameMap; // Map of old name into new name + typedef vl_unordered_set IdSet; + IdSet m_newIdSet; // Which new names exist +protected: + // CONSTRUCTORS + friend class VIdProtect; + static VIdProtectImp& singleton() { static VIdProtectImp s; return s; } +public: + VIdProtectImp() { + passthru("this"); + passthru("TOPp"); + passthru("vlTOPp"); + passthru("vlSymsp"); + } + ~VIdProtectImp() {} + // METHODS + string passthru(const string& old) { + if (!v3Global.opt.protectIds()) return old; + IdMap::iterator it = m_nameMap.find(old); + if (it != m_nameMap.end()) { + // No way to go back and correct the older crypt name + UASSERT(old == it->second, "Passthru request for '" + +old+"' after already --protect-ids of it."); + } + else { + m_nameMap.insert(make_pair(old, old)); + m_newIdSet.insert(old); + } + return old; + } + string protectIf(const string& old, bool doIt) { + if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old; + IdMap::iterator it = m_nameMap.find(old); + if (it != m_nameMap.end()) return it->second; + else { + string out; + if (v3Global.opt.debugProtect()) { + // This lets us see the symbol being protected to debug cases + // where e.g. the definition is protect() but reference is + // missing a protect() + out = "PS"+old; + } else { + VHashSha256 digest (v3Global.opt.protectKeyDefaulted()); + digest.insert(old); + // Add "PS" prefix (Protect Symbols) as cannot start symbol with number + out = "PS"+digest.digestSymbol(); + // See if we can shrink the digest symbol to something smaller + for (size_t len = 6; len < out.size() - 3; len += 3) { + string tryout = out.substr(0, len); + if (m_newIdSet.find(tryout) == m_newIdSet.end()) { + out = tryout; + break; + } + } + } + m_nameMap.insert(make_pair(old, out)); + m_newIdSet.insert(out); + return out; + } + } + string protectWordsIf(const string& old, bool doIt) { + // Split at " " (for traces), "." (for scopes), or "->" (for scopes) + if (!(doIt && v3Global.opt.protectIds())) return old; + string out; + string::size_type start = 0; + // space, ., -> + while (1) { + // When C++11, use find_if and lambda + string::size_type pos = string::npos; + string separator = ""; + trySep(old, start, " ", pos/*ref*/, separator/*ref*/); + trySep(old, start, ".", pos/*ref*/, separator/*ref*/); + trySep(old, start, "->", pos/*ref*/, separator/*ref*/); + if (pos == string::npos) break; + out += protectIf(old.substr(start, pos-start), true) + separator; + start = pos + separator.length(); + } + out += protectIf(old.substr(start), true); + return out; + } + void writeMapFile(const string& filename) const { + V3OutXmlFile of (filename); + of.putsHeader(); + of.puts("\n"); + of.puts("\n"); + { + for (IdMap::const_iterator it = m_nameMap.begin(); it != m_nameMap.end(); ++it) { + of.puts("second+"\" to=\""+it->first+"\"/>\n"); + } + } + of.puts("\n"); + } +private: + void trySep(const string& old, string::size_type start, const string& trySep, + string::size_type& posr, string& separatorr) { + string::size_type trypos = old.find(trySep, start); + if (trypos != string::npos) { + if (posr == string::npos || (posr > trypos)) { + posr = trypos; + separatorr = trySep; + } + } + } +}; + +string VIdProtect::protectIf(const string& old, bool doIt) { + return VIdProtectImp::singleton().protectIf(old, doIt); +} +string VIdProtect::protectWordsIf(const string& old, bool doIt) { + return VIdProtectImp::singleton().protectWordsIf(old, doIt); +} +void VIdProtect::writeMapFile(const string& filename) { + VIdProtectImp::singleton().writeMapFile(filename); +} diff --git a/src/V3File.h b/src/V3File.h index 774c7d84e..3659ad0a0 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -182,9 +182,6 @@ private: virtual void putcOutput(char chr) { fputc(chr, m_fp); } }; -//###################################################################### -// V3OutCFile: A class for abstracting out SystemC/C++ details - class V3OutCFile : public V3OutFile { int m_private; public: @@ -250,4 +247,21 @@ public: void puts(const string& strg) { putsNoTracking(strg); } }; +//============================================================================ +// VIdProtect: Hash identifier names in output files to protect them + +class VIdProtectImp; + +class VIdProtect { +public: + // METHODS + // Rename to a new encoded string (unless earlier passthru'ed) + static string protect(const string& old) { return protectIf(old, true); } + static string protectIf(const string& old, bool doIt=true); + // Rename words to a new encoded string + static string protectWordsIf(const string& old, bool doIt=true); + // Write map of renames to output file + static void writeMapFile(const string& filename); +}; + #endif // Guard diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 96fbf01a2..8c453ab2a 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -112,6 +112,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) { newmodp->addNext(oldmodp); newmodp->level(1); newmodp->modPublic(true); + newmodp->protect(false); rootp->addModulep(newmodp); // TODO the module creation above could be done after linkcells, but @@ -192,6 +193,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { AstVar* varp = oldvarp->cloneTree(false); varp->name(name); + varp->protect(false); newmodp->addStmtp(varp); varp->sigPublic(true); // User needs to be able to get to it... if (oldvarp->isIO()) { diff --git a/src/V3Name.cpp b/src/V3Name.cpp index d5f4df898..a8ef0eef2 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -29,6 +29,7 @@ #include "V3Global.h" #include "V3Name.h" #include "V3Ast.h" +#include "V3File.h" #include "V3LanguageWords.h" #include diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 7ae630d27..d1044a926 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -534,6 +534,25 @@ void V3Options::notify() { && !cdc()) { v3fatal("verilator: Need --cc, --sc, --cdc, --lint-only, --xml_only or --E option"); } + if (protectIds()) { + FileLine* cmdfl = new FileLine(FileLine::commandLineFilename()); + if (allPublic()) { + // We always call protect() on names, we don't check if public or not + // Hence any external references wouldn't be able to find the refed public object. + cmdfl->v3error("Unsupported: Using --protect-ids with --public\n" + +V3Error::warnMore()+"... Suggest remove --public."); + } + if (trace()) { + cmdfl->v3warn(INSECURE, + "Using --protect-ids with --trace may expose private design details\n" + +V3Error::warnMore()+"... Suggest remove --trace."); + } + if (vpi()) { + cmdfl->v3warn(INSECURE, + "Using --protect-ids with --vpi may expose private design details\n" + +V3Error::warnMore()+"... Suggest remove --vpi."); + } + } } //###################################################################### @@ -545,6 +564,16 @@ string V3Options::version() { return ver; } +string V3Options::protectKeyDefaulted() { + if (m_protectKey.empty()) { + // Create a key with a human-readable symbol-like name. + // This conversion drops ~2 bits of entropy out of 256, shouldn't matter. + VHashSha256 digest (V3Os::trueRandom(32)); + m_protectKey = digest.digestSymbol(); + } + return m_protectKey; +} + void V3Options::throwSigsegv() { #if !(defined(VL_CPPCHECK) || defined(__clang_analyzer__)) char* zp=NULL; *zp=0; // Intentional core dump, ignore warnings here @@ -687,6 +716,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( onoff (sw, "-debug-leak", flag/*ref*/)) { m_debugLeak = flag; } else if ( onoff (sw, "-debug-nondeterminism", flag/*ref*/)){ m_debugNondeterminism = flag; } else if ( onoff (sw, "-debug-partition", flag/*ref*/)){ m_debugPartition = flag; } // Undocumented + else if ( onoff (sw, "-debug-protect", flag/*ref*/)){ m_debugProtect = flag; } // Undocumented else if ( onoff (sw, "-debug-self-test", flag/*ref*/)){ m_debugSelfTest = flag; } // Undocumented else if (!strcmp(sw, "-debug-sigsegv")) { throwSigsegv(); } // Undocumented, see also --debug-abort else if (!strcmp(sw, "-debug-fatalsrc")) { v3fatalSrc("--debug-fatal-src"); } // Undocumented, see also --debug-abort @@ -709,6 +739,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char else if ( onoff (sw, "-prof-cfuncs", flag/*ref*/)) { m_profCFuncs = flag; } else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/)) { m_profCFuncs = flag; } // Undocumented, for backward compat else if ( onoff (sw, "-prof-threads", flag/*ref*/)) { m_profThreads = flag; } + else if ( onoff (sw, "-protect-ids", flag/*ref*/)) { m_protectIds = flag; } else if ( onoff (sw, "-public", flag/*ref*/)) { m_public = flag; } else if ( onoff (sw, "-public-flat-rw", flag/*ref*/) ) { m_publicFlatRW = flag; v3Global.dpi(true); } else if (!strncmp(sw, "-pvalue+", strlen("-pvalue+"))) { addParameter(string(sw+strlen("-pvalue+")), false); } @@ -1056,6 +1087,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char shift; m_prefix = argv[i]; if (m_modPrefix=="") m_modPrefix = m_prefix; } + else if (!strcmp(sw, "-protect-key") && (i+1) #include #include +#include #include #include #include @@ -218,6 +219,18 @@ vluint64_t V3Os::rand64(vluint64_t* statep) { return result; } +string V3Os::trueRandom(size_t size) { + string data; data.reserve(size); + std::ifstream is ("/dev/urandom", std::ios::in | std::ios::binary); + char bytes[size]; + if (!is.read(bytes, size)) { + v3fatal("Could not open /dev/urandom, no source of randomness. Try specifing a key instead."); + return ""; + } + data.append(bytes, size); + return data; +} + //###################################################################### // METHODS (performance) diff --git a/src/V3Os.h b/src/V3Os.h index 3baeccbb1..731fda83c 100644 --- a/src/V3Os.h +++ b/src/V3Os.h @@ -56,6 +56,7 @@ public: // METHODS (random) static vluint64_t rand64(vluint64_t* statep); + static string trueRandom(size_t size); // METHODS (performance) static uint64_t timeUsecs(); ///< Return wall time since epoch in microseconds, or 0 if not implemented diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 762046113..c72391dae 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -711,6 +711,7 @@ private: dpip->entryPoint(true); dpip->isStatic(true); dpip->dpiExportWrapper(true); + dpip->protect(false); dpip->cname(nodep->cname()); // Add DPI reference to top, since it's a global function m_topScopep->scopep()->addActivep(dpip); @@ -733,7 +734,8 @@ private: // If the find fails, it will throw an error stmt += "const VerilatedScope* __Vscopep = Verilated::dpiScope();\n"; // If dpiScope is fails and is null; the exportFind function throws and error - string cbtype = v3Global.opt.prefix()+"__Vcb_"+nodep->cname()+"_t"; + string cbtype = VIdProtect::protect(v3Global.opt.prefix() + +"__Vcb_"+nodep->cname()+"_t"); stmt += cbtype+" __Vcb = ("+cbtype+")(VerilatedScope::exportFind(__Vscopep, __Vfuncnum));\n"; // Can't use static_cast // If __Vcb is null the exportFind function throws and error dpip->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); @@ -741,7 +743,8 @@ private: // Convert input/inout DPI arguments to Internal types string args; - args += "("+v3Global.opt.prefix()+"__Syms*)(__Vscopep->symsp())"; // Upcast w/o overhead + args += ("("+EmitCBaseVisitor::symClassName() + +"*)(__Vscopep->symsp())"); // Upcast w/o overhead AstNode* argnodesp = NULL; for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { @@ -755,6 +758,9 @@ private: args = ""; } AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp); + // No information exposure; is already visible in import/export func template + outvscp->varp()->protect(false); + portp->protect(false); AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isWritable()); argnodesp = argnodesp->addNextNull(refp); @@ -775,6 +781,8 @@ private: args=""; } AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp); + // No information exposure; is already visible in import/export func template + outvscp->varp()->protect(false); AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isWritable()); argnodesp = argnodesp->addNextNull(refp); } @@ -826,6 +834,7 @@ private: dpip->entryPoint(false); dpip->funcPublic(true); dpip->isStatic(false); + dpip->protect(false); dpip->pure(nodep->pure()); dpip->dpiImport(true); // Add DPI reference to top, since it's a global function @@ -952,6 +961,7 @@ private: // Convert output/inout arguments back to internal type for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { + portp->protect(false); // No additional exposure - already part of shown proto if (portp->isIO() && (portp->isWritable() || portp->isFuncReturn()) && !portp->isDpiOpenArray()) { AstVarScope* portvscp = VN_CAST(portp->user2p(), VarScope); // Remembered when we created it earlier @@ -984,6 +994,7 @@ private: rtnvarp = portp; rtnvarp->funcLocal(true); rtnvarp->name(rtnvarp->name()+"__Vfuncrtn"); // Avoid conflict with DPI function name + if (nodep->dpiImport() || nodep->dpiExport()) rtnvarp->protect(false); } if (nodep->dpiImport()) { @@ -1245,6 +1256,11 @@ private: if (nodep->dpiImport()) modes++; if (nodep->dpiExport()) modes++; if (nodep->taskPublic()) modes++; + if (v3Global.opt.protectIds() && nodep->taskPublic()) { + // We always call protect() on names, we don't check if public or not + // Hence any external references wouldn't be able to find the refed public object. + nodep->v3error("Unsupported: Using --protect-ids with public function"); + } if (modes > 1) nodep->v3error("Cannot mix DPI import, DPI export and/or public on same function: " <prettyNameQ()); diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 95c5dc2f4..5b25a2b0b 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -643,6 +643,9 @@ int main(int argc, char** argv, char** env) { V3File::writeTimes(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix() +"__verFiles.dat", argString); } + if (v3Global.opt.protectIds()) { + VIdProtect::writeMapFile(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__idmap.xml"); + } // Final writing shouldn't throw warnings, but... V3Error::abortIfWarnings(); diff --git a/test_regress/t/t_dpi_accessors.cpp b/test_regress/t/t_dpi_accessors.cpp index 8ba834543..f62d8f11e 100644 --- a/test_regress/t/t_dpi_accessors.cpp +++ b/test_regress/t/t_dpi_accessors.cpp @@ -81,7 +81,9 @@ static void checkResult(bool p, const char *msg_fail) { // Main function instantiates the model and steps through the test. int main() { Vt_dpi_accessors *dut = new Vt_dpi_accessors ("dut"); - svSetScope(svGetScopeFromName("dut.t")); + svScope scope = svGetScopeFromName("dut.t"); + if (!scope) vl_fatal(__FILE__, __LINE__, "dut", "No svGetScopeFromName result"); + svSetScope(scope); // evaluate the model with no signal changes to get the initial blocks // executed. diff --git a/test_regress/t/t_protect_ids.pl b/test_regress/t/t_protect_ids.pl new file mode 100755 index 000000000..cff3e8341 --- /dev/null +++ b/test_regress/t/t_protect_ids.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(vlt_all => 1); + +# Use --debug-protect to assist debug + +# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first +foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp" + ." $Self->{obj_dir}/*_PS*.h" + ." $Self->{obj_dir}/*.d" )) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +compile( + verilator_flags2 => ["--protect-ids", + "--trace", + "--coverage", + "-Wno-INSECURE", + "t/t_protect_ids_c.cpp"], + ); + +execute( + check_finished => 1, + ); + +# 'to="PS"' indicates means we probably mis-protected something already protected +# Use --debug-protect to assist debugging these +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}__idmap.xml", qr/to="PS/); + +if ($Self->{vlt_all}) { + # Check for secret in any outputs + my $any; + foreach my $filename (glob $Self->{obj_dir}."/*.[ch]*") { + if ($filename =~ /secret/) { + $Self->error("Secret found in a filename: ".$filename); + } + file_grep_not($filename, qr/secret/); + $any = 1; + } + $any or $Self->error("No outputs found"); +} + +ok(1); +1; diff --git a/test_regress/t/t_protect_ids.v b/test_regress/t/t_protect_ids.v new file mode 100644 index 000000000..d6a5c50f0 --- /dev/null +++ b/test_regress/t/t_protect_ids.v @@ -0,0 +1,61 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2019 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + secret_sub secret_inst (.*); + secret_other secret_inst2 (.*); +endmodule + +module secret_sub + ( + input clk); + + // verilator no_inline_module + + integer secret_cyc; + real secret_cyc_r; + integer secret_o; + real secret_r; + + export "DPI-C" task dpix_a_task; + task dpix_a_task(input int i, output int o); o = i + 1; endtask + import "DPI-C" context task dpii_a_task(input int i, output int o); + + export "DPI-C" function dpix_a_func; + function int dpix_a_func(input int i); return i + 2; endfunction + import "DPI-C" context function int dpii_a_func(input int i); + + // Test loop + always @ (posedge clk) begin + secret_cyc_r = $itor(secret_cyc)/10.0 - 5.0; + secret_cyc <= dpii_a_func(secret_cyc); + secret_r += 1.0 + $cos(secret_cyc_r); + dpix_a_task(secret_cyc, secret_o); + if (secret_cyc==90) begin + $write("*-* All Finished *-*\n"); + end + end + +endmodule + +module secret_other + ( + input clk); + + integer secret_cyc; + + always @ (posedge clk) begin + secret_cyc <= secret_cyc + 1; + if (secret_cyc==99) begin + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_protect_ids_bad.out b/test_regress/t/t_protect_ids_bad.out new file mode 100644 index 000000000..ae7d64f3b --- /dev/null +++ b/test_regress/t/t_protect_ids_bad.out @@ -0,0 +1,8 @@ +%Error: Unsupported: Using --protect-ids with --public + ... Suggest remove --public. +%Warning-INSECURE: Using --protect-ids with --trace may expose private design details + ... Suggest remove --trace. + ... Use "/* verilator lint_off INSECURE */" and lint_on around source to disable this message. +%Warning-INSECURE: Using --protect-ids with --vpi may expose private design details + ... Suggest remove --vpi. +%Error: Exiting due to diff --git a/test_regress/t/t_protect_ids_bad.pl b/test_regress/t/t_protect_ids_bad.pl new file mode 100755 index 000000000..c45b262af --- /dev/null +++ b/test_regress/t/t_protect_ids_bad.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["--protect-ids", + "--trace", + "--public", + "--vpi", + ], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_protect_ids_bad.v b/test_regress/t/t_protect_ids_bad.v new file mode 100644 index 000000000..52742f831 --- /dev/null +++ b/test_regress/t/t_protect_ids_bad.v @@ -0,0 +1,7 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2019 by Wilson Snyder. + +module t (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_protect_ids_c.cpp b/test_regress/t/t_protect_ids_c.cpp new file mode 100644 index 000000000..00657d5bf --- /dev/null +++ b/test_regress/t/t_protect_ids_c.cpp @@ -0,0 +1,51 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2009-2009 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License. +// Version 2.0. +// +// Verilator 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. +// +//************************************************************************* + +#include +#include +#include "svdpi.h" + +//====================================================================== + +#if defined(VERILATOR) +# ifdef T_PROTECT_IDS_KEY +# include "Vt_protect_ids_key__Dpi.h" +# else +# include "Vt_protect_ids__Dpi.h" +# endif +#elif defined(VCS) +# include "../vc_hdrs.h" +#elif defined(CADENCE) +# define NEED_EXTERNS +#else +# error "Unknown simulator for DPI test" +#endif + +#ifdef NEED_EXTERNS +# error "Not supported" +#endif + +//====================================================================== + +int dpii_a_func(int i) { + int o = dpix_a_func(i); + return o; +} + +int dpii_a_task(int i, int* op) { + int o = 0; + (void)dpix_a_task(i, op); + return 0; +} diff --git a/test_regress/t/t_protect_ids_key.out b/test_regress/t/t_protect_ids_key.out new file mode 100644 index 000000000..173c1b1e0 --- /dev/null +++ b/test_regress/t/t_protect_ids_key.out @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test_regress/t/t_protect_ids_key.pl b/test_regress/t/t_protect_ids_key.pl new file mode 100755 index 000000000..b51e8cd7b --- /dev/null +++ b/test_regress/t/t_protect_ids_key.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(vlt => 1); + +top_filename("t/t_protect_ids.v"); + +compile( + verilator_flags2 => ["--protect-ids --protect-key MY_KEY", + "t/t_protect_ids_c.cpp"], + ); + +execute( + check_finished => 1, + ); + +# Since using a named key, we can check for always identical map +files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__idmap.xml", $Self->{golden_filename}); + +ok(1); +1;