* Copyright (c) 2021-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cstdio>
#include <cstdlib>
#include <securec.h>
#include <string>
#include <unistd.h>
#include <getopt.h>
#include "dfx_define.h"
#include "dfx_log.h"
#include "dump_catcher.h"
#include "faultloggerd_client.h"
#if defined(DEBUG_CRASH_LOCAL_HANDLER)
#include "dfx_signal_local_handler.h"
#endif
using namespace OHOS::HiviewDFX;
static const std::string DUMP_STACK_TAG_USAGE = "Usage:";
static const std::string DUMP_STACK_TAG_FAILED = "Failed:";
static constexpr int SAVE_CORE_DUMP_TIMEOUT = 10000;
static void PrintCommandHelp()
{
printf("%s\n", DUMP_STACK_TAG_USAGE.c_str());
printf("-p pid | dump the stacktrace of all the threads with given pid, timeout default 3000ms.\n");
printf("-p pid -t tid | dump the stacktrace of the thread with given tid .\n");
printf("-p pid -T timeout(ms) | dump the stacktrace of the thread with given tid in timeout.\n");
printf("-k pid | dump the origin kernel stacktrace without ark of the pid.\n");
printf("-k pid -a | dump the origin kernel stacktrace with ark of the pid.\n");
printf("-k pid -a -f | dump the origin kernel stacktrace with ark of the pid and format parse stack.\n");
printf("-c save pid | begin to coredump the process of the pid.\n");
printf("-c cancel pid | cancel to coredump the process of the pid.\n");
}
static void PrintCommandFailed()
{
printf("%s\npid and tid and timeout must > 0.\n", DUMP_STACK_TAG_FAILED.c_str());
}
static int GetIdFromArgs(char *optarg, int32_t &id)
{
int ret = 0;
if (atoi(optarg) > 0) {
ret = 1;
id = atoi(optarg);
} else {
ret = -1;
PrintCommandFailed();
}
return ret;
}
static int ExecuteCoredumpCmd(std::string subCmd, char* pidChar)
{
if (atoi(pidChar) <= 0) {
printf("pid error, input should like dumpcatcher -c save/cancel pid\n");
return -1;
}
pid_t pid = atoi(pidChar);
printf("cmd is -c %s %d \n", subCmd.c_str(), pid);
if (subCmd == "save") {
SaveCoredumpToFileTimeout(pid, SAVE_CORE_DUMP_TIMEOUT);
return 0;
} else if (subCmd == "cancel") {
CancelCoredump(pid);
return 0;
} else {
printf("input error coredump cmd!\n");
return -1;
}
}
static int ParseParamters(int argc, char *argv[], DumpOptions& dumpOpt)
{
int ret = 0;
if (argc <= 1) {
return ret;
}
DFXLOGD("[%{public}d]: argc: %{public}d, argv1: %{public}s", __LINE__, argc, argv[1]);
int optRet;
const char *optString = "p:t:c:T:k:af";
while ((optRet = getopt(argc, argv, optString)) != -1) {
if (optarg == nullptr) {
continue;
}
switch (optRet) {
case 'a':
dumpOpt.needArk = true;
break;
case 'c':
if (optind >= argc) {
printf("input error, input should like dumpcatcher -c save/cancel pid\n");
return 0;
}
ExecuteCoredumpCmd(optarg, argv[optind]);
return 0;
case 'f':
dumpOpt.needParse = true;
break;
case 'k':
ret = GetIdFromArgs(optarg, dumpOpt.pid);
dumpOpt.type = DumpType::DUMP_KERNEL_STACK;
break;
case 'p':
ret = GetIdFromArgs(optarg, dumpOpt.pid);
dumpOpt.type = DumpType::DUMP_USER_STACK;
break;
case 't':
ret = GetIdFromArgs(optarg, dumpOpt.tid);
break;
case 'T':
ret = GetIdFromArgs(optarg, dumpOpt.timeout);
break;
default:
ret = 0;
break;
}
}
if (ret == 0) {
PrintCommandHelp();
}
return ret;
}
int main(int argc, char *argv[])
{
#if defined(DEBUG_CRASH_LOCAL_HANDLER)
DFX_InstallLocalSignalHandler();
#endif
DumpOptions dumpOpt;
alarm(DUMPCATCHER_TIMEOUT);
setsid();
if (ParseParamters(argc, argv, dumpOpt) <= 0) {
return 0;
}
DFXLOGD("pid: %{public}d, tid: %{public}d, timeout: %{public}d", dumpOpt.pid, dumpOpt.tid, dumpOpt.timeout);
if (dumpOpt.type == DumpType::DUMP_USER_STACK) {
DumpCatcher::GetInstance().Dump(dumpOpt);
} else if (dumpOpt.type == DumpType::DUMP_KERNEL_STACK) {
DumpCatcher::GetInstance().DumpKernelStack(dumpOpt);
}
return 0;
}