#include <gelf.h>
#include <dwarf.h>
#include <libdwfl.h>
+#include <libdwfl_stacktrace.h>
#include <libdw.h>
#include "../libebl/libebl.h"
-#include "../libdwfl_stacktrace/libdwfl_stacktrace.h"
+
+// optional debug code
+//#define STACKPROF_STATS_DEBUG
using namespace std;
{ "verbose", 'v', NULL, 0, N_("Increase verbosity of logging messages (modules/samples/frames/more)."), 0 },
/* TODO: Add "quiet" option suppressing summary table. */
{ "gmon", 'g', NULL, 0, N_("Generate gmon.BUILDID.out files for each binary."), 0 },
- { "hist-split", 'G', HIST_SPLIT_OPTS, 0, N_("Histogram splitting method for gmon, default 'even'."), 0 },
+ { "hist-split", 'G', HIST_SPLIT_OPTS, 0, N_("Split gmon histogram output into even or flexible chunks, default 'even'."), 0 },
{ "maxframes", 'n', "MAXFRAMES", 0, N_("Maximum number of frames to unwind, default 1 with --gmon, 256 otherwise."), 0 },
{ "output", 'o', "DIR", 0, N_("Output directory for gmon.BUILDID.out files."), 0 },
{ "force", 'f', NULL, 0, N_("Unlink output files to force writing as new."), 0 },
case 'p':
pid = atoi(arg);
+ if (pid == 0)
+ argp_error (state, N_("-p PID should be a positive process id."));
break;
case 'n':
}
else
{
-#if 1
+#ifndef STACKPROF_STATS_DEBUG
tab = new UnwindStatsTable();
usc = new UnwindStatsConsumer(tab);
pcu = new PerfConsumerUnwinder(usc, tab);
catch (const exception& e)
{
cerr << format("{}\n", e.what());
+ return 127;
}
return 0;
std::string_view machine = u.machine;
if (machine == "x86_64") em = EM_X86_64;
else if (machine == "i686" || machine == "i386") em = EM_386;
- else if (machine == "aarch64" || machine == "armv7l") em = EM_ARM;
+ else if (machine == "aarch64") em = EM_AARCH64;
+ else if (machine == "armv7l") em = EM_ARM;
else {
cerr << format("ERROR: Unsupported architecture: {}\n", u.machine);
exit(1);
int m = ebl_get_elfmachine(ebl);
/* TODO: Generalize the API via libdwflst to allow any architecture. */
/* For aarch64, we actually use fewer than ebl->frame_nregs to unwind. */
- if (m == EM_ARM) /* TODO also EM_AARCH64 */
- return 14; /* XXX 16 for 32-bit ARM */
+ if (m == EM_AARCH64)
+ return 14;
+ if (m == EM_ARM)
+ return 16;
/* On x86, expect everything except FLAGS: */
if (m == EM_X86_64 || m == EM_386)
return ebl_frame_nregs(ebl);
goto reuse;
}
err = this->find_procfile(dwfl, &pid, &elf, &elf_fd);
- if (err < 0)
+ if (err != 0) /* TODO check errnos */
{
if (verbose)
cerr << format("WARNING: find_procfile pid {}: {}\n", (long long) pid, dwfl_errmsg(-1));
/* TODO: Generalize the API via libdwflst to allow any architecture. */
int machine = ebl_get_elfmachine(this->reader->ebl());
if (machine == EM_X86_64 || machine == EM_386) return is_abi32 ? 4 : 7;
- else if (machine == EM_ARM) return is_abi32 ? 13 : 31;
+ else if (machine == EM_ARM || machine == EM_AARCH64) return is_abi32 ? 13 : 31;
else { assert(0); return 7; }
}
if (!of)
{
cerr << format(N_("ERROR: buildid {} -- could not open '{}' for writing\n"), buildid, filename);
+ return;
}
/* Write gmon header. It and other headers mostly hold
uint64_t next_size = opt_size;
while (next_size < max_size)
{
- if (next_size > max_size)
- next_size = max_size;
uint64_t size_inc = sizeof(struct gmon_hdr) + next_size;
uint64_t size_est = size_inc;
uint64_t pc = low_pc;
Dwfl_Module *mod = dwfl_addrmodule(sample->dwfl, pc);
if (mod == NULL)
return;
-#if 0
- // XXX is the bias needed?
- Dwarf_Addr bias;
- Elf *elf = dwfl_module_getelf(mod, &bias);
- (void)elf;
-#endif
Dwfl_Module *mod2 = dwfl_addrmodule(sample->dwfl, pc2);
// XXX: allowing mod2 == NULL -- callgraph arc will be skipped