StreamFactory = std::function<std::unique_ptr<llvm::raw_ostream>()>;
86ModelDumper(llvm::json::OStream &JOS,
constEnvironment &Env)
90 JOS.attribute(
"value_id", llvm::to_string(&
V));
96 switch(
V.getKind()) {
103 JOS.attributeObject(
104 "pointee", [&] {
dump(cast<PointerValue>(
V).getPointeeLoc()); });
108 for(
const auto& Prop :
V.properties())
109 JOS.attributeObject((
"p:"+ Prop.first()).str(),
110[&] {
dump(*Prop.second); });
114 if(
auto*B = llvm::dyn_cast<BoolValue>(&
V)) {
115 JOS.attribute(
"formula", llvm::to_string(B->formula()));
116 JOS.attribute(
"truth",
Env.proves(B->formula()) ?
"true" 117:
Env.proves(
Env.arena().makeNot(B->formula()))
122 void dump(
constStorageLocation &L) {
123 JOS.attribute(
"location", llvm::to_string(&L));
124 if(!
Visited.insert(&L).second)
127 JOS.attribute(
"type", L.getType().getAsString());
128 if(!L.getType()->isRecordType())
129 if(
auto*
V=
Env.getValue(L))
132 if(
auto*RLoc = dyn_cast<RecordStorageLocation>(&L)) {
133 for(
const auto&Child : RLoc->children())
134 JOS.attributeObject(
"f:"+ Child.first->getNameAsString(), [&] {
139 for(
const auto&SyntheticField : RLoc->synthetic_fields())
140 JOS.attributeObject((
"sf:"+ SyntheticField.first()).str(),
141[&] { dump(*SyntheticField.second); });
146llvm::json::OStream &
JOS;
150classHTMLLogger :
publicLogger {
158StreamFactory Streams;
159std::unique_ptr<llvm::raw_ostream> OS;
161llvm::raw_string_ostream JStringStream{JSON};
162llvm::json::OStream
JOS{JStringStream,
2};
164 constAdornedCFG *ACFG;
166std::vector<Iteration> Iters;
168llvm::DenseMap<const CFGBlock *, llvm::SmallVector<size_t>> BlockIters;
170llvm::BitVector BlockConverged;
172std::string ContextLogs;
174 unsignedElementIndex;
177 explicitHTMLLogger(StreamFactory Streams) : Streams(
std::move(Streams)) {}
178 voidbeginAnalysis(
constAdornedCFG &ACFG,
179TypeErasedDataflowAnalysis &A)
override{
182*OS << llvm::StringRef(HTMLLogger_html).split(
"<?INJECT?>").first;
184BlockConverged.resize(ACFG.getCFG().getNumBlockIDs());
186 const auto&
D= ACFG.getDecl();
187 const auto&
SM= A.getASTContext().getSourceManager();
189 if(
const auto*ND = dyn_cast<NamedDecl>(&
D))
190*OS << ND->getNameAsString() <<
" at ";
191*OS <<
SM.getFilename(
D.getLocation()) <<
":" 192<<
SM.getSpellingLineNumber(
D.getLocation());
193*OS <<
"</title>\n";
195*OS <<
"<style>"<< HTMLLogger_css <<
"</style>\n";
196*OS <<
"<script>"<< HTMLLogger_js <<
"</script>\n";
200 JOS.attributeBegin(
"states");
205 voidendAnalysis()
override{
209 JOS.attributeArray(
"timeline", [&] {
210 for(
const auto&
E: Iters) {
212 JOS.attribute(
"block", blockID(
E.Block->getBlockID()));
213 JOS.attribute(
"iter",
E.Iter);
214 JOS.attribute(
"post_visit",
E.PostVisit);
215 JOS.attribute(
"converged",
E.Converged);
219 JOS.attributeObject(
"cfg", [&] {
220 for(
const auto&
E: BlockIters)
221writeBlock(*
E.first,
E.second);
228*OS <<
"<script>var HTMLLoggerData = \n";
230*OS <<
";\n</script>\n";
231*OS << llvm::StringRef(HTMLLogger_html).split(
"<?INJECT?>").second;
234 voidenterBlock(
constCFGBlock &B,
bool PostVisit)
override{
236 unsignedIterNum = BIter.size() + 1;
237BIter.push_back(Iters.size());
238Iters.push_back({&B, IterNum,
PostVisit,
false});
240BlockConverged[B.getBlockID()] =
false;
243 voidenterElement(
constCFGElement &
E)
override{
247 staticstd::string blockID(
unsigned Block) {
248 returnllvm::formatv(
"B{0}",
Block);
250 staticstd::string eltID(
unsigned Block,
unsignedElement) {
251 returnllvm::formatv(
"B{0}.{1}",
Block, Element);
253 staticstd::string iterID(
unsigned Block,
unsigned Iter) {
254 returnllvm::formatv(
"B{0}:{1}",
Block,
Iter);
256 staticstd::string elementIterID(
unsigned Block,
unsigned Iter,
258 returnllvm::formatv(
"B{0}:{1}_B{0}.{2}",
Block,
Iter, Element);
267 voidrecordState(TypeErasedDataflowAnalysisState &State)
override{
268 unsigned Block= Iters.back().Block->getBlockID();
269 unsigned Iter= Iters.back().Iter;
271 JOS.attributeObject(elementIterID(
Block,
Iter, ElementIndex), [&] {
272 JOS.attribute(
"block", blockID(
Block));
273 JOS.attribute(
"iter",
Iter);
275 JOS.attribute(
"element", ElementIndex);
278 if(ElementIndex > 0) {
280Iters.back().
Block->Elements[ElementIndex - 1].getAs<CFGStmt>();
281 if(
constExpr *
E= S ? llvm::dyn_cast<Expr>(S->getStmt()) :
nullptr) {
282if (E->isPRValue()) {
283if (!E->getType()->isRecordType())
284if (auto *V = State.Env.getValue(*E))
286 "value", [&] { ModelDumper(JOS, State.Env).dump(*V); });
288if (auto *Loc = State.Env.getStorageLocation(*E))
290 "value", [&] { ModelDumper(JOS, State.Env).dump(*Loc); });
294 if(!ContextLogs.empty()) {
295 JOS.attribute(
"logs", ContextLogs);
299std::string BuiltinLattice;
300llvm::raw_string_ostream BuiltinLatticeS(BuiltinLattice);
301State.Env.dump(BuiltinLatticeS);
302 JOS.attribute(
"builtinLattice", BuiltinLattice);
306 voidblockConverged()
override{
307Iters.back().Converged =
true;
308BlockConverged[Iters.back().Block->getBlockID()] =
true;
311 voidlogText(llvm::StringRef S)
override{
312ContextLogs.append(S.begin(), S.end());
313ContextLogs.push_back(
'\n');
321 JOS.attributeObject(blockID(B.getBlockID()), [&] {
322JOS.attributeArray(
"iters", [&] {
323for (size_t IterIdx : ItersForB) {
324const Iteration &Iter = Iters[IterIdx];
326JOS.attribute(
"iter", Iter.Iter);
327JOS.attribute(
"post_visit", Iter.PostVisit);
328JOS.attribute(
"converged", Iter.Converged);
332 JOS.attributeArray(
"elements", [&] {
333 for(
const auto&Elt : B.Elements) {
335llvm::raw_string_ostream DumpS(Dump);
336Elt.dumpToStream(DumpS);
348 const auto&AST = ACFG->getDecl().getASTContext();
356CharSourceRange::getTokenRange(ACFG->getDecl().getSourceRange()),
357AST.getSourceManager(), AST.getLangOpts());
358 if(
Range.isInvalid())
361 Range, AST.getSourceManager(), AST.getLangOpts(), &Invalid);
367enum :
unsigned{ Missing =
static_cast<unsigned>(-1) };
371 unsignedBB = Missing;
372 unsignedBBPriority = 0;
374 unsignedElt = Missing;
375 unsignedEltPriority = 0;
377SmallVector<unsigned> Elts;
385 voidassign(
unsignedBB,
unsignedElt,
unsignedRangeLen) {
387 if(this->BB != Missing && BB != this->BB && BBPriority <= RangeLen)
389 if(BB != this->BB) {
392BBPriority = RangeLen;
394BBPriority = std::min(BBPriority, RangeLen);
396 if(this->Elt == Missing || EltPriority > RangeLen)
399 bool operator==(
constTokenInfo &Other)
const{
400 returnstd::tie(BB, Elt, Elts) ==
404 voidwrite(llvm::raw_ostream &OS)
const{
407OS <<
" "<< blockID(BB);
408 for(
unsignedElt : Elts)
409OS <<
" "<< eltID(BB, Elt);
413OS <<
" data-elt='"<< eltID(BB, Elt) <<
"'";
415OS <<
" data-bb='"<< blockID(BB) <<
"'";
421std::vector<TokenInfo> State(Code.size());
422 for(
const auto*
Block: ACFG->getCFG()) {
423 unsignedEltIndex = 0;
424 for(
const auto& Elt : *
Block) {
426 if(
const autoS = Elt.getAs<CFGStmt>()) {
428CharSourceRange::getTokenRange(S->getStmt()->getSourceRange()),
429AST.getSourceManager(), AST.getLangOpts());
430 if(EltRange.isInvalid())
432 if(EltRange.getBegin() <
Range.getBegin() ||
433EltRange.getEnd() >=
Range.getEnd() ||
434EltRange.getEnd() <
Range.getBegin() ||
435EltRange.getEnd() >=
Range.getEnd())
437 unsignedOff = EltRange.getBegin().getRawEncoding() -
438 Range.getBegin().getRawEncoding();
439 unsignedLen = EltRange.getEnd().getRawEncoding() -
440EltRange.getBegin().getRawEncoding();
441 for(
unsignedI = 0; I < Len; ++I)
442State[Off + I].assign(
Block->getBlockID(), EltIndex, Len);
449AST.getSourceManager().getSpellingLineNumber(
Range.getBegin());
450*OS <<
"<template data-copy='code'>\n";
451*OS <<
"<code class='filename'>";
452llvm::printHTMLEscaped(
453llvm::sys::path::filename(
454AST.getSourceManager().getFilename(
Range.getBegin())),
457*OS <<
"<code class='line' data-line='"<< Line++ <<
"'>";
458 for(
unsignedI = 0; I < Code.size(); ++I) {
461 boolNeedOpen = I == 0 || !(State[I] == State[I-1]);
462 boolNeedClose = I + 1 == Code.size() || !(State[I] == State[I + 1]);
468 if(Code[I] ==
'\n')
469*OS <<
"</code>\n<code class='line' data-line='"<< Line++ <<
"'>";
471llvm::printHTMLEscaped(Code.substr(I, 1), *OS);
472 if(NeedClose) *OS <<
"</span>";
475*OS <<
"</template>";
482*OS <<
"<template data-copy='cfg'>\n";
483 if(
autoSVG = renderSVG(buildCFGDot(ACFG->getCFG())))
486*OS <<
"Can't draw CFG: "<<
toString(SVG.takeError());
487*OS <<
"</template>\n";
491std::string buildCFGDot(
const clang::CFG&CFG) {
493llvm::raw_string_ostream GraphS(Graph);
495GraphS << R
"(digraph { 497 node[class=bb, shape=square, fontname="sans-serif", tooltip=" "] 501std::string Name = blockID(I);
503 const char*ConvergenceMarker = (
const char*)u8
"\\n\u2192\u007c";
504 if(BlockConverged[I])
505Name += ConvergenceMarker;
506GraphS <<
" "<< blockID(I) <<
" [id="<< blockID(I) <<
" label=\"" 509 for(
const auto*
Block: CFG) {
510 for(
const auto&Succ :
Block->succs()) {
511 if(Succ.getReachableBlock())
512GraphS <<
" "<< blockID(
Block->getBlockID()) <<
" -> " 513<< blockID(Succ.getReachableBlock()->getBlockID()) <<
"\n";
524 if(
const auto*FromEnv = ::getenv(
"GRAPHVIZ_DOT"))
527 autoFromPath = llvm::sys::findProgramByName(
"dot");
529 returnllvm::createStringError(FromPath.getError(),
530 "'dot' not found on PATH");
531DotPath = FromPath.get();
538 if(
autoEC = llvm::sys::fs::createTemporaryFile(
"analysis",
".dot", InputFD,
540 returnllvm::createStringError(EC,
"failed to create `dot` temp input");
541llvm::raw_fd_ostream(InputFD,
true) << DotGraph;
543llvm::make_scope_exit([&] { llvm::sys::fs::remove(Input); });
544 if(
autoEC = llvm::sys::fs::createTemporaryFile(
"analysis",
".svg", Output))
545 returnllvm::createStringError(EC,
"failed to create `dot` temp output");
547llvm::make_scope_exit([&] { llvm::sys::fs::remove(Output); });
549std::vector<std::optional<llvm::StringRef>> Redirects = {
553 intCode = llvm::sys::ExecuteAndWait(
554DotPath, {
"dot",
"-Tsvg"},
std::nullopt, Redirects,
557 returnllvm::createStringError(llvm::inconvertibleErrorCode(),
558 "'dot' failed: "+ ErrMsg);
560 returnllvm::createStringError(llvm::inconvertibleErrorCode(),
561 "'dot' failed ("+ llvm::Twine(Code) +
")");
563 autoBuf = llvm::MemoryBuffer::getFile(Output);
565 returnllvm::createStringError(Buf.getError(),
"Can't read `dot` output");
568llvm::StringRef Result = Buf.get()->getBuffer();
569 autoPos = Result.find(
"<svg");
570 if(Pos == llvm::StringRef::npos)
571 returnllvm::createStringError(llvm::inconvertibleErrorCode(),
572 "Can't find <svg> tag in `dot` output");
573 returnResult.substr(Pos).str();
578std::unique_ptr<Logger>
579Logger::html(std::function<std::unique_ptr<llvm::raw_ostream>()> Streams) {
580 returnstd::make_unique<HTMLLogger>(std::move(Streams));
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
llvm::json::OStream & JOS
llvm::DenseSet< const void * > Visited
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
Defines the SourceManager interface.
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
static CharSourceRange makeFileCharRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Accepts a range and returns a character range with file locations.
Dataflow Directional Tag Classes.
llvm::StringRef debugString(Value::Kind Kind)
Returns a string representation of a value kind.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
@ Other
Other implicit parameter.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4