diff options
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | measure-stack.cc | 134 |
2 files changed, 138 insertions, 1 deletions
diff --git a/Makefile b/Makefile index c6de20c..9de3e0d 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ PREFIX ?= /usr/local BIN_PREFIX ::= $(DESTDIR)$(PREFIX)/bin/taosc- DATA_DIR ::= $(DESTDIR)$(PREFIX)/share/taosc -BIN ::= fix scout synth trace-call +BIN ::= fix measure-stack scout synth trace-call DATA ::= collect collection jump patch all: $(BIN) $(DATA) @@ -19,6 +19,9 @@ clean: fix: fix.m4 m4 -D DATA_DIR=$(DATA_DIR) $< > $@ +measure-stack: measure-stack.o helpers.o + $(CXX) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ + scout: scout.o helpers.o $(CXX) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ diff --git a/measure-stack.cc b/measure-stack.cc new file mode 100644 index 0000000..5151772 --- /dev/null +++ b/measure-stack.cc @@ -0,0 +1,134 @@ +// Function stack size counter +// Copyright (C) 2025 Nguyễn Gia Phong +// +// This file is part of taosc. +// +// Taosc is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Taosc 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with taosc. If not, see <https://www.gnu.org/licenses/>. + +#include "helpers.hh" + +// Dyninst headers +#include <Architecture.h> +#include <CFG.h> +#include <CodeObject.h> +#include <InstructionDecoder.h> +#include <Register.h> + +using Architecture = Dyninst::Architecture; +using Address = Dyninst::Address; +using Function = Dyninst::ParseAPI::Function; +using CodeObject = Dyninst::ParseAPI::CodeObject; +using CodeSource = Dyninst::ParseAPI::SymtabCodeSource; +using Instruction = Dyninst::InstructionAPI::Instruction; +using InstructionDecoder = Dyninst::InstructionAPI::InstructionDecoder; +using MachRegister = Dyninst::MachRegister; +using Operand = Dyninst::InstructionAPI::Operand; +using RegisterAST = Dyninst::InstructionAPI::RegisterAST; + +#include <cassert> +#include <cstdint> +#include <iostream> +#include <vector> +#include <utility> + +static int64_t +immediate (Operand const& operand) +{ + auto const& result = operand.getValue ().get ()->eval (); + assert (result.defined); + switch (result.type) + { + case Dyninst::InstructionAPI::s8: + case Dyninst::InstructionAPI::u8: + return result.val.s8val; + case Dyninst::InstructionAPI::s16: + case Dyninst::InstructionAPI::u16: + return result.val.s16val; + case Dyninst::InstructionAPI::s32: + case Dyninst::InstructionAPI::u32: + return result.val.s32val; + case Dyninst::InstructionAPI::s64: + case Dyninst::InstructionAPI::u64: + return result.val.s64val; + default: + std::unreachable (); + } +} + +static int64_t +stack_offset (Instruction const& instruction, + Architecture architecture) +{ + switch (instruction.getOperation ().getID ()) + { + case e_push: + return Dyninst::getArchAddressWidth (architecture); + case e_pop: + return -Dyninst::getArchAddressWidth (architecture); + case e_sub: + return immediate (instruction.getOperand (1)); + case e_add: + return -immediate (instruction.getOperand (1)); + default: + std::unreachable (); + } +} + +int +main (int argc, char** argv) +{ + CodeSource cs {parse_args (argc, argv)}; + auto const architecture = cs.getArch (); + RegisterAST::Ptr const stack_pointer + {new RegisterAST(MachRegister::getStackPointer (architecture))}; + CodeObject co {&cs}; + co.parse (); // parsed functions have same lifetime as co + while (!std::cin.eof ()) + { + Address address; + std::cin >> std::hex >> address; + if (std::cin.fail ()) + break; + auto* const block = find_block (cs, co, address); + if (block->containingFuncs () < 1) + die_for (address, "no function found containing instruction at"); + std::vector <Function*> functions; + block->getFuncs (functions); + size_t stack_size = 0; + for (auto* const fun : functions) + { + auto const entry = fun->addr (); + auto const* buffer = (char*) cs.getPtrToInstruction (entry); + auto const length = fun->entry ()->end () - entry; + InstructionDecoder decoder {buffer, length, architecture}; + size_t s = 0; + for (auto insn = decoder.decode (); + insn.isValid (); + insn = decoder.decode ()) + if (insn.isWritten (stack_pointer)) + s += stack_offset (insn, architecture); + if (s == 0) + continue; + if (stack_size == 0) + stack_size = s; + else if (s != stack_size) + die_for (address, "functions with different stack sizes spanning"); + } + std::cout << stack_size << '\n'; + } + if (std::cin.eof ()) + return 0; + std::cerr << "invalid input\n"; + return -1; +} |
