⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dwarfutils.pas

📁 一个不出名的GBA模拟器
💻 PAS
📖 第 1 页 / 共 4 页
字号:
    logWriteLn('.');
  end;}
end;

//////////////////////////////////////////////////////////////////////

function FindAttribute(node: PDwarfNode; name: uint32): PDwarfAttribute;
var
  attrib: PDwarfAttribute;
begin
  Result := nil;
  attrib := node^.attribs;
  while attrib <> nil do begin
    if attrib^.name = name then begin
      Result := attrib;
      Exit;
    end;
    attrib := attrib^.next;
  end;
end;

//////////////////////////////////////////////////////////////////////

procedure ReadSubroutine(cunit: TCompilationUnit; node: PDwarfNode);
var
  attrib: PDwarfAttribute;
  sub: TDwarfSubroutine;
begin
  sub := TDwarfSubroutine.Create;
  sub.node := node;

  // Read the name
  attrib := FindAttribute(node, DW_AT_name);
  if attrib <> nil then sub.name := attrib^.st else sub.name := '';

  // Read the PC ranges
  attrib := FindAttribute(node, DW_AT_low_pc);
  if attrib = nil then sub.lowPC := $FFFFFFFF else sub.lowPC := attrib^.address;

  attrib := FindAttribute(node, DW_AT_high_pc);
  if attrib = nil then sub.highPC := 0 else sub.highPC := attrib^.address;

  // Read the possible declaration position in the source code
  attrib := FindAttribute(node, DW_AT_decl_file);
  if attrib = nil then sub.fileIndex := 0 else sub.fileIndex := attrib^.data;

  attrib := FindAttribute(node, DW_AT_decl_line);
  if attrib = nil then sub.line := 0 else sub.line := attrib^.data;

  attrib := FindAttribute(node, DW_AT_decl_column);
  if attrib = nil then sub.column := 0 else sub.column := attrib^.data;

  cunit.functions.AddObject(sub.name, sub);

  logWriteLn(Format('Function "%s" compiles to %8.8x..%8.8x, defined in file %d at (%d: %d)', [sub.name, sub.lowPC, sub.highPC, sub.fileIndex, sub.line, sub.column]));
end;

//////////////////////////////////////////////////////////////////////

procedure ReadVariable(cunit: TCompilationUnit; node: PDwarfNode);
var
  attrib: PDwarfAttribute;
  v: TDwarfVariable;
begin
  v := TDwarfVariable.Create;
  v.node := node;

  // Read the name
  attrib := FindAttribute(node, DW_AT_name);
  if attrib <> nil then v.name := attrib^.st else v.name := '';


  // if its defining, it'll have a DW_AT_location, otherwise, it
  // will have a DW_AT_declaration
  // however, if its missing the DW_AT_declaration, and the
  // DW_AT_location is also missing or if it describes a null entry
  // then the variable was in the source code, but not in the compiled
  // program, i.e. unused variables compiled out

  // C++ union/struct/class defining declarations will have a
  // DW_AT_specification attribute and will not duplicate any data
  // contained in the DW_AT_specs pointed to

  // Read the possible declaration position in the source code
  attrib := FindAttribute(node, DW_AT_decl_file);
  if attrib = nil then v.fileIndex := 0 else v.fileIndex := attrib^.data;

  attrib := FindAttribute(node, DW_AT_decl_line);
  if attrib = nil then v.line := 0 else v.line := attrib^.data;

  attrib := FindAttribute(node, DW_AT_decl_column);
  if attrib = nil then v.column := 0 else v.column := attrib^.data;

  attrib := FindAttribute(node, DW_AT_location);
  if attrib <> nil then v.loc := attrib;

  attrib := FindAttribute(node, DW_AT_type);
  if attrib <> nil then v.typ := attrib;

  attrib := FindAttribute(v.node, DW_AT_start_scope);
  if attrib <> nil then v.startScope := attrib.address else v.startScope := 0;

  cunit.variables.AddObject(v.name, v);
  logWriteLn(Format('Variable "%s", defined in file %d at (%d: %d)', [v.name, v.fileIndex, v.line, v.column]));
