Use gdb

gdb <binary>
gdb --args <binary> -i ...
(gdb) break filename:linenum
(gdb) step
(gdb) stepi
(gdb) next
(gdb) nexti
(gdb) finish
(gdb) continue
(gdb) until
(gdb) frame <frame #>
(gdb) info args
(gdb) info locals
(gdb) p <variable name>

(gdb) clear linenum
(gdb) clear filename:linenum
(gdb) info break
(gdb) del <breakpoint #>
(gdb) del <start #> - <end #>

(gdb) help <option name>

Use gdb to find where to throw a C++ exception

Here is a simple example about how to find where to throw a C++ exception.

#include <iostream>
#include <stdexcept>

using namespace std;

void computeIntegral() {
  throw std::runtime_error( "Input data is not valid" );  
}

int main(int argc, char** argv) {
  try {
    computeIntegral();
  } catch( std::runtime_error &e ) {
    cout << "Caught an exception: " << e.what() << endl;
  }
  
  return 0;
}

Build and run it.

g++ testException.cpp --std=c++14
./a.out
Caught an exception: Input data is not valid

Now use gdb to debug it.

gdb --args ./a.out
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) r
...
(gdb) bt
#0  __cxxabiv1::__cxa_throw (obj=0x614ca0, 
    tinfo=0x6020c0 <_ZTISt13runtime_error@@GLIBCXX_3.4>, 
    dest=0x400a40 <_ZNSt13runtime_errorD1Ev@plt>)
    at ../../../../gcc-8.3.0/libstdc++-v3/libsupc++/eh_throw.cc:80
#1  0x0000000000400bd5 in computeIntegral() ()
#2  0x0000000000400c00 in main ()