1 #include "disassembler.h"
2 #include "../plugins/assembler/algorithm/algorithm.h"
3 #include <algorithm>
4 #include <memory>
5 
6 namespace REDasm {
7 
Disassembler(AssemblerPlugin * assembler,LoaderPlugin * loader)8 Disassembler::Disassembler(AssemblerPlugin *assembler, LoaderPlugin *loader): DisassemblerBase(assembler, loader)
9 {
10     m_algorithm = REDasm::safe_ptr<AssemblerAlgorithm>(m_assembler->createAlgorithm(this));
11 
12     m_analyzejob.setOneShot(true);
13     EVENT_CONNECT(&m_analyzejob, stateChanged, this, [&](Job*) { busyChanged(); });
14     m_analyzejob.work(std::bind(&Disassembler::analyzeStep, this), true); // Deferred
15     EVENT_CONNECT(&m_jobs, stateChanged, this, [&](Job*) { busyChanged(); });
16 }
17 
disassembleStep(Job * job)18 void Disassembler::disassembleStep(Job* job)
19 {
20     if(m_algorithm->hasNext())
21         m_algorithm->next();
22     else
23         job->stop();
24 
25     if(!m_jobs.active())
26         m_analyzejob.start();
27 }
28 
analyzeStep()29 void Disassembler::analyzeStep()
30 {
31     m_algorithm->analyze();
32     auto duration = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - m_starttime);
33 
34     if(duration.count())
35     {
36         std::stringstream ss;
37         ss << duration.count();
38         REDasm::log("Analysis completed in ~" + ss.str() + " second(s)");
39     }
40     else
41         REDasm::log("Analysis completed");
42 }
43 
disassemble()44 void Disassembler::disassemble()
45 {
46     m_starttime = std::chrono::steady_clock::now();
47 
48     if(!this->document()->segmentsCount())
49     {
50         REDasm::log("ERROR: Segment list is empty");
51         return;
52     }
53 
54     const SymbolTable* symboltable = this->document()->symbols();
55 
56     // Preload loader functions for analysis
57     symboltable->iterate(SymbolType::FunctionMask, [=](const Symbol* symbol) -> bool {
58         m_algorithm->enqueue(symbol->address);
59         return true;
60     });
61 
62     const Symbol* entrypoint = this->document()->documentEntry();
63 
64     if(entrypoint)
65         m_algorithm->enqueue(entrypoint->address); // Push entry point
66 
67     REDasm::log("Disassembling with " + std::to_string(m_jobs.concurrency()) + " threads");
68     this->disassembleJob();
69 }
70 
createPrinter()71 Printer *Disassembler::createPrinter() { return m_assembler->createPrinter(this); }
72 
disassemble(address_t address)73 void Disassembler::disassemble(address_t address)
74 {
75     m_algorithm->enqueue(address);
76 
77     if(m_jobs.active())
78         return;
79 
80     this->disassembleJob();
81 }
82 
stop()83 void Disassembler::stop() { m_jobs.stop(); }
pause()84 void Disassembler::pause() { m_jobs.pause(); }
resume()85 void Disassembler::resume() { m_jobs.resume(); }
state() const86 size_t Disassembler::state() const { return m_jobs.state(); }
busy() const87 bool Disassembler::busy() const { return m_analyzejob.active() || m_jobs.active(); }
disassembleJob()88 void Disassembler::disassembleJob() { m_jobs.work(std::bind(&Disassembler::disassembleStep, this, std::placeholders::_1)); }
89 
disassembleInstruction(address_t address)90 InstructionPtr Disassembler::disassembleInstruction(address_t address)
91 {
92     InstructionPtr instruction = this->document()->instruction(address);
93 
94     if(instruction)
95         return instruction;
96 
97     instruction = std::make_shared<Instruction>();
98     m_algorithm->disassembleInstruction(address, instruction);
99     m_algorithm->done(address);
100     return instruction;
101 }
102 
103 }
104