end;

//////////////////////////////////////////////////////////////////////

function dwarfLookupVal(cmd: string): string;
var
  cunit: TCompilationUnit;
  i: integer;
  v: TDwarfVariable;
  inReg, notOptimized: boolean;
  addr: uint32;
begin
  logwriteln('fixme in dwarfLookupVal');

  Result := cmd + ' is not accessable at this location or the expression is too complex';
  if Assigned(dwarf) then begin
    // Find the current compilation unit
    cunit := Dwarf.FindContainingUnit(vmCurrentPC);
    if cunit <> nil then begin
      i := cunit.variables.IndexOf(cmd);
      if i > -1 then begin
        v := TDwarfVariable(cunit.variables.Objects[i]);
//        Result := Format('defined in %d at (%d: %d)', [v.fileIndex, v.line, v.column]);

        if Assigned(v.loc) and (v.startScope <= vmCurrentPC) then begin
          addr := LocationSM(v.loc.block, inReg, notOptimized);
          if inReg then begin
            addr := addr and 15;
            Result := Format('%s is %8.8x, in r%d', [cmd, vmGetRegister(addr), addr]);
          end else begin
            Result := Format('%s is %8.8x, at u32[$%8.8x]', [cmd, vmReadWord(addr), addr]);
          end;
        end;

      end;
    end;

  end;
  logWriteLn(Result);
end;

//////////////////////////////////////////////////////////////////////

procedure ReadType(cunit: TCompilationUnit; node: PDwarfNode);
var
  attrib: PDwarfAttribute;
  v: TDwarfType;
begin
  v := TDwarfType.Create;
  v.node := node;

  // Read the name
  attrib := FindAttribute(node, DW_AT_name);
  if attrib <> nil then v.name := attrib^.st else v.name := '';

  // Read the possible declaration position in the source code
  attrib := FindAttribute(node, DW_AT_decl_file);
  if attrib = nil then v.fileIndex := 0 else v.fileIndex := attrib^.data;

  attrib := FindAttribute(node, DW_AT_decl_line);
  if attrib = nil then v.line := 0 else v.line := attrib^.data;

  attrib := FindAttribute(node, DW_AT_decl_column);
  if attrib = nil then v.column := 0 else v.column := attrib^.data;

  cunit.types.AddObject(v.name, v);
  logWriteLn(Format('Type "%s", defined in file %d at (%d: %d)', [v.name, v.fileIndex, v.line, v.column]));
end;

//////////////////////////////////////////////////////////////////////

procedure ProcessNode(cunit: TCompilationUnit; node: PDwarfNode);
var
  attrib: PDwarfAttribute;
  hitless: TLineHit;
begin
  while node <> nil do begin
    case node^.tag of
      DW_TAG_array_type: ;
      DW_TAG_class_type: ;
      DW_TAG_entry_point: ;
      DW_TAG_enumeration_type: ;
      DW_TAG_formal_parameter: ;
      DW_TAG_imported_declaration: ;
      DW_TAG_label: ;
      DW_TAG_lexical_block: ;
      DW_TAG_member: ;
      DW_TAG_pointer_type: ;
      DW_TAG_reference_type: ;
      DW_TAG_compile_unit: begin
        attrib := FindAttribute(node, DW_AT_language);
        if attrib = nil then cunit.lang := DW_LANG_C89 else cunit.lang := attrib^.data;
