| Andrew Jeffery | c7a446e | 2022-07-21 10:14:54 +0930 | [diff] [blame] | 1 | #!/bin/sh | 
 | 2 |  | 
 | 3 | set -eu | 
 | 4 |  | 
 | 5 | : ${IPKDBG_OPKG_CACHE:=} | 
 | 6 | : ${IPKDBG_CONF_HOST:=host.local} | 
 | 7 | : ${IPKDBG_CONF_MNT:=mountpoint} | 
 | 8 | : ${IPKDBG_CONF_LOC:=themoon} | 
 | 9 | : ${IPKDBG_CONF_ROOT:=path} | 
 | 10 | : ${IPKDBG_CONF_USER:=$USER} | 
 | 11 | : ${IPKDBG_WGET_OPTS:="--quiet"} | 
 | 12 | : ${IPKDBG_ZSTD:=zstd} | 
 | 13 |  | 
 | 14 | ipkdbg_error() { | 
 | 15 |     /bin/echo -e "$@" | fold >&2 | 
 | 16 | } | 
 | 17 |  | 
 | 18 | ipkdbg_info() { | 
 | 19 |     /bin/echo -e "$@" | fold | 
 | 20 | } | 
 | 21 |  | 
 | 22 | ipkdbg_help() { | 
 | 23 | /bin/echo -e "\033[1mNAME\033[0m" | 
 | 24 | /bin/echo -e "\tipkdbg - debug OpenBMC applications from an (internally) released firmware" | 
 | 25 | /bin/echo -e | 
 | 26 | /bin/echo -e "\033[1mSYNOPSIS\033[0m" | 
 | 27 | /bin/echo -e "\tipkdbg [-q] RELEASE FILE CORE [PACKAGE...]" | 
 | 28 | /bin/echo -e | 
 | 29 | /bin/echo -e "\033[1mDESCRIPTION\033[0m" | 
 | 30 | /bin/echo -e "\tRELEASE is the firmware release whose packages to install" | 
 | 31 | /bin/echo -e "\tFILE is the absolute path to the binary of interest in the target environment" | 
 | 32 | /bin/echo -e "\tCORE is an optional core file generated by FILE. Pass '-' for no core file" | 
 | 33 | /bin/echo -e "\tPACKAGES will be used to populate a temporary rootfs for debugging FILE" | 
 | 34 | /bin/echo -e | 
 | 35 | /bin/echo -e "\033[1mOPTIONS\033[0m" | 
 | 36 | /bin/echo -e "\t\033[1m-h\033[0m" | 
 | 37 | /bin/echo -e "\tPrint this help." | 
 | 38 | /bin/echo -e | 
 | 39 | /bin/echo -e "\t\033[1m-q\033[0m" | 
 | 40 | /bin/echo -e "\tQuit gdb once done. Intended for use in a scripting environment in combination" | 
 | 41 | /bin/echo -e "\twith a core file, as the backtrace will be printed as an implicit first command." | 
 | 42 | /bin/echo -e | 
 | 43 | /bin/echo -e "\033[1mENVIRONMENT\033[0m" | 
 | 44 | /bin/echo -e "\tThere are several important environment variables controlling the behaviour of" | 
 | 45 | /bin/echo -e "\tthe script:" | 
 | 46 | /bin/echo -e | 
 | 47 | /bin/echo -e "\t\033[1mIPKDBG_OPKG_CACHE\033[0m" | 
 | 48 | /bin/echo -e "\tA package cache directory for opkg. Defaults to empty, disabling the cache." | 
 | 49 | /bin/echo -e | 
 | 50 | /bin/echo -e "\t\033[1mIPKDBG_CONF_HOST\033[0m" | 
 | 51 | /bin/echo -e "\tHostname for access to opkg.conf over the web interface" | 
 | 52 | /bin/echo -e | 
 | 53 | /bin/echo -e "\tDefaults to '${IPKDBG_CONF_HOST}'" | 
 | 54 | /bin/echo -e | 
 | 55 | /bin/echo -e "\t\033[1mIPKDBG_CONF_MNT\033[0m" | 
 | 56 | /bin/echo -e "\tMount-point for access to opkg.conf" | 
 | 57 | /bin/echo -e | 
 | 58 | /bin/echo -e "\tDefaults to '${IPKDBG_CONF_MNT}'" | 
 | 59 | /bin/echo -e | 
 | 60 | /bin/echo -e "\t\033[1mIPKDBG_CONF_LOC\033[0m" | 
 | 61 | /bin/echo -e "\tGeo-location for access to opkg.conf" | 
 | 62 | /bin/echo -e | 
 | 63 | /bin/echo -e "\tDefaults to '${IPKDBG_CONF_LOC}'" | 
 | 64 | /bin/echo -e | 
 | 65 | /bin/echo -e "\t\033[1mIPKDBG_CONF_ROOT\033[0m" | 
 | 66 | /bin/echo -e "\tPath to the directory containing build artifacts, for access to opkg.conf" | 
 | 67 | /bin/echo -e | 
 | 68 | /bin/echo -e "\tDefaults to '${IPKDBG_CONF_ROOT}'" | 
 | 69 | /bin/echo -e | 
 | 70 | /bin/echo -e "\t\033[1mIPKDBG_CONF_USER\033[0m" | 
 | 71 | /bin/echo -e "\tUsername for access to opkg.conf over the web interface" | 
 | 72 | /bin/echo -e | 
 | 73 | /bin/echo -e "\tDefaults to \$USER ($USER)" | 
 | 74 | /bin/echo -e | 
 | 75 | /bin/echo -e "\t\033[1mIPKDBG_GDB\033[0m" | 
 | 76 | /bin/echo -e "\tThe gdb(1) binary to invoke. Automatically detected if unset." | 
 | 77 | /bin/echo -e | 
 | 78 | /bin/echo -e "\t\033[1mIPKDBG_WGET_OPTS\033[0m" | 
 | 79 | /bin/echo -e "\tUser options to pass to wget(1) when fetching opkg.conf. Defaults to" | 
 | 80 | /bin/echo -e "\t'$IPKDBG_WGET_OPTS'" | 
 | 81 | /bin/echo -e | 
 | 82 | /bin/echo -e "\t\033[1mIPKDBG_ZSTD\033[0m" | 
 | 83 | /bin/echo -e "\tThe zstd(1) binary to extract the compressed core dump. Automatically" | 
 | 84 | /bin/echo -e "\tdetected if unset." | 
 | 85 | /bin/echo -e | 
 | 86 | /bin/echo -e "\033[1mEXAMPLE\033[0m" | 
 | 87 | /bin/echo -e "\tipkdbg 1020.2206.20220208a \\" | 
 | 88 | /bin/echo -e "\t\t/usr/bin/nvmesensor - \\" | 
 | 89 | /bin/echo -e "\t\tdbus-sensors dbus-sensors-dbg" | 
 | 90 | } | 
 | 91 |  | 
 | 92 | IPKDBG_OPT_QUIT=0 | 
 | 93 |  | 
 | 94 | while getopts hq f | 
 | 95 | do | 
 | 96 |     case $f in | 
 | 97 |     q) IPKDBG_OPT_QUIT=1;; | 
 | 98 |     h|\?) ipkdbg_help ; exit 1;; | 
 | 99 |     esac | 
 | 100 | done | 
 | 101 | shift $(expr $OPTIND - 1) | 
 | 102 |  | 
 | 103 | trap ipkdbg_help EXIT | 
 | 104 |  | 
 | 105 | ipkdbg_core_extract() | 
 | 106 | { | 
 | 107 |     if [ "-" = "$1" ] | 
 | 108 |     then | 
 | 109 |         echo - | 
 | 110 |     else | 
 | 111 |         local src="$(realpath "$1")" | 
 | 112 |         local dst="${src%.zst}" | 
 | 113 |  | 
 | 114 |         command -v $IPKDBG_ZSTD > /dev/null | 
 | 115 |         $IPKDBG_ZSTD --decompress --quiet --quiet --force -o "$dst" "$src" || true | 
 | 116 |         echo "$dst" | 
 | 117 |     fi | 
 | 118 | } | 
 | 119 |  | 
 | 120 | IPKDBG_BUILD=$1; shift | 
 | 121 | IPKDBG_FILE=$1; shift | 
 | 122 | IPKDBG_CORE=$(ipkdbg_core_extract "$1"); shift | 
 | 123 | IPKDBG_PKGS=$@ | 
 | 124 |  | 
 | 125 | : ${IPKDBG_GDB:=} | 
 | 126 | if [ -n "$IPKDBG_GDB" ] | 
 | 127 | then | 
 | 128 |     ipkdbg_info "Using provided gdb command '$IPKDBG_GDB'" | 
 | 129 | else | 
 | 130 |     os_id=$(. /etc/os-release; echo ${ID}-${VERSION_ID}) | 
 | 131 |     case $os_id in | 
 | 132 |     rhel-8.6 | fedora*) | 
 | 133 |         IPKDBG_GDB=gdb | 
 | 134 |         if [ -z "$(command -v $IPKDBG_GDB)" ] | 
 | 135 |         then | 
 | 136 |             ipkdbg_error "Please install the gdb package:" | 
 | 137 |             ipkdbg_error | 
 | 138 |             ipkdbg_error "\tsudo dnf install gdb" | 
 | 139 |             ipkdbg_error | 
 | 140 |             exit 1 | 
 | 141 |         fi | 
 | 142 |         ;; | 
 | 143 |     rhel*) | 
 | 144 |         IPKDBG_GDB=gdb-multiarch | 
 | 145 |         if [ -z "$(command -v $IPKDBG_GDB)" ] | 
 | 146 |         then | 
 | 147 |             ipkdbg_error "Please install the gdb-multiarch package:" | 
 | 148 |             ipkdbg_error | 
 | 149 |             ipkdbg_error "\tsudo dnf install gdb-multiarch" | 
 | 150 |             ipkdbg_error | 
 | 151 |             exit 1 | 
 | 152 |         fi | 
 | 153 |         ;; | 
 | 154 |     ubuntu*) | 
 | 155 |         IPKDBG_GDB=gdb-multiarch | 
 | 156 |         if [ -z "$(command -v $IPKDBG_GDB)" ] | 
 | 157 |         then | 
 | 158 |             ipkdbg_error "Please Install the gdb-multiarch package" | 
 | 159 |             ipkdbg_error | 
 | 160 |             ipkdbg_error "\tsudo apt install gdb-multiarch" | 
 | 161 |             ipkdbg_error | 
 | 162 |             exit 1 | 
 | 163 |         fi | 
 | 164 |         ;; | 
 | 165 |     *) | 
 | 166 |         ipkdbg_error "Unrecognised distribution $release_id. Please set IPKDBG_GDB or " \ | 
 | 167 |             "install an appropriate gdb binary to invoke" | 
 | 168 |         exit 1 | 
 | 169 |         ;; | 
 | 170 |     esac | 
 | 171 |     ipkdbg_info "Using gdb command ${IPKDBG_GDB} ($(command -v $IPKDBG_GDB))" | 
 | 172 | fi | 
 | 173 |  | 
 | 174 | ipkdbg_archive_extract() { | 
 | 175 |     local offset=$1 | 
 | 176 |     local work=$2 | 
 | 177 |     tail -n+$offset $0 | base64 --decode - | tar -xz -C $work | 
 | 178 | } | 
 | 179 |  | 
 | 180 | ipkdbg_opkg_path() { | 
 | 181 |     local root=$1 | 
 | 182 |     local arch=$(uname -m) | 
 | 183 |     local release_id=$(. /etc/os-release; echo $ID) | 
 | 184 |     local release_version_id=$(. /etc/os-release; echo $VERSION_ID) | 
 | 185 |     local p=${root}/bin/${arch}/${release_id}/${release_version_id}/opkg | 
 | 186 |     if [ ! -x "$p" ] | 
 | 187 |     then | 
 | 188 |         ipkdbg_error "Unsupported environment:" | 
 | 189 |         ipkdbg_error | 
 | 190 |         ipkdbg_error "Architecture:\t$arch" | 
 | 191 |         ipkdbg_error "Distribution ID:\t$release_id" | 
 | 192 |         ipkdbg_error "Distribution Version:\t$release_version_id" | 
 | 193 |         exit 1 | 
 | 194 |     fi | 
 | 195 |     echo $p | 
 | 196 | } | 
 | 197 |  | 
 | 198 | if [ ! -f $0 ] | 
 | 199 | then | 
 | 200 |     ipkdbg_error "Please execute the script with a relative or absolute path" | 
 | 201 |     exit 1 | 
 | 202 | fi | 
 | 203 |  | 
 | 204 | IPKDBG_DATA=$(awk '/^__ARCHIVE_BEGIN__$/ { print NR + 1; exit 0 }' $0) | 
 | 205 | IPKDBG_WORK=$(mktemp -t --directory ipkdbg.XXX) | 
 | 206 | IPKDBG_BINS=${IPKDBG_WORK}/tools | 
 | 207 | IPKDBG_ROOT=${IPKDBG_WORK}/root | 
 | 208 | IPKDBG_CONF=${IPKDBG_WORK}/opkg.conf | 
 | 209 | IPKDBG_DB=${IPKDBG_WORK}/database | 
 | 210 |  | 
 | 211 | cleanup() { | 
 | 212 |     rm -rf $IPKDBG_WORK | 
 | 213 | } | 
 | 214 |  | 
 | 215 | trap cleanup EXIT INT QUIT KILL | 
 | 216 |  | 
 | 217 | mkdir $IPKDBG_BINS $IPKDBG_DB | 
 | 218 | ipkdbg_archive_extract $IPKDBG_DATA $IPKDBG_BINS | 
 | 219 |  | 
 | 220 | IPKDBG_OPKG_BIN=$(ipkdbg_opkg_path $IPKDBG_BINS) | 
 | 221 |  | 
 | 222 | ipkdbg_build_gen_path() { | 
 | 223 |     local build=$1 | 
 | 224 |     local component="$2" | 
 | 225 |     echo /${IPKDBG_CONF_MNT}/${IPKDBG_CONF_LOC}/${IPKDBG_CONF_ROOT}/${build}/"$component" | 
 | 226 | } | 
 | 227 |  | 
 | 228 | ipkdbg_build_gen_url() { | 
 | 229 |     local build=$1 | 
 | 230 |     local component="$2" | 
 | 231 |     echo https://${IPKDBG_CONF_HOST}/${IPKDBG_CONF_MNT}/${IPKDBG_CONF_LOC}/${IPKDBG_CONF_ROOT}/${build}/${component} | 
 | 232 | } | 
 | 233 |  | 
 | 234 | ipkdbg_build_gen_cache() { | 
 | 235 |     local build=$1 | 
 | 236 |     local component="$2" | 
 | 237 |     echo "${HOME}/.cache/ipkdbg/builds/${build}/${component}" | 
 | 238 | } | 
 | 239 |  | 
 | 240 | ipkdbg_opkg_conf_gen_path() { | 
 | 241 |     local build=$1 | 
 | 242 |     ipkdbg_build_gen_path $build bmc_ipk/opkg.conf | 
 | 243 | } | 
 | 244 |  | 
 | 245 | ipkdbg_opkg_fetch_path() { | 
 | 246 |     local path=$1 | 
 | 247 |     local output=$2 | 
 | 248 |     cp "$path" "$output" > /dev/null 2>&1 | 
 | 249 | } | 
 | 250 |  | 
 | 251 | ipkdbg_opkg_conf_gen_url() { | 
 | 252 |     local build=$1 | 
 | 253 |     ipkdbg_build_gen_url $build bmc_ipk/opkg.conf | 
 | 254 | } | 
 | 255 |  | 
 | 256 | ipkdbg_opkg_fetch_url() { | 
 | 257 |     local url=$1 | 
 | 258 |     local output=$2 | 
 | 259 |     # We don't want URL to wrap | 
 | 260 |     ipkdbg_info "Authenticating as user $IPKDBG_CONF_USER" | 
 | 261 |     if ! wget --http-user=$IPKDBG_CONF_USER \ | 
 | 262 |         --ask-password \ | 
 | 263 |         --output-document $output \ | 
 | 264 |         $IPKDBG_WGET_OPTS \ | 
 | 265 |         $url | 
 | 266 |     then | 
 | 267 |         ipkdbg_error "Failed to fetch resource" | 
 | 268 |         exit 1 | 
 | 269 |     fi | 
 | 270 | } | 
 | 271 |  | 
 | 272 | ipkdbg_opkg_conf_gen_cache() { | 
 | 273 |     local build=$1 | 
 | 274 |     ipkdbg_build_gen_cache $build opkg.conf | 
 | 275 | } | 
 | 276 |  | 
 | 277 | ipkdbg_opkg_conf_fetch_cache() { | 
 | 278 |     local build=$1 | 
 | 279 |     local output=$2 | 
 | 280 |     local path="$(ipkdbg_opkg_conf_gen_cache $build)" | 
 | 281 |     cp "$path" "$output" > /dev/null 2>&1 | 
 | 282 | } | 
 | 283 |  | 
 | 284 | ipkdbg_opkg_conf_install() { | 
 | 285 |     local build=$1 | 
 | 286 |     local output=$2 | 
 | 287 |     mkdir -p $(dirname $output) | 
 | 288 |     if ! ipkdbg_opkg_conf_fetch_cache $build $output | 
 | 289 |     then | 
 | 290 |         local cache="$(ipkdbg_opkg_conf_gen_cache $build)" | 
 | 291 |         mkdir -p $(dirname $cache) | 
 | 292 |         url= | 
 | 293 |         ipkdbg_opkg_fetch_path "$(ipkdbg_opkg_conf_gen_path $build)" $cache || | 
 | 294 |             (echo "Configuring opkg via $(ipkdbg_opkg_conf_gen_url $build)" && | 
 | 295 |                 ipkdbg_opkg_fetch_url "$(ipkdbg_opkg_conf_gen_url $build)" $cache) | 
 | 296 |         ipkdbg_opkg_conf_fetch_cache $build $output | 
 | 297 |     fi | 
 | 298 | } | 
 | 299 |  | 
 | 300 | ipkdbg_opkg_db_gen_path() { | 
 | 301 |     local build=$1 | 
 | 302 |     ipkdbg_build_gen_path $build bmc_ipk/opkg-database.tar.xz | 
 | 303 | } | 
 | 304 |  | 
 | 305 | ipkdbg_opkg_db_gen_url() { | 
 | 306 |     local build=$1 | 
 | 307 |     ipkdbg_build_gen_url ${build} bmc_ipk/opkg-database.tar.xz | 
 | 308 | } | 
 | 309 |  | 
 | 310 | ipkdbg_opkg_db_gen_cache() { | 
 | 311 |     local build=$1 | 
 | 312 |     ipkdbg_build_gen_cache $build opkg-database.tar.xz | 
 | 313 | } | 
 | 314 |  | 
 | 315 | ipkdbg_opkg_db_install() { | 
 | 316 |     local build=$1 | 
 | 317 |     local root=$2 | 
 | 318 |     local state=${root}/var/lib/opkg | 
 | 319 |     local cache="$(ipkdbg_opkg_db_gen_cache $build)" | 
 | 320 |     mkdir -p $state | 
 | 321 |     if ! [ -f $cache ] | 
 | 322 |     then | 
 | 323 |         mkdir -p $(dirname $cache) | 
 | 324 |         ipkdbg_opkg_fetch_path "$(ipkdbg_opkg_db_gen_path $build)" $cache || | 
 | 325 |             ipkdbg_opkg_fetch_url "$(ipkdbg_opkg_db_gen_url $build)" $cache || | 
 | 326 |             rm -f $cache | 
 | 327 |     fi | 
 | 328 |     tar -xf $cache -C $state 2> /dev/null | 
 | 329 |     mkdir -p ${root}/usr/local | 
 | 330 |     ln -s ${root}/var ${root}/usr/local/var | 
 | 331 | } | 
 | 332 |  | 
 | 333 | ipkdbg_opkg() { | 
 | 334 |     $IPKDBG_OPKG_BIN \ | 
 | 335 |         $([ -z "$IPKDBG_OPKG_CACHE" ] || | 
 | 336 |             echo --cache-dir $IPKDBG_OPKG_CACHE --host-cache-dir) \ | 
 | 337 |         -V1 -f $IPKDBG_CONF -o $IPKDBG_ROOT $@ | 
 | 338 | } | 
 | 339 |  | 
 | 340 | ipkdbg_gdb_extract_bin() { | 
 | 341 |     local core=$1 | 
 | 342 |     $IPKDBG_GDB --core $core -ex quit 2> /dev/null | | 
 | 343 |         awk -F "[\`']" '/Core was generated by/ { print $2 }' | | 
 | 344 |         awk -F " " '{ print $1 }' # Chop off the arguments, we only want the binary path | 
 | 345 | } | 
 | 346 |  | 
 | 347 | ipkdbg_opkg_find() { | 
 | 348 |     ipkdbg_opkg find $@ | awk '{ print $1 }' | 
 | 349 | } | 
 | 350 |  | 
 | 351 | ipkdbg_opkg_find_extra() { | 
 | 352 |     local pkg=$1 | 
 | 353 |  | 
 | 354 |     # Try appending -dbg and -src to the binary package name | 
 | 355 |     extra_pkgs="$(ipkdbg_opkg_find ${pkg}-dbg) $(ipkdbg_opkg_find ${pkg}-src)" | 
 | 356 |  | 
 | 357 |     # If that fails, we probably have a split binary package | 
 | 358 |     if [ -z "$extra_pkgs" ] | 
 | 359 |     then | 
 | 360 |         # Strip the last component off as it's probably the split binary package name and | 
 | 361 |         # try again | 
 | 362 |         extra_pkgs="$(ipkdbg_opkg_find ${pkg%-*}-dbg) $(ipkdbg_opkg_find ${pkg%-*}-src)" | 
 | 363 |     fi | 
 | 364 |     echo $extra_pkgs | 
 | 365 | } | 
 | 366 |  | 
 | 367 | ipkdbg_opkg_conf_install $IPKDBG_BUILD $IPKDBG_CONF | 
 | 368 |  | 
 | 369 | # Extract the binary path from the core | 
 | 370 | if [ '-' = "$IPKDBG_FILE" -a '-' != "$IPKDBG_CORE" ] | 
 | 371 | then | 
 | 372 |     IPKDBG_FILE=$(ipkdbg_gdb_extract_bin $IPKDBG_CORE) | 
 | 373 | fi | 
 | 374 |  | 
 | 375 | # Update the package database before potentially looking up the debug packages | 
 | 376 | ipkdbg_opkg update | 
 | 377 |  | 
 | 378 | # Extract the package name for the binary | 
 | 379 | if [ '-' != "$IPKDBG_CORE" ] | 
 | 380 | then | 
 | 381 |     if ipkdbg_opkg_db_install $IPKDBG_BUILD $IPKDBG_DB | 
 | 382 |     then | 
 | 383 |         # Look up the package for the binary | 
 | 384 |         IPKDBG_CORE_PKG="$(IPKDBG_ROOT=$IPKDBG_DB ipkdbg_opkg search ${IPKDBG_DB}${IPKDBG_FILE} | awk '{ print $1 }')" | 
 | 385 |         if [ -n "$IPKDBG_CORE_PKG" ] | 
 | 386 |         then | 
 | 387 |             # Look up the extra (debug, source) packages for the binary package | 
 | 388 |             IPKDBG_PKGS="$IPKDBG_PKGS $IPKDBG_CORE_PKG" | 
 | 389 |             IPKDBG_PKGS="$IPKDBG_PKGS $(ipkdbg_opkg_find_extra $IPKDBG_CORE_PKG)" | 
 | 390 |         fi | 
 | 391 |     fi | 
 | 392 |  | 
 | 393 |     if [ -z "$IPKDBG_PKGS" ] | 
 | 394 |     then | 
 | 395 |         ipkdbg_error "Unable to determine package-set to install, please specify" \ | 
 | 396 |                  "appropriate packages on the command line" | 
 | 397 |         exit 1 | 
 | 398 |     fi | 
 | 399 | fi | 
 | 400 |  | 
 | 401 | # Force installation of gcc-runtime-dbg to give us debug symbols for libstdc++ | 
 | 402 | IPKDBG_PKGS="gcc-runtime-dbg $IPKDBG_PKGS" | 
 | 403 |  | 
 | 404 | if [ -n "$IPKDBG_OPKG_CACHE" ] | 
 | 405 | then | 
 | 406 |     mkdir -p "$IPKDBG_OPKG_CACHE" | 
 | 407 |     ipkdbg_opkg install --download-only $IPKDBG_PKGS | 
 | 408 | fi | 
 | 409 |  | 
 | 410 | ipkdbg_opkg install $IPKDBG_PKGS | grep -vF 'Warning when extracting archive entry' | 
 | 411 |  | 
 | 412 | cat <<EOF > ${IPKDBG_BINS}/opkg | 
 | 413 | #!/bin/sh | 
 | 414 | exec $IPKDBG_OPKG_BIN -f $IPKDBG_CONF -o $IPKDBG_ROOT \$@ | 
 | 415 | EOF | 
 | 416 | chmod +x ${IPKDBG_BINS}/opkg | 
 | 417 |  | 
 | 418 | PATH=${IPKDBG_BINS}:${PATH} $IPKDBG_GDB -q \ | 
 | 419 |     -iex "set solib-absolute-prefix $IPKDBG_ROOT" \ | 
 | 420 |     -iex "add-auto-load-safe-path $IPKDBG_ROOT" \ | 
 | 421 |     -iex "set directories $IPKDBG_ROOT" \ | 
 | 422 |     -iex "cd $IPKDBG_ROOT" \ | 
 | 423 |     $([ '-' = "$IPKDBG_CORE" ] || echo -ex bt) \ | 
 | 424 |     $([ 0 -eq $IPKDBG_OPT_QUIT ] || echo -ex quit) \ | 
 | 425 |     ${IPKDBG_ROOT}${IPKDBG_FILE} \ | 
 | 426 |     $([ '-' = "$IPKDBG_CORE" ] || echo $IPKDBG_CORE) | 
 | 427 |  | 
 | 428 | exit 0 | 
 | 429 |  | 
 | 430 | __ARCHIVE_BEGIN__ |