//        if (cunit.lang <> DW_LANG_C89) and (cunit.lang <> DW_LANG_C) and (cunit.lang <> DW_LANG_C_plus_plus) then
//          raise EBadDwarf.CreateFmt('DWARF compilation unit contains an unsupported language %s', [DwarfLangToString(cunit.lang)]);

        // Read the PC ranges
        attrib := FindAttribute(node, DW_AT_low_pc);
        if attrib = nil then
          cunit.lowPC := $FFFFFFFF
        else
          cunit.lowPC := attrib^.address;

        attrib := FindAttribute(node, DW_AT_high_pc);
        if attrib = nil then
          cunit.highPC := 0
        else
          cunit.highPC := attrib^.address;

        // Read the statement offset
        attrib := FindAttribute(node, DW_AT_stmt_list);
        if attrib <> nil then begin
          cunit.statementOffset := attrib^.data;
          DoLineProgram(true, cunit, 0, hitless);
        end else
          cunit.statementOffset := $FFFFFFFF;

        // Read the macro offset
        attrib := FindAttribute(node, DW_AT_macro_info);
        if attrib <> nil then
          cunit.macroOffset := attrib^.address;

        logWriteLn(Format('*** Compilation Unit with a range of %.8x to %.8x', [cunit.lowPC, cunit.highPC]));
      end;
      DW_TAG_string_type: ;
      DW_TAG_structure_type: ;
      DW_TAG_subroutine_type: ;
      DW_TAG_typedef: ;
      DW_TAG_union_type: ;
      DW_TAG_unspecified_parameters: ;
      DW_TAG_variant: ;
      DW_TAG_common_block: ;
      DW_TAG_common_inclusion: ;
      DW_TAG_inheritance: ;
      DW_TAG_inlined_subroutine: ;
      DW_TAG_module: ;
      DW_TAG_ptr_to_member_type: ;
//      DW_TAG_set_type: ;
      DW_TAG_subrange_type: ;
//      DW_TAG_with_stmt: ;
      DW_TAG_access_declaration: ;
      DW_TAG_base_type: ReadType(cunit, node);
      DW_TAG_catch_block: ;
      DW_TAG_const_type: ;
      DW_TAG_constant: ;
      DW_TAG_enumerator: ;
      DW_TAG_file_type: ;
      DW_TAG_friend: ;
      DW_TAG_namelist: ;
      DW_TAG_namelist_item: ;
      DW_TAG_packed_type: ;
      DW_TAG_subprogram: ReadSubroutine(cunit, node);
      DW_TAG_template_type_param: ;
      DW_TAG_template_value_param: ;
      DW_TAG_thrown_type: ;
      DW_TAG_try_block: ;
      DW_TAG_variant_part: ;
      DW_TAG_variable: ReadVariable(cunit, node);
      DW_TAG_volatile_type: ;
    end;

    if node.hasChildren then
      ProcessNode(cunit, node^.kids);
    node := node^.next;
  end;
end;

//////////////////////////////////////////////////////////////////////

function ExamineVariable(name: string): integer;
var
  compUnit: TCompilationUnit;
//  attrib: PDwarfAttribute;
  i: integer;
  v: TDwarfVariable;
  inReg, notOptimized: boolean;
  addr: uint32;
  currentPC: uint32;
begin
  Result := 0;
  if not assigned(dwarf) then Exit;

  currentPC := vmCurrentPC;

  compUnit := dwarf.FindContainingUnit(currentPC);
  if compUnit <> nil then begin
    for i := 0 to compUnit.variables.Count - 1 do begin
      v := TDwarfVariable(compUnit.variables.Objects[i]);
      if v.name = name then begin
        if Assigned(v.loc) and (v.startScope <= currentPC) then begin
          addr := LocationSM(v.loc.block, inReg, notOptimized);
          if inReg then
            Result := vmGetRegister(addr and 15)
          else
            Result := vmReadWord(addr);
        end;
        Exit;
      end;
    end;
  end;
end;

//////////////////////////////////////////////////////////////////////

procedure WalkVariables(var res: TStringList);
var
  compUnit: TCompilationUnit;
//  attrib: PDwarfAttribute;
  i, k: integer;
  v: TDwarfVariable;
  inReg, notOptimized: boolean;
  addr: uint32;
begin
  if not assigned(dwarf) then Exit;

  res.clear;
  res.Add('Valid variables at PC = ' + IntToHex(vmCurrentPC, 8));

  for k := 0 to dwarf.compUnits.Count - 1 do begin
    compUnit := TCompilationUnit(dwarf.compUnits[k]);

    if (vmCurrentPC >= compUnit.lowPC) and (vmCurrentPC <= compUnit.highPC) then begin
      for i := 0 to compUnit.variables.Count - 1 do begin
        v := TDwarfVariable(compUnit.variables.Objects[i]);
        // attrib := FindAttribute(v.node, DW_AT_location);

        if Assigned(v.loc) and (v.startScope <= vmCurrentPC) then begin
          addr := LocationSM(v.loc.block, inReg, notOptimized);
          if inReg then begin
            addr := addr and 15;
            res.Add(Format('%s is $%8.8x, in r%d', [v.name, vmGetRegister(addr), addr]));
          end else begin
            res.Add(Format('%s is $%8.8x, at u32[$%8.8x]', [v.name, vmReadWord(addr), addr]));
          end;
        end;
      end;
    end;

  end;

  for i := 0 to res.count - 1 do logWriteLn(res.strings[i]);
end;

//////////////////////////////////////////////////////////////////////

function conWalkVariables(params: string): string;
var
  junk: TStringList;
begin
  junk := TStringList.Create;
  WalkVariables(junk);
  junk.Free;
end;

//////////////////////////////////////////////////////////////////////
// TDwarfFile ////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

constructor TDwarfFile.Create;
begin
  varList := TStringList.Create;
  compUnits := TObjectList.Create;
end;

//////////////////////////////////////////////////////////////////////

destructor TDwarfFile.Destroy;
begin
  logWriteLn('Clearing DWARF file');

  varList.Free;
  compUnits.Free;

  closeSourceFiles;

  inherited;
end;

//////////////////////////////////////////////////////////////////////

procedure TDwarfFile.DestroyNode(node: PDwarfNode);
var
  lastNode: PDwarfNode;
  lastAttrib, attrib: PDwarfAttribute;
begin
  // Destroy a node and all of its siblings
  while node <> nil do begin
    // Free the attributes
    attrib := node^.attribs;
    while attrib <> nil do begin
      lastAttrib := attrib;
      attrib := attrib^.next;
      FreeMem(lastAttrib, SizeOf(TDwarfAttribute));
    end;

    // Recursively wax all the children
    if node.hasChildren then
      DestroyNode(node^.kids);

    // Free the node
    lastNode := node;
    node := node^.next;
    FreeMem(lastNode, SizeOf(TDwarfNode));
  end;
end;

//////////////////////////////////////////////////////////////////////

function TDwarfFile.FindContainingUnit(address: uint32): TCompilationUnit;
var
  i: integer;
  cunit: TCompilationUnit;
begin
  Result := nil;
  for i := 0 to dwarf.compUnits.Count - 1 do begin
    cunit := TCompilationUnit(dwarf.compUnits.Items[i]);
    if (address >= cunit.lowPC) and (address < cunit.highPC) then begin
      Result := cunit;
      Exit;
    end;
  end;
end;

//////////////////////////////////////////////////////////////////////
// TCompilationUnit //////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

constructor TCompilationUnit.Create;
begin
  // Read the compilation unit header
  unitLength := debugInfo.ReadUint32;
  producerVersion := debugInfo.ReadUint16;
  abbrevOffset := debugInfo.ReadUint32;
  addressSize := debugInfo.ReadUint8;

  // Chunk out some memory
  dirs := TStringList.Create;
  files := TStringList.Create;
  functions := TStringList.Create;
  types := TStringList.Create;
  classes := TStringList.Create;
  variables := TStringList.Create;

  // Read all the nodes in the compilation unit
  rootNode := ReadNode(self);

  // Read all the nodes hither and dither
  ProcessNode(self, rootNode);
end;

//////////////////////////////////////////////////////////////////////

destructor TCompilationUnit.Destroy;
begin
  // Free all of the nodes that belong to this compilation unit
  dwarf.DestroyNode(rootNode);

  // Free the string lists
  variables.Free;
  classes.Free;
  types.Free;
  functions.Free;
  files.Free;
  dirs.Free;
end;

//////////////////////////////////////////////////////////////////////

begin
  logAddCommand('expressionEvaluator', dwarfLookupVal, 'Evaluates an expression');
  logAddCommand('walkVariables', conWalkVariables, 'Display active variables if valid DWARF data is present');
end.

//////